/* * $Id: calendar.c,v 1.4 2010-01-17 00:38:47 judd Exp $ * * calendar.c - Support for PalmOne Calendar application (CalendarDB-PDat), * this is a copy of datebook.c with the calendar fields added. * * (c) 2008, Jon Schewe * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Library General Public License as published by * the Free Software Foundation; either version 2 of the License, or (at * your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library * General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include #ifdef TIME_WITH_SYS_TIME # include # include #else # ifdef HAVE_SYS_TIME_H # include # else # include # endif #endif #include "pi-macros.h" #include "pi-calendar.h" #define alarmFlag 64 #define repeatFlag 32 #define noteFlag 16 #define exceptFlag 8 #define descFlag 4 #define locFlag 2 /*********************************************************************** * * Function: new_CalendarEvent * * Summary: Create empty calendar event * * Parameters: CalendarEvent_t* * * Returns: void * ***********************************************************************/ void new_CalendarEvent(CalendarEvent_t *a) { int i = 0; a->event = 0; a->begin.tm_hour = 0; a->begin.tm_min = 0; a->begin.tm_sec = 0; a->begin.tm_year = 2000; a->begin.tm_mon = 0; a->begin.tm_mday = 0; a->begin.tm_isdst = -1; a->end.tm_hour = 0; a->end.tm_min = 0; a->end.tm_sec = 0; a->end.tm_year = 2000; a->end.tm_mon = 0; a->end.tm_mday = 0; a->end.tm_isdst = -1; a->alarm = 0; a->advance = 0; a->advanceUnits = 0; a->repeatType = 0; a->repeatForever = 0; a->repeatEnd.tm_hour = 0; a->repeatEnd.tm_min = 0; a->repeatEnd.tm_sec = 0; a->repeatEnd.tm_year = 2000; a->repeatEnd.tm_mon = 0; a->repeatEnd.tm_mday = 0; a->repeatEnd.tm_isdst = -1; a->repeatFrequency = 0; a->repeatDay = 0; for (i = 0; i < 7; i++) { a->repeatDays[i] = 0; } a->repeatWeekstart = 0; a->exceptions = 0; a->exception = NULL; a->description = NULL; a->note = NULL; a->location = NULL; a->tz = NULL; /* initialize the blobs to NULL */ for (i=0; iblob[i]=NULL; } } /*********************************************************************** * * Function: copy_CalendarEvent * * Summary: Copy the data from one calendar event to another. The destination * calendar event must already be cleared, either by creating new or by * calling free_CalendarEvent on it first. * * Parameters: CalendarEvent_t*, CalendarEvent_t* * * Returns: int -1 on failure (errno will be set), 0 on success * ***********************************************************************/ int copy_CalendarEvent(const CalendarEvent_t *source, CalendarEvent_t *dest) { int i = 0; dest->event = source->event; memcpy(&(dest->begin), &(source->begin), sizeof(struct tm)); memcpy(&(dest->end), &(source->end), sizeof(struct tm)); dest->alarm = source->alarm; dest->advance = source->advance; dest->advanceUnits = source->advanceUnits; dest->repeatType = source->repeatType; dest->repeatForever = source->repeatForever; memcpy(&(dest->repeatEnd), &(source->repeatEnd), sizeof(struct tm)); dest->repeatFrequency = source->repeatFrequency; dest->repeatDay = source->repeatDay; for (i = 0; i < 7; i++) { dest->repeatDays[i] = source->repeatDays[i]; } dest->repeatWeekstart = source->repeatWeekstart; dest->exceptions = source->exceptions; if(source->exceptions > 0) { dest->exception = (struct tm*)malloc(source->exceptions * sizeof(struct tm)); if(NULL == dest->exception) { errno = ENOMEM; return -1; } for(i=0; iexceptions; i++) { memcpy(&(dest->exception[i]), &(source->exception[i]), sizeof(struct tm)); } } if(NULL != source->description) { dest->description = strdup(source->description); } else { dest->description = NULL; } if(NULL != source->note) { dest->note = strdup(source->note); } else { dest->note = NULL; } if(NULL != source->location) { dest->location = strdup(source->location); } else { dest->location = NULL; } /* copy the blobs */ for (i=0; iblob[i] != NULL) { dest->blob[i] = dup_Blob(source->blob[i]); if(NULL == dest->blob[i]) { return -1; } } else { dest->blob[i] = NULL; } } if(source->tz != NULL) { dest->tz = dup_Timezone(source->tz); if(NULL == dest->tz) { return -1; } } else { dest->tz = NULL; } return 0; } /*********************************************************************** * * Function: free_CalendarEvent * * Summary: Frees members of the calendar event structure * * Parameters: CalendarEvent_t* * * Returns: void * ***********************************************************************/ void free_CalendarEvent(CalendarEvent_t *a) { int i; if (a->exception != NULL) { free(a->exception); a->exception = NULL; } if (a->description != NULL) { free(a->description); a->description = NULL; } if (a->note != NULL) { free(a->note); a->note = NULL; } if(a->location != NULL) { free(a->location); a->location = NULL; } if(NULL != a->tz) { free_Timezone(a->tz); free(a->tz); } for(i=0; iblob[i]) { free_Blob(a->blob[i]); free(a->blob[i]); a->blob[i] = NULL; } } } /*********************************************************************** * * Function: unpack_CalendarEvent * * Summary: Fill in the calendar event structure based on the raw * record data * * Parameters: CalendarEvent_t*, pi_buffer_t * of buffer, calendarType * * Returns: -1 on fail, 0 on success * ***********************************************************************/ int unpack_CalendarEvent(CalendarEvent_t *a, const pi_buffer_t *buf, calendarType type) { int iflags, j, destlen, i, result; unsigned char *p2; unsigned long d; destlen = 8; if (type != calendar_v1) return -1; if (buf == NULL || buf->data == NULL || buf->used < destlen) { return -1; } a->begin.tm_hour = get_byte(buf->data); a->begin.tm_min = get_byte(buf->data + 1); a->begin.tm_sec = 0; d = (unsigned short int) get_short(buf->data + 4); a->begin.tm_year = (d >> 9) + 4; a->begin.tm_mon = ((d >> 5) & 15) - 1; a->begin.tm_mday = d & 31; a->begin.tm_isdst = -1; a->end = a->begin; a->end.tm_hour = get_byte(buf->data + 2); a->end.tm_min = get_byte(buf->data + 3); if (get_short(buf->data) == 0xffff) { a->event = 1; a->begin.tm_hour = 0; a->begin.tm_min = 0; a->end.tm_hour = 0; a->end.tm_min = 0; } else { a->event = 0; } mktime(&a->begin); mktime(&a->end); iflags = get_byte(buf->data + 6); /* buf->data+7 is gapfill */ p2 = (unsigned char *) buf->data + 8; if (iflags & alarmFlag) { a->alarm = 1; a->advance = get_byte(p2); p2 += 1; a->advanceUnits = get_byte(p2); p2 += 1; } else { a->alarm = 0; a->advance = 0; a->advanceUnits = 0; } if (iflags & repeatFlag) { int i, on; a->repeatType = (enum calendarRepeatType) get_byte(p2); p2 += 2; d = (unsigned short int) get_short(p2); p2 += 2; if (d == 0xffff) a->repeatForever = 1; /* repeatEnd is invalid */ else { a->repeatEnd.tm_year = (d >> 9) + 4; a->repeatEnd.tm_mon = ((d >> 5) & 15) - 1; a->repeatEnd.tm_mday = d & 31; a->repeatEnd.tm_min = 0; a->repeatEnd.tm_hour = 0; a->repeatEnd.tm_sec = 0; a->repeatEnd.tm_isdst = -1; mktime(&a->repeatEnd); a->repeatForever = 0; } a->repeatFrequency = get_byte(p2); p2++; on = get_byte(p2); p2++; a->repeatDay = (enum calendarDayOfMonthType) 0; for (i = 0; i < 7; i++) a->repeatDays[i] = 0; if (a->repeatType == calendarRepeatMonthlyByDay) a->repeatDay = (enum calendarDayOfMonthType) on; else if (a->repeatType == calendarRepeatWeekly) for (i = 0; i < 7; i++) a->repeatDays[i] = !!(on & (1 << i)); a->repeatWeekstart = get_byte(p2); p2++; p2++; } else { int i; a->repeatType = (enum calendarRepeatType) 0; a->repeatForever = 1; /* repeatEnd is invalid */ a->repeatFrequency = 0; a->repeatDay = (enum calendarDayOfMonthType) 0; for (i = 0; i < 7; i++) a->repeatDays[i] = 0; a->repeatWeekstart = 0; } if (iflags & exceptFlag) { a->exceptions = get_short(p2); p2 += 2; a->exception = malloc(sizeof(struct tm) * a->exceptions); for (j = 0; j < a->exceptions; j++, p2 += 2) { d = (unsigned short int) get_short(p2); a->exception[j].tm_year = (d >> 9) + 4; a->exception[j].tm_mon = ((d >> 5) & 15) - 1; a->exception[j].tm_mday = d & 31; a->exception[j].tm_hour = 0; a->exception[j].tm_min = 0; a->exception[j].tm_sec = 0; a->exception[j].tm_isdst = -1; mktime(&a->exception[j]); } } else { a->exceptions = 0; a->exception = 0; } if (iflags & descFlag) { a->description = strdup((char *)p2); p2 += strlen((char *)p2) + 1; } else a->description = 0; if (iflags & noteFlag) { a->note = strdup((char *)p2); p2 += strlen((char *)p2) + 1; } else { a->note = 0; } if (iflags & locFlag) { a->location = strdup((char *)p2); p2 += strlen((char *)p2) + 1; } else { a->location = 0; } /* initialize the blobs to NULL */ for (i=0; iblob[i]=NULL; } if(p2 - buf->data < buf->used) { uint8_t blob_count; /* read the blobs */ a->tz = NULL; for(blob_count = 0; buf->used - (p2 - buf->data) > 6; ++blob_count) { if(blob_count >= MAX_BLOBS) { /* too many blobs were found */ printf("Error, found more than %d blobs: %d\n", MAX_BLOBS, blob_count); return -1; } a->blob[blob_count] = (Blob_t *)malloc(sizeof(Blob_t)); result = unpack_Blob_p(a->blob[blob_count], p2, 0); if(-1 == result) { return -1; } else { p2 += result; } //printf("DEBUG: record %s read in blob[%d] of size %d\n", a->description, blob_count, a->blob[blob_count]->length); /* if it's a timezone blob store it */ if (0 == memcmp(a->blob[blob_count]->type, BLOB_TYPE_CALENDAR_TIMEZONE_ID, 4)) { int result; if(NULL != a->tz) { printf("Warning: Found more than one timezone blob! Freeing the previous one and starting again\n"); free_Timezone(a->tz); free(a->tz); } a->tz = (Timezone_t *)malloc(sizeof(Timezone_t)); result = unpack_Timezone_p(a->tz, a->blob[blob_count]->data, 0); if(-1 == result) { printf("Error unpacking timezone blob\n"); return -1; } else if(result != a->blob[blob_count]->length) { printf("Read the wrong number of bytes for a timezone expected %d but was %d\n", a->blob[blob_count]->length, result); return -1; } } } if(p2 - buf->data < buf->used) { printf("Extra data found %ld bytes\n", (buf->used - (p2 - buf->data))); return -1; } } else { a->tz = NULL; } return 0; } /*********************************************************************** * * Function: pack_CalendarEvent * * Summary: Fill in the raw calendar event record data based on the * calendar event structure. * * Parameters: CalendarEvent_t*, pi_buffer_t*, calendarType * * Returns: -1 on error (bad arguments, mostyle) or 0 on success. * The buffer is sized to accomodate the required data. * ***********************************************************************/ int pack_CalendarEvent(const CalendarEvent_t *a, pi_buffer_t *buf, calendarType type) { int iflags, destlen = 8; char *pos; if (type != calendar_v1) return -1; if (a == NULL || buf == NULL) return -1; if (a->alarm) destlen += 2; if (a->repeatType) destlen += 8; if (a->exceptions) destlen += 2 + 2 * a->exceptions; if (a->note) destlen += strlen(a->note) + 1; if (a->description) destlen += strlen(a->description) + 1; if (a->location) destlen += strlen(a->location) + 1; pi_buffer_expect (buf, destlen); buf->used = destlen; set_byte(buf->data, a->begin.tm_hour); set_byte(buf->data + 1, a->begin.tm_min); set_byte(buf->data + 2, a->end.tm_hour); set_byte(buf->data + 3, a->end.tm_min); set_short(buf->data + 4, ((a-> begin.tm_year - 4) << 9) | ((a->begin.tm_mon + 1) << 5) | a->begin. tm_mday); if (a->event) { set_long(buf->data, 0xffffffff); } iflags = 0; pos = (char *) buf->data + 8; if (a->alarm) { iflags |= alarmFlag; set_byte(pos, a->advance); set_byte(pos + 1, a->advanceUnits); pos += 2; } if (a->repeatType) { int i, on; iflags |= repeatFlag; if (a->repeatType == calendarRepeatMonthlyByDay) on = a->repeatDay; else if (a->repeatType == calendarRepeatWeekly) { on = 0; for (i = 0; i < 7; i++) if (a->repeatDays[i]) on |= 1 << i; } else on = 0; set_byte(pos, a->repeatType); set_byte(pos + 1, 0); pos += 2; if (a->repeatForever) set_short(pos, 0xffff); else set_short(pos, ((a-> repeatEnd.tm_year - 4) << 9) | ((a->repeatEnd.tm_mon + 1) << 5) | a->repeatEnd. tm_mday); pos += 2; set_byte(pos, a->repeatFrequency); pos++; set_byte(pos, on); pos++; set_byte(pos, a->repeatWeekstart); pos++; set_byte(pos, 0); pos++; } if (a->exceptions) { int i; iflags |= exceptFlag; set_short(pos, a->exceptions); pos += 2; for (i = 0; i < a->exceptions; i++, pos += 2) set_short(pos, ((a-> exception[i].tm_year - 4) << 9) | ((a->exception[i].tm_mon + 1) << 5) | a-> exception[i].tm_mday); } if (a->description != NULL) { iflags |= descFlag; strcpy(pos, a->description); pos += strlen(pos) + 1; } if (a->note != NULL) { iflags |= noteFlag; strcpy(pos, a->note); pos += strlen(pos) + 1; } if (a->location != NULL) { iflags |= locFlag; strcpy(pos, a->location); pos += strlen(pos) + 1; } set_byte(buf->data + 6, iflags); set_byte(buf->data + 7, 0); /* gapfill */ /* Calendar stuff */ uint8_t blob_index; //write out the blobs for(blob_index = 0; blob_index < MAX_BLOBS; ++blob_index) { if(NULL != a->blob[blob_index]) { pack_Blob(a->blob[blob_index], buf); } } return 0; } /*********************************************************************** * * Function: unpack_CalendarAppInfo * * Summary: Fill in the app info structure based on the raw app * info data * * Parameters: CalendarAppInfo_t*, char* to record, record length * * Returns: 0 on error, the length of the data used from the * buffer otherwise * ***********************************************************************/ int unpack_CalendarAppInfo(CalendarAppInfo_t *ai, pi_buffer_t *buf) { int i; int len; unsigned char *record; int used; len = buf->used; record = buf->data; used = unpack_CategoryAppInfo(&ai->category, record, len); if (!used) return 0; record += used; len -= used; if (len < 2) return 0; ai->startOfWeek = get_byte(record); // alignment byte record += 2; used += 2; for(i=0; i<18; ++i) { ai->internal[i] = get_byte(record); record++; used++; } ai->type = calendar_v1; return used; } /*********************************************************************** * * Function: pack_CalendarAppInfo * * Summary: Fill in the raw app info record data based on the app * info structure * * Parameters: AppointmentAppInfo*, char* to buffer, buffer length * * Returns: The length of the buffer required if record is NULL, * or 0 on error, the length of the data used from the * buffer otherwise * ***********************************************************************/ int pack_CalendarAppInfo(const CalendarAppInfo_t *ai, pi_buffer_t *buf) { int i; int len; unsigned char *record; if (!buf) { return 298; } /* AppInfo size should be 298, 300 will do */ len = 300; pi_buffer_expect(buf, 300); buf->used = pack_CategoryAppInfo(&ai->category, buf->data, buf->allocated); if (!buf->used) return 0; record = buf->data + buf->used; len -= buf->used; if (len < 2) return 0; set_short(record, 0); set_byte(record, ai->startOfWeek); record += 2; buf->used += 2; for(i=0; i<18; ++i) { set_byte(record, ai->internal[i]); record ++; buf->used ++; } return (record - buf->data); } /* vi: set ts=8 sw=4 sts=4 noexpandtab: cin */ /* ex: set tabstop=4 expandtab: */ /* Local Variables: */ /* indent-tabs-mode: t */ /* c-basic-offset: 8 */ /* End: */