DWORD _CeGetFileSize( HANDLE hFile, LPDWORD lpFileSizeHigh) { RapiContext* context = rapi_context_current(); DWORD size = BAD_FILE_SIZE; rapi_context_begin_command(context, 0x1d); rapi_buffer_write_uint32(context->send_buffer, (uint32_t)hFile); rapi_buffer_write_optional_out(context->send_buffer, lpFileSizeHigh, sizeof(*lpFileSizeHigh)); if ( !rapi_context_call(context) ) return BAD_FILE_SIZE; if ( !rapi_buffer_read_uint32(context->recv_buffer, &context->last_error) ) return BAD_FILE_SIZE; synce_trace("last_error = %i", context->last_error); if ( !rapi_buffer_read_uint32(context->recv_buffer, &size) ) return BAD_FILE_SIZE; if ( !rapi_buffer_read_optional_uint32(context->recv_buffer, lpFileSizeHigh) ) return BAD_FILE_SIZE; return size; }
static bool recurrence_set_exceptions(RRA_RecurrencePattern* pattern, RRA_MdirLineVector* exdates) { unsigned i; bool success = false; RRA_Exceptions* exceptions = pattern->exceptions; /* TODO: support more than one exception per EXDATE line */ rra_exceptions_make_reservation(exceptions, exdates->used); for (i = 0; i < exdates->used; i++) { RRA_Exception* exception = rra_exceptions_item(exceptions, i); struct tm exdate; if (!parser_datetime_to_struct(exdates->items[i]->values[0], &exdate, NULL)) goto exit; exception->deleted = true; /* Only date */ exception->date = rra_minutes_from_struct(&exdate); /* Date and time */ exdate.tm_min = pattern->start_minute; exception->original_time = rra_minutes_from_struct(&exdate); synce_trace("exception->original_time: %s", asctime(&exdate)); } success = true; exit: return success; }
static bool recurrence_initialize_rrule_ical(const char* str, RRule* rrule) { int i; char** strv = strsplit(str, ';'); rrule->interval = 1; for (i = 0; strv[i]; i++) { char** pair = strsplit(strv[i], '='); if (!pair[0] || !pair[1]) { synce_warning("Invalid rrule part: '%s'", strv[i]); continue; } synce_trace("RRULE part: key=%s, value=%s", pair[0], pair[1]); if (STR_EQUAL(pair[0], "BYDAY")) replace_string_with_copy(&rrule->byday, pair[1]); else if (STR_EQUAL(pair[0], "BYMONTH")) rrule->bymonth = atoi(pair[1]); else if (STR_EQUAL(pair[0], "BYMONTHDAY")) rrule->bymonthday = atoi(pair[1]); else if (STR_EQUAL(pair[0], "BYSETPOS")) rrule->bysetpos = atoi(pair[1]); else if (STR_EQUAL(pair[0], "COUNT")) rrule->count = atoi(pair[1]); else if (STR_EQUAL(pair[0], "FREQ")) { if (STR_EQUAL(pair[1], "DAILY")) rrule->freq = RRuleDaily; else if (STR_EQUAL(pair[1], "WEEKLY")) rrule->freq = RRuleWeekly; else if (STR_EQUAL(pair[1], "MONTHLY")) rrule->freq = RRuleMonthly; else if (STR_EQUAL(pair[1], "YEARLY")) rrule->freq = RRuleYearly; else synce_error("Unexpected frequencey in RRULE '%s'", str); } else if (STR_EQUAL(pair[0], "INTERVAL")) rrule->interval = atoi(pair[1]); else if (STR_EQUAL(pair[0], "UNTIL")) replace_string_with_copy(&rrule->until, pair[1]); else synce_warning("Unhandled part of RRULE: '%s'", strv[i]); strv_free(pair); } strv_free(strv); return true; }
bool generator_set_data(Generator* self, const uint8_t* data, size_t data_size)/*{{{*/ { bool success = false; if (!data) { synce_error("RRA Calendar data is NULL"); goto exit; } if (data_size < 8) { synce_error("Invalid data size for RRA calendar data"); goto exit; } self->propval_count = letoh32(*(uint32_t*)(data + 0)); synce_trace("RRA calendar data field count: %i", self->propval_count); if (0 == self->propval_count) { synce_error("No fields in RRA calendar record!"); goto exit; } if (self->propval_count > MAX_PROPVAL_COUNT) { synce_error("Too many fields in RRA calendar record"); goto exit; } self->propvals = (CEPROPVAL*)malloc(sizeof(CEPROPVAL) * self->propval_count); if (!dbstream_to_propvals(data + 8, self->propval_count, self->propvals)) { synce_error("Failed to convert RRA calendar database stream"); goto exit; } success = true; exit: return success; }/*}}}*/
static void recurrence_append_until_or_count_ical( char* buffer, size_t size, RRA_RecurrencePattern* pattern) { switch (pattern->flags & RecurrenceEndMask) { case RecurrenceEndsOnDate: { struct tm date = rra_minutes_to_struct(pattern->pattern_end_date + pattern->start_minute); strftime(buffer, size, ";UNTIL=%Y%m%dT%H%M%SZ", &date); synce_trace("UNTIL: %s", buffer); } break; case RecurrenceEndsAfterXOccurrences: snprintf(buffer, size, ";COUNT=%i", pattern->occurrences); break; } }
BOOL _CeSHCreateShortcut( LPCWSTR lpszShortcut, LPCWSTR lpszTarget) { RapiContext* context = rapi_context_current(); BOOL return_value = 0; synce_trace("Creating shortcut"); rapi_context_begin_command(context, 0x30); rapi_buffer_write_optional_string(context->send_buffer, lpszShortcut); rapi_buffer_write_optional_string(context->send_buffer, lpszTarget); if ( !rapi_context_call(context) ) goto exit; rapi_buffer_read_uint32(context->recv_buffer, &context->last_error); rapi_buffer_read_uint32(context->recv_buffer, &return_value); exit: return return_value; }
BOOL _CeSetFileAttributes( LPCWSTR lpFileName, DWORD dwFileAttributes) { RapiContext* context = rapi_context_current(); BOOL return_value = false; synce_trace("Setting attributes %08x", dwFileAttributes); rapi_context_begin_command(context, 0x04); rapi_buffer_write_uint32(context->send_buffer, dwFileAttributes); rapi_buffer_write_string(context->send_buffer, lpFileName); if ( !rapi_context_call(context) ) goto exit; rapi_buffer_read_uint32(context->recv_buffer, &context->last_error); rapi_buffer_read_uint32(context->recv_buffer, &return_value); exit: return return_value; }
DWORD _CeGetSpecialFolderPath( int nFolder, DWORD nBufferLength, LPWSTR lpBuffer) { RapiContext* context = rapi_context_current(); size_t string_length = nBufferLength; rapi_context_begin_command(context, 0x44); rapi_buffer_write_uint32(context->send_buffer, (uint32_t)nFolder); rapi_buffer_write_uint32(context->send_buffer, nBufferLength); if ( !rapi_context_call(context) ) return 0; if ( !rapi_buffer_read_uint32(context->recv_buffer, &context->last_error) ) return 0; synce_trace("last_error = %i", context->last_error); if ( !rapi_buffer_read_string(context->recv_buffer, lpBuffer, &string_length) ) return 0; return string_length; }
BOOL _CeFindAllFiles( LPCWSTR szPath, DWORD dwFlags, LPDWORD lpdwFoundCount, LPLPCE_FIND_DATA ppFindDataArray) { RapiContext* context = rapi_context_current(); uint32_t count = 0; rapi_context_begin_command(context, 0x09); rapi_buffer_write_string(context->send_buffer, szPath); rapi_buffer_write_uint32(context->send_buffer, dwFlags); if ( !rapi_context_call(context) ) return false; rapi_buffer_read_uint32(context->recv_buffer, &count); synce_trace("found %i files", count); if (count) { unsigned i; uint32_t name_size; CE_FIND_DATA* array = calloc(count, sizeof(CE_FIND_DATA)); if (!array) return false; for (i = 0; i < count; i++) { if (dwFlags & FAF_NAME) rapi_buffer_read_uint32(context->recv_buffer, &name_size); if (dwFlags & FAF_ATTRIBUTES) rapi_buffer_read_uint32(context->recv_buffer, &array[i].dwFileAttributes); if (dwFlags & FAF_CREATION_TIME) { rapi_buffer_read_uint32(context->recv_buffer, &array[i].ftCreationTime.dwLowDateTime); rapi_buffer_read_uint32(context->recv_buffer, &array[i].ftCreationTime.dwHighDateTime); } if (dwFlags & FAF_LASTACCESS_TIME) { rapi_buffer_read_uint32(context->recv_buffer, &array[i].ftLastAccessTime.dwLowDateTime); rapi_buffer_read_uint32(context->recv_buffer, &array[i].ftLastAccessTime.dwHighDateTime); } if (dwFlags & FAF_LASTWRITE_TIME) { rapi_buffer_read_uint32(context->recv_buffer, &array[i].ftLastWriteTime.dwLowDateTime); rapi_buffer_read_uint32(context->recv_buffer, &array[i].ftLastWriteTime.dwHighDateTime); } if (dwFlags & FAF_SIZE_HIGH) rapi_buffer_read_uint32(context->recv_buffer, &array[i].nFileSizeHigh); if (dwFlags & FAF_SIZE_LOW) rapi_buffer_read_uint32(context->recv_buffer, &array[i].nFileSizeLow); if (dwFlags & FAF_OID) rapi_buffer_read_uint32(context->recv_buffer, &array[i].dwOID); if (dwFlags & FAF_NAME) { rapi_buffer_read_data(context->recv_buffer, array[i].cFileName, name_size * sizeof(WCHAR) ); synce_trace_wstr(array[i].cFileName); } } if (ppFindDataArray) *ppFindDataArray = array; } if (lpdwFoundCount) *lpdwFoundCount = count; return true; }
bool recurrence_parse_rrule( struct _Parser* p, mdir_line* mdir_dtstart, mdir_line* mdir_dtend, mdir_line* mdir_rrule, RRA_MdirLineVector* exdates, RRA_Timezone *tzi) { bool success = false; RRule rrule; RRA_RecurrencePattern* pattern = rra_recurrence_pattern_new(); if (!recurrence_set_dates(pattern, mdir_dtstart, mdir_dtend)) { synce_error("Failed to set dates"); goto exit; } memset(&rrule, 0, sizeof(RRule)); bool rrule_init_result; if (strstr(mdir_rrule->values[0],"FREQ")) rrule_init_result = recurrence_initialize_rrule_ical(mdir_rrule->values[0], &rrule); else rrule_init_result = recurrence_initialize_rrule_vcal(mdir_rrule->values[0], &rrule); if (!rrule_init_result) { synce_error("Failed to parse RRULE '%s'", mdir_rrule->values[0]); goto exit; } if (rrule.freq == RRuleFreqUnknown) { synce_error("No FREQ part in RRULE '%s'", mdir_rrule->values[0]); goto exit; } if (rrule.freq == RRuleDaily) { pattern->recurrence_type = olRecursDaily; /* Convert to Daily with 24*60 times the interval (days->minutes) */ synce_trace("Converting Interval to minutes"); rrule.interval *= MINUTES_PER_DAY; } else if (rrule.freq == RRuleWeekly) { pattern->recurrence_type = olRecursWeekly; recurrence_set_days_of_week_mask(pattern, &rrule); } else if (rrule.freq == RRuleMonthly) { if (rrule.bymonthday) { pattern->recurrence_type = olRecursMonthly; pattern->day_of_month = rrule.bymonthday; } else if (rrule.bysetpos) { pattern->recurrence_type = olRecursMonthNth; pattern->instance = rrule.bysetpos; recurrence_set_days_of_week_mask(pattern, &rrule); } else { synce_error("Missing information for monthly recurrence in RRULE '%s'", mdir_rrule->values[0]); goto exit; } } else if (rrule.freq == RRuleYearly) { /* Convert to Monthly with 12 times the interval */ pattern->recurrence_type = olRecursMonthly; rrule.interval *= 12; if (rrule.bymonthday) { pattern->day_of_month = rrule.bymonthday; } else if (rrule.bysetpos || rrule.bymonth) { synce_error("Don't know how to handle BYSETPOS or BYMONTH in RRULE '%s'", mdir_rrule->values[0]); goto exit; } else { /* Get BYMONTHDAY from start date */ struct tm start_date = rra_minutes_to_struct(pattern->pattern_start_date); pattern->day_of_month = start_date.tm_mday; } } else { synce_error("Unexpected frequencey in RRULE '%s'", mdir_rrule->values[0]); goto exit; } pattern->interval = rrule.interval; if (rrule.count) { pattern->occurrences = rrule.count; pattern->flags |= RecurrenceEndsAfterXOccurrences; /* XXX calculate pattern->pattern_end_date */ /* CE requires an explicit end date */ /* XXX Could be problematic with leap years */ switch (pattern->recurrence_type) { case olRecursDaily: synce_trace("Calculating Pattern end date for daily recursion"); pattern->pattern_end_date = pattern->pattern_start_date + (rrule.count-1) * rrule.interval; break; case olRecursWeekly: /* XXX Only works for interval=1 at the moment */ synce_trace("Calculating Pattern end date for weekly recursion"); uint32_t count_in_mask=0; int i; for (i=0; i<7; i++) if (pattern->days_of_week_mask & (1 << i)) count_in_mask++; uint32_t days_to_add=((rrule.count-1)/count_in_mask)*7; uint32_t rest=(rrule.count-1)%count_in_mask; struct tm start_date = rra_minutes_to_struct(pattern->pattern_start_date); /* rotate the bitmask */ uint32_t biased_mask = (pattern->days_of_week_mask | ((pattern->days_of_week_mask & ((1<<start_date.tm_wday)-1)) << 7))>>(start_date.tm_wday+1); while (rest) { rest--; while (biased_mask%2==0) { if (biased_mask==0) {synce_error("Calculation of Pattern end date failed"); goto failed;} days_to_add++; biased_mask>>=1; } days_to_add++; biased_mask>>=1; } pattern->pattern_end_date = pattern->pattern_start_date + days_to_add * MINUTES_PER_DAY; break; default: failed: synce_trace("FIXME: Have to calculate Pattern end date"); pattern->pattern_end_date = RRA_DoesNotEndDate; } }
static bool recurrence_set_dates( RRA_RecurrencePattern* pattern, mdir_line* mdir_dtstart, mdir_line* mdir_dtend) { bool success = false; struct tm start_struct; struct tm tmp_struct; time_t start; time_t end; int32_t minutes = 0; ParserTimeFormat format = parser_get_time_format(mdir_dtstart); bool start_is_utc = false; bool end_is_utc = false; /* XXX timezone handling? */ if (!parser_datetime_to_struct(mdir_dtstart->values[0], &start_struct, NULL)) goto exit; if (!parser_datetime_to_unix_time(mdir_dtstart->values[0], &start, &start_is_utc)) goto exit; if (!parser_datetime_to_unix_time(mdir_dtend->values[0], &end, &end_is_utc)) goto exit; #if VERBOSE synce_trace("start is %s", asctime(&start_struct)); synce_trace("start is utc: %i, end is utc: %i", start_is_utc, end_is_utc); #endif tmp_struct = start_struct; tmp_struct.tm_sec = 0; tmp_struct.tm_min = 0; tmp_struct.tm_hour = 0; pattern->pattern_start_date = rra_minutes_from_struct(&tmp_struct); pattern->start_minute = start_struct.tm_hour * 60 + start_struct.tm_min; switch (format) { case PARSER_TIME_FORMAT_UNKNOWN: goto exit; case PARSER_TIME_FORMAT_DATE_AND_TIME: minutes = (end - start) / 60; break; case PARSER_TIME_FORMAT_ONLY_DATE: minutes = (end - start - SECONDS_PER_DAY) / 60 + 1; break; } pattern->end_minute = pattern->start_minute + minutes; synce_trace("pattern->start_minute/60: %u", pattern->start_minute / 60); synce_trace("pattern->end_minute /60: %u", pattern->end_minute / 60); success = true; exit: return success; }
bool generator_run(Generator* self) { unsigned i; bool success = false; for (i = 0; i < self->propval_count; i++) { uint16_t id = self->propvals[i].propid >> 16; GeneratorProperty* gp = (GeneratorProperty*)s_hash_table_lookup(self->properties, &id); if (gp) { if (!gp->func(self, &self->propvals[i], self->cookie)) goto exit; } else { char *tmp_str; switch (self->propvals[i].propid & 0xffff) { case CEVT_BLOB: synce_trace("Generator: Unhandled property, id: %04x, type: BLOB", id); break; case CEVT_BOOL: if (self->propvals[i].val.boolVal == FALSE) synce_trace("Generator: Unhandled property, id: %04x, type: bool:FALSE", id); else synce_trace("Generator: Unhandled property, id: %04x, type: bool:TRUE", id); break; case CEVT_FILETIME: if ((0 == self->propvals[i].val.filetime.dwLowDateTime) && (0 == self->propvals[i].val.filetime.dwHighDateTime)) synce_trace("Generator: Unhandled property, id: %04x, type: filetime:NULL", id); else { time_t start_time; char buffer[32]; parser_filetime_to_unix_time(&self->propvals[i].val.filetime, &start_time); strftime(buffer, sizeof(buffer), "%Y%m%dT%H%M%SZ", gmtime(&start_time)); synce_trace("Generator: Unhandled property, id: %04x, type: filetime:%08x %08x=%s", id, self->propvals[i].val.filetime.dwHighDateTime, self->propvals[i].val.filetime.dwLowDateTime, buffer); } break; case CEVT_I2: synce_trace("Generator: Unhandled property, id: %04x, type: I2:%d", id, self->propvals[i].val.iVal); break; case CEVT_I4: synce_trace("Generator: Unhandled property, id: %04x, type: I4:%d", id, self->propvals[i].val.iVal); break; case CEVT_LPWSTR: tmp_str = wstr_to_current(self->propvals[i].val.lpwstr); synce_trace("Generator: Unhandled property, id: %04x, type: WSTR:%s", id, tmp_str); free(tmp_str); break; case CEVT_R8: synce_trace("Generator: Unhandled property, id: %04x, type: R8", id); break; case CEVT_UI2: synce_trace("Generator: Unhandled property, id: %04x, type: UI2:%u", id, self->propvals[i].val.uiVal); break; case CEVT_UI4: synce_trace("Generator: Unhandled property, id: %04x, type: UI4:%u", id, self->propvals[i].val.uiVal); break; default: synce_trace("Generator: Unhandled property, id: %04x, unknown type: %u", id, (self->propvals[i].propid & 0xffff)); break; } } } success = true; exit: return success; }