* to the currently selected room.
*/
void ical_write_to_cal(struct ctdluser *u, icalcomponent *cal) {
- char temp[PATH_MAX];
- FILE *fp = NULL;
char *ser = NULL;
icalcomponent *encaps = NULL;
struct CtdlMessage *msg = NULL;
/* If the caller supplied a user, write to that user's default calendar room */
if (u) {
- /* Make a temp file out of it */
- CtdlMakeTempFileName(temp, sizeof temp);
- fp = fopen(temp, "w");
- if (fp != NULL) {
- fwrite(ser, strlen(ser), 1, fp);
- fclose(fp);
-
- /* This handy API function does all the work for us. */
- CtdlWriteObject(USERCALENDARROOM, /* which room */
- "text/calendar", /* MIME type */
- temp, /* temp file */
- u, /* which user */
- 0, /* not binary */
- 0, /* don't delete others of this type */
- 0 /* no flags */
- );
- unlink(temp);
- }
+ /* This handy API function does all the work for us. */
+ CtdlWriteObject(USERCALENDARROOM, /* which room */
+ "text/calendar", /* MIME type */
+ ser, /* data */
+ strlen(ser)+1, /* length */
+ u, /* which user */
+ 0, /* not binary */
+ 0, /* don't delete others of this type */
+ 0 /* no flags */
+ );
}
/* If the caller did not supply a user, write to the currently selected room */
strcat(msg->cm_fields['M'], ser);
/* Now write the data */
- CtdlSubmitMsg(msg, NULL, "");
+ CtdlSubmitMsg(msg, NULL, "", QP_EADDR);
CtdlFreeMessage(msg);
}
reply_message_text = malloc(strlen(serialized_reply) + SIZ);
if (reply_message_text != NULL) {
sprintf(reply_message_text,
- "Content-type: text/calendar charset=\"utf-8\"\r\n\r\n%s\r\n",
+ "Content-type: text/calendar; charset=\"utf-8\"\r\n\r\n%s\r\n",
serialized_reply
);
if (msg != NULL) {
valid = validate_recipients(organizer_string, NULL, 0);
- CtdlSubmitMsg(msg, valid, "");
+ CtdlSubmitMsg(msg, valid, "", QP_EADDR);
CtdlFreeMessage(msg);
free_recipients(valid);
}
/*
* Look in the EUID index for a message with
* the Citadel EUID set to the value we're looking for. Since
- * Citadel always sets the message EUID to the vCalendar UID of
+ * Citadel always sets the message EUID to the iCalendar UID of
* the event, this will work.
*/
msgnum_being_replaced = locate_message_by_euid(uid, &CC->room);
message_text = malloc(strlen(serialized_event) + SIZ);
if (message_text != NULL) {
sprintf(message_text,
- "Content-type: text/calendar charset=\"utf-8\"\r\n\r\n%s\r\n",
+ "Content-type: text/calendar; charset=\"utf-8\"\r\n\r\n%s\r\n",
serialized_event
);
if (msg != NULL) {
CIT_ICAL->avoid_sending_invitations = 1;
- CtdlSubmitMsg(msg, NULL, roomname);
+ CtdlSubmitMsg(msg, NULL, roomname, QP_EADDR);
CtdlFreeMessage(msg);
CIT_ICAL->avoid_sending_invitations = 0;
}
/* First, check for all-day events */
if (t1start.is_date) {
- if (!icaltime_compare_date_only(t1start, t2start,
- icaltimezone_get_utc_timezone())) {
+ if (!icaltime_compare_date_only(t1start, t2start)) {
return(1);
}
if (!icaltime_is_null_time(t2end)) {
- if (!icaltime_compare_date_only(t1start, t2end,
- icaltimezone_get_utc_timezone())) {
+ if (!icaltime_compare_date_only(t1start, t2end)) {
return(1);
}
}
}
if (t2start.is_date) {
- if (!icaltime_compare_date_only(t2start, t1start,
- icaltimezone_get_utc_timezone())) {
+ if (!icaltime_compare_date_only(t2start, t1start)) {
return(1);
}
if (!icaltime_is_null_time(t1end)) {
- if (!icaltime_compare_date_only(t2start, t1end,
- icaltimezone_get_utc_timezone())) {
+ if (!icaltime_compare_date_only(t2start, t1end)) {
return(1);
}
}
+
/*
- * Backend for ical_hunt_for_conflicts()
+ * Called by ical_hunt_for_conflicts_backend()
+ *
+ * At this point we've got it boiled down to two icalcomponent events in memory.
+ * If they conflict, output something to the client.
*/
-void ical_hunt_for_conflicts_backend(long msgnum, void *data) {
- icalcomponent *cal;
- struct CtdlMessage *msg = NULL;
- struct ical_respond_data ird;
+void ical_output_conflicts(icalcomponent *proposed_event,
+ icalcomponent *existing_event,
+ long existing_msgnum)
+{
struct icaltimetype t1start, t1end, t2start, t2end;
+ t1start = icaltime_null_time();
+ t1end = icaltime_null_time();
+ t2start = icaltime_null_time();
+ t1end = icaltime_null_time();
icalproperty *p;
char conflict_event_uid[SIZ];
char conflict_event_summary[SIZ];
char compare_uid[SIZ];
- cal = (icalcomponent *)data;
+
+ /* initialization */
+
strcpy(compare_uid, "");
strcpy(conflict_event_uid, "");
strcpy(conflict_event_summary, "");
- msg = CtdlFetchMessage(msgnum, 1);
- if (msg == NULL) return;
- memset(&ird, 0, sizeof ird);
- strcpy(ird.desired_partnum, "_HUNT_");
- mime_parser(msg->cm_fields['M'],
- NULL,
- *ical_locate_part, /* callback function */
- NULL, NULL,
- (void *) &ird, /* user data */
- 0
- );
- CtdlFreeMessage(msg);
-
- if (ird.cal == NULL) return;
- t1start = icaltime_null_time();
- t1end = icaltime_null_time();
- t2start = icaltime_null_time();
- t1end = icaltime_null_time();
+ /* existing event stuff */
- /* Now compare cal to ird.cal */
- p = ical_ctdl_get_subprop(ird.cal, ICAL_DTSTART_PROPERTY);
+ p = ical_ctdl_get_subprop(existing_event, ICAL_DTSTART_PROPERTY);
if (p == NULL) return;
if (p != NULL) t2start = icalproperty_get_dtstart(p);
- p = ical_ctdl_get_subprop(ird.cal, ICAL_DTEND_PROPERTY);
+ p = ical_ctdl_get_subprop(existing_event, ICAL_DTEND_PROPERTY);
if (p != NULL) t2end = icalproperty_get_dtend(p);
- p = ical_ctdl_get_subprop(cal, ICAL_DTSTART_PROPERTY);
+ p = ical_ctdl_get_subprop(existing_event, ICAL_UID_PROPERTY);
+ if (p != NULL) {
+ strcpy(conflict_event_uid, icalproperty_get_comment(p));
+ }
+
+ p = ical_ctdl_get_subprop(existing_event, ICAL_SUMMARY_PROPERTY);
+ if (p != NULL) {
+ strcpy(conflict_event_summary, icalproperty_get_comment(p));
+ }
+
+
+ /* proposed event stuff */
+
+ p = ical_ctdl_get_subprop(proposed_event, ICAL_DTSTART_PROPERTY);
if (p == NULL) return;
if (p != NULL) t1start = icalproperty_get_dtstart(p);
- p = ical_ctdl_get_subprop(cal, ICAL_DTEND_PROPERTY);
+ p = ical_ctdl_get_subprop(proposed_event, ICAL_DTEND_PROPERTY);
if (p != NULL) t1end = icalproperty_get_dtend(p);
- p = ical_ctdl_get_subprop(cal, ICAL_UID_PROPERTY);
+ p = ical_ctdl_get_subprop(proposed_event, ICAL_UID_PROPERTY);
if (p != NULL) {
strcpy(compare_uid, icalproperty_get_comment(p));
}
- p = ical_ctdl_get_subprop(ird.cal, ICAL_UID_PROPERTY);
- if (p != NULL) {
- strcpy(conflict_event_uid, icalproperty_get_comment(p));
- }
- p = ical_ctdl_get_subprop(ird.cal, ICAL_SUMMARY_PROPERTY);
- if (p != NULL) {
- strcpy(conflict_event_summary, icalproperty_get_comment(p));
- }
-
- icalcomponent_free(ird.cal);
+ /* compare and output */
if (ical_ctdl_is_overlap(t1start, t1end, t2start, t2end)) {
cprintf("%ld||%s|%s|%d|\n",
- msgnum,
+ existing_msgnum,
conflict_event_uid,
conflict_event_summary,
( ((strlen(compare_uid)>0)
)
);
}
+
+}
+
+
+
+/*
+ * Called by ical_hunt_for_conflicts()
+ */
+void ical_hunt_for_conflicts_backend(long msgnum, void *data) {
+ icalcomponent *proposed_event;
+ struct CtdlMessage *msg = NULL;
+ struct ical_respond_data ird;
+
+ proposed_event = (icalcomponent *)data;
+
+ msg = CtdlFetchMessage(msgnum, 1);
+ if (msg == NULL) return;
+ memset(&ird, 0, sizeof ird);
+ strcpy(ird.desired_partnum, "_HUNT_");
+ mime_parser(msg->cm_fields['M'],
+ NULL,
+ *ical_locate_part, /* callback function */
+ NULL, NULL,
+ (void *) &ird, /* user data */
+ 0
+ );
+ CtdlFreeMessage(msg);
+
+ if (ird.cal == NULL) return;
+
+ /* here it is */
+ ical_output_conflicts(proposed_event, ird.cal, msgnum);
+ icalcomponent_free(ird.cal);
}
/*
* Phase 2 of "hunt for conflicts" operation.
* At this point we have a calendar object which represents the VEVENT that
- * we're considering adding to the calendar. Now hunt through the user's
+ * is proposed for addition to the calendar. Now hunt through the user's
* calendar room, and output zero or more existing VEVENTs which conflict
* with this one.
*/
if ( (CC->room.QRdefaultview != VIEW_CALENDAR)
&&(CC->room.QRdefaultview != VIEW_TASKS) ) {
cprintf("%d Not a calendar room\n", ERROR+NOT_HERE);
- return; /* Not a vCalendar-centric room */
+ return; /* Not an iCalendar-centric room */
}
encaps = icalcomponent_new_vcalendar();
if ( (CC->room.QRdefaultview != VIEW_CALENDAR)
&&(CC->room.QRdefaultview != VIEW_TASKS) ) {
cprintf("%d Not a calendar room\n", ERROR+NOT_HERE);
- return; /* Not a vCalendar-centric room */
+ return; /* Not an iCalendar-centric room */
}
if (!CtdlDoIHavePermissionToDeleteMessagesFromThisRoom()) {
if (msg != NULL) {
valid = validate_recipients(attendees_string, NULL, 0);
- CtdlSubmitMsg(msg, valid, "");
+ CtdlSubmitMsg(msg, valid, "", QP_EADDR);
CtdlFreeMessage(msg);
free_recipients(valid);
}
* the summary of the event (becomes message subject),
* and the start time (becomes message date/time).
*/
-void ical_ctdl_set_exclusive_msgid(char *name, char *filename, char *partnum,
+void ical_obj_beforesave_backend(char *name, char *filename, char *partnum,
char *disp, void *content, char *cbtype, char *cbcharset, size_t length,
char *encoding, void *cbuserdata)
{
icalcomponent *cal, *nested_event, *nested_todo, *whole_cal;
icalproperty *p;
- struct icalmessagemod *imm;
- char new_uid[SIZ];
+ char new_uid[256] = "";
+ char buf[1024] = "";
+ struct CtdlMessage *msg = (struct CtdlMessage *) cbuserdata;
- imm = (struct icalmessagemod *)cbuserdata;
+ if (!msg) return;
/* We're only interested in calendar data. */
if ( (strcasecmp(cbtype, "text/calendar"))
}
if (cal != NULL) {
+
+ /* Set the message EUID to the iCalendar UID */
+
p = ical_ctdl_get_subprop(cal, ICAL_UID_PROPERTY);
if (p == NULL) {
/* If there's no uid we must generate one */
p = ical_ctdl_get_subprop(cal, ICAL_UID_PROPERTY);
}
if (p != NULL) {
- strcpy(imm->uid, icalproperty_get_comment(p));
+ safestrncpy(buf, icalproperty_get_comment(p), sizeof buf);
+ if (!IsEmptyStr(buf)) {
+ if (msg->cm_fields['E'] != NULL) {
+ free(msg->cm_fields['E']);
+ }
+ msg->cm_fields['E'] = strdup(buf);
+ CtdlLogPrintf(CTDL_DEBUG, "Saving calendar UID <%s>\n", buf);
+ }
}
+
+ /* Set the message subject to the iCalendar summary */
+
p = ical_ctdl_get_subprop(cal, ICAL_SUMMARY_PROPERTY);
if (p != NULL) {
- strcpy(imm->subject, icalproperty_get_comment(p));
+ safestrncpy(buf, icalproperty_get_comment(p), sizeof buf);
+ if (!IsEmptyStr(buf)) {
+ if (msg->cm_fields['U'] != NULL) {
+ free(msg->cm_fields['U']);
+ }
+ msg->cm_fields['U'] = strdup(buf);
+ }
}
+
+ /* Set the message date/time to the iCalendar start time */
+
p = ical_ctdl_get_subprop(cal, ICAL_DTSTART_PROPERTY);
if (p != NULL) {
- imm->dtstart = icaltime_as_timet(icalproperty_get_dtstart(p));
+ time_t idtstart;
+ idtstart = icaltime_as_timet(icalproperty_get_dtstart(p));
+ if (idtstart > 0) {
+ if (msg->cm_fields['T'] != NULL) {
+ free(msg->cm_fields['T']);
+ }
+ msg->cm_fields['T'] = strdup("000000000000000000");
+ sprintf(msg->cm_fields['T'], "%ld", idtstart);
+ }
}
+
}
icalcomponent_free(cal);
if (whole_cal != cal) {
/*
* See if we need to prevent the object from being saved (we don't allow
- * MIME types other than text/calendar in "calendar" or "tasks" rooms). Also,
- * when saving an event to the calendar, set the message's Citadel exclusive
- * message ID to the UID of the object. This causes our replication checker to
- * automatically delete any existing instances of the same object. (Isn't
- * that cool?)
+ * MIME types other than text/calendar in "calendar" or "tasks" rooms).
*
- * We also set the message's Subject to the event summary, and the Date/time to
- * the event start time.
+ * If the message is being saved, we also set various message header fields
+ * using data found in the iCalendar object.
*/
int ical_obj_beforesave(struct CtdlMessage *msg)
{
- struct icalmessagemod imm;
-
/* First determine if this is a calendar or tasks room */
if ( (CC->room.QRdefaultview != VIEW_CALENDAR)
&& (CC->room.QRdefaultview != VIEW_TASKS)
) {
- return(0); /* Not a vCalendar-centric room */
+ return(0); /* Not an iCalendar-centric room */
}
/* It must be an RFC822 message! */
return(1); /* You tried to save a null message! */
}
- memset(&imm, 0, sizeof(struct icalmessagemod));
-
/* Do all of our lovely back-end parsing */
mime_parser(msg->cm_fields['M'],
NULL,
- *ical_ctdl_set_exclusive_msgid,
+ *ical_obj_beforesave_backend,
NULL, NULL,
- (void *)&imm,
+ (void *)msg,
0
);
- if (!IsEmptyStr(imm.uid)) {
- if (msg->cm_fields['E'] != NULL) {
- free(msg->cm_fields['E']);
- }
- msg->cm_fields['E'] = strdup(imm.uid);
- CtdlLogPrintf(CTDL_DEBUG, "Saving calendar UID <%s>\n", msg->cm_fields['E']);
- }
- if (!IsEmptyStr(imm.subject)) {
- if (msg->cm_fields['U'] != NULL) {
- free(msg->cm_fields['U']);
- }
- msg->cm_fields['U'] = strdup(imm.subject);
- }
- if (imm.dtstart > 0) {
- if (msg->cm_fields['T'] != NULL) {
- free(msg->cm_fields['T']);
- }
- msg->cm_fields['T'] = strdup("000000000000000000");
- sprintf(msg->cm_fields['T'], "%ld", imm.dtstart);
- }
-
return(0);
}
/*
- * Function to output vcalendar data as plain text. Nobody uses MSG0
+ * Function to output iCalendar data as plain text. Nobody uses MSG0
* anymore, so really this is just so we expose the vCard data to the full
* text indexer.
*/