#ifdef HAVE_STRINGS_H
#include <strings.h>
#endif
+#include <ical.h>
+#include <libcitadel.h>
#include "citadel.h"
#include "server.h"
#include "citserver.h"
#include "config.h"
#include "user_ops.h"
#include "room_ops.h"
-#include "tools.h"
#include "msgbase.h"
-#include "mime_parser.h"
#include "internet_addressing.h"
#include "serv_calendar.h"
#include "euidindex.h"
#include "ctdl_module.h"
-
-#ifdef CITADEL_WITH_CALENDAR_SERVICE
-
-#include <ical.h>
#include "ical_dezonify.h"
encaps = icalcomponent_new_vcalendar();
if (encaps == NULL) {
- lprintf(CTDL_CRIT, "Error at %s:%d - could not allocate component!\n",
+ CtdlLogPrintf(CTDL_CRIT, "Error at %s:%d - could not allocate component!\n",
__FILE__, __LINE__);
return NULL;
}
/*
* Write a calendar object into the specified user's calendar room.
+ * If the supplied user is NULL, this function writes the calendar object
+ * to the currently selected room.
*/
void ical_write_to_cal(struct ctdluser *u, icalcomponent *cal) {
- char temp[PATH_MAX];
- FILE *fp;
- char *ser;
- icalcomponent *encaps;
+ char *ser = NULL;
+ icalcomponent *encaps = NULL;
+ struct CtdlMessage *msg = NULL;
+ icalcomponent *tmp=NULL;
if (cal == NULL) return;
* a full VCALENDAR component, and save that instead.
*/
if (icalcomponent_isa(cal) != ICAL_VCALENDAR_COMPONENT) {
- encaps = ical_encapsulate_subcomponent(
- icalcomponent_new_clone(cal)
- );
+ tmp = icalcomponent_new_clone(cal);
+ encaps = ical_encapsulate_subcomponent(tmp);
ical_write_to_cal(u, encaps);
+ icalcomponent_free(tmp);
icalcomponent_free(encaps);
return;
}
- CtdlMakeTempFileName(temp, sizeof temp);
ser = icalcomponent_as_ical_string(cal);
if (ser == NULL) return;
- /* Make a temp file out of it */
- fp = fopen(temp, "w");
- if (fp == NULL) return;
- fwrite(ser, strlen(ser), 1, fp);
- fclose(fp);
-
- /* This handy API function does all the work for us.
- */
- CtdlWriteObject(USERCALENDARROOM, /* which room */
+ /* If the caller supplied a user, write to that user's default calendar room */
+ if (u) {
+ /* This handy API function does all the work for us. */
+ CtdlWriteObject(USERCALENDARROOM, /* which room */
"text/calendar", /* MIME type */
- temp, /* temp file */
+ ser, /* data */
+ strlen(ser)+1, /* length */
u, /* which user */
0, /* not binary */
- 0, /* don't delete others of this type */
- 0); /* no flags */
+ 0, /* don't delete others of this type */
+ 0 /* no flags */
+ );
+ }
- unlink(temp);
+ /* If the caller did not supply a user, write to the currently selected room */
+ if (!u) {
+ msg = malloc(sizeof(struct CtdlMessage));
+ memset(msg, 0, sizeof(struct CtdlMessage));
+ msg->cm_magic = CTDLMESSAGE_MAGIC;
+ msg->cm_anon_type = MES_NORMAL;
+ msg->cm_format_type = 4;
+ msg->cm_fields['A'] = strdup(CC->user.fullname);
+ msg->cm_fields['O'] = strdup(CC->room.QRname);
+ msg->cm_fields['N'] = strdup(config.c_nodename);
+ msg->cm_fields['H'] = strdup(config.c_humannode);
+ msg->cm_fields['M'] = malloc(strlen(ser) + 40);
+ strcpy(msg->cm_fields['M'], "Content-type: text/calendar\r\n\r\n");
+ strcat(msg->cm_fields['M'], ser);
+
+ /* Now write the data */
+ CtdlSubmitMsg(msg, NULL, "", QP_EADDR);
+ CtdlFreeMessage(msg);
+ }
+
+ /* In either case, now we can free the serialized calendar object */
+// free(ser);
}
strcpy(summary_string, "Calendar item");
if (request == NULL) {
- lprintf(CTDL_ERR, "ERROR: trying to reply to NULL event?\n");
+ CtdlLogPrintf(CTDL_ERR, "ERROR: trying to reply to NULL event?\n");
return;
}
the_reply = icalcomponent_new_clone(request);
if (the_reply == NULL) {
- lprintf(CTDL_ERR, "ERROR: cannot clone request\n");
+ CtdlLogPrintf(CTDL_ERR, "ERROR: cannot clone request\n");
return;
}
if (!strncasecmp(attendee_string, "MAILTO:", 7)) {
strcpy(attendee_string, &attendee_string[7]);
striplt(attendee_string);
- recp = validate_recipients(attendee_string);
+ recp = validate_recipients(attendee_string, NULL, 0);
if (recp != NULL) {
if (!strcasecmp(recp->recp_local, CC->user.fullname)) {
if (me_attend) icalproperty_free(me_attend);
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
);
"",
summary_string, /* Use summary for subject */
NULL,
- reply_message_text);
+ reply_message_text,
+ NULL);
if (msg != NULL) {
- valid = validate_recipients(organizer_string);
- CtdlSubmitMsg(msg, valid, "");
+ valid = validate_recipients(organizer_string, NULL, 0);
+ CtdlSubmitMsg(msg, valid, "", QP_EADDR);
CtdlFreeMessage(msg);
free_recipients(valid);
}
}
}
- if (strcasecmp(cbtype, "text/calendar")) {
+ if ( (strcasecmp(cbtype, "text/calendar"))
+ && (strcasecmp(cbtype, "application/ics")) ) {
return;
}
struct original_event_container *oec = NULL;
- if (strcasecmp(cbtype, "text/calendar")) {
+ if ( (strcasecmp(cbtype, "text/calendar"))
+ && (strcasecmp(cbtype, "application/ics")) ) {
return;
}
oec = (struct original_event_container *) cbuserdata;
/* Figure out just what event it is we're dealing with */
strcpy(uid, "--==<< InVaLiD uId >>==--");
ical_learn_uid_of_reply(uid, cal);
- lprintf(CTDL_DEBUG, "UID of event being replied to is <%s>\n", uid);
+ CtdlLogPrintf(CTDL_DEBUG, "UID of event being replied to is <%s>\n", uid);
strcpy(hold_rm, CC->room.QRname); /* save current room */
if (getroom(&CC->room, USERCALENDARROOM) != 0) {
getroom(&CC->room, hold_rm);
- lprintf(CTDL_CRIT, "cannot get user calendar room\n");
+ CtdlLogPrintf(CTDL_CRIT, "cannot get user calendar room\n");
return(2);
}
/*
* 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);
getroom(&CC->room, hold_rm); /* return to saved room */
- lprintf(CTDL_DEBUG, "msgnum_being_replaced == %ld\n", msgnum_being_replaced);
+ CtdlLogPrintf(CTDL_DEBUG, "msgnum_being_replaced == %ld\n", msgnum_being_replaced);
if (msgnum_being_replaced == 0) {
return(1); /* no calendar event found */
}
original_event = oec.c;
if (original_event == NULL) {
- lprintf(CTDL_ERR, "ERROR: Original_component is NULL.\n");
+ CtdlLogPrintf(CTDL_ERR, "ERROR: Original_component is NULL.\n");
return(2);
}
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
);
"",
"", /* no subject */
NULL,
- message_text);
+ message_text,
+ NULL);
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;
}
+
/*
- * 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;
+ /* existing event stuff */
- t1start = icaltime_null_time();
- t1end = icaltime_null_time();
- t2start = icaltime_null_time();
- t1end = icaltime_null_time();
-
- /* 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 not found, try it as an unqualified email address. */
if (found_user != 0) {
strcpy(buf, who);
- recp = validate_recipients(buf);
- lprintf(CTDL_DEBUG, "Trying <%s>\n", buf);
+ recp = validate_recipients(buf, NULL, 0);
+ CtdlLogPrintf(CTDL_DEBUG, "Trying <%s>\n", buf);
if (recp != NULL) {
if (recp->num_local == 1) {
found_user = getuser(&usbuf, recp->recp_local);
*/
if (found_user != 0) {
snprintf(buf, sizeof buf, "%s@%s", who, config.c_fqdn);
- lprintf(CTDL_DEBUG, "Trying <%s>\n", buf);
- recp = validate_recipients(buf);
+ CtdlLogPrintf(CTDL_DEBUG, "Trying <%s>\n", buf);
+ recp = validate_recipients(buf, NULL, 0);
if (recp != NULL) {
if (recp->num_local == 1) {
found_user = getuser(&usbuf, recp->recp_local);
if ( (!strcasecmp(type, "localhost"))
|| (!strcasecmp(type, "directory")) ) {
snprintf(buf, sizeof buf, "%s@%s", who, host);
- lprintf(CTDL_DEBUG, "Trying <%s>\n", buf);
- recp = validate_recipients(buf);
+ CtdlLogPrintf(CTDL_DEBUG, "Trying <%s>\n", buf);
+ recp = validate_recipients(buf, NULL, 0);
if (recp != NULL) {
if (recp->num_local == 1) {
found_user = getuser(&usbuf, recp->recp_local);
}
/* Create a VFREEBUSY subcomponent */
- lprintf(CTDL_DEBUG, "Creating VFREEBUSY component\n");
+ CtdlLogPrintf(CTDL_DEBUG, "Creating VFREEBUSY component\n");
fb = icalcomponent_new_vfreebusy();
if (fb == NULL) {
cprintf("%d Internal error: cannot allocate memory.\n",
ERROR + INTERNAL_ERROR);
- icalcomponent_free(encaps);
getroom(&CC->room, hold_rm);
return;
}
strcat(buf, "@");
strcat(buf, config.c_fqdn);
}
- for (i=0; !IsEmptyStr(&buf[i]); ++i) {
+ for (i=0; buf[i]; ++i) {
if (buf[i]==' ') buf[i] = '_';
}
icalcomponent_add_property(fb, icalproperty_new_organizer(buf));
/* Add busy time from events */
- lprintf(CTDL_DEBUG, "Adding busy time from events\n");
+ CtdlLogPrintf(CTDL_DEBUG, "Adding busy time from events\n");
CtdlForEachMessage(MSGS_ALL, 0, NULL, NULL, NULL, ical_freebusy_backend, (void *)fb );
/* If values for DTSTART and DTEND are still not present, set them
}
/* Put the freebusy component into the calendar component */
- lprintf(CTDL_DEBUG, "Encapsulating\n");
+ CtdlLogPrintf(CTDL_DEBUG, "Encapsulating\n");
encaps = ical_encapsulate_subcomponent(fb);
if (encaps == NULL) {
icalcomponent_free(fb);
}
/* Set the method to PUBLISH */
- lprintf(CTDL_DEBUG, "Setting method\n");
+ CtdlLogPrintf(CTDL_DEBUG, "Setting method\n");
icalcomponent_set_method(encaps, ICAL_METHOD_PUBLISH);
/* Serialize it */
- lprintf(CTDL_DEBUG, "Serializing\n");
+ CtdlLogPrintf(CTDL_DEBUG, "Serializing\n");
serialized_request = strdup(icalcomponent_as_ical_string(encaps));
icalcomponent_free(encaps); /* Don't need this anymore. */
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 (encaps == NULL) {
- lprintf(CTDL_DEBUG, "Error at %s:%d - could not allocate component!\n",
+ CtdlLogPrintf(CTDL_DEBUG, "Error at %s:%d - could not allocate component!\n",
__FILE__, __LINE__);
cprintf("%d Could not allocate memory\n", ERROR+INTERNAL_ERROR);
return;
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()) {
}
cprintf("%d Transmit data now\n", SEND_LISTING);
- calstream = CtdlReadMessageBody("000", config.c_maxmsglen, NULL, 0);
+ calstream = CtdlReadMessageBody("000", config.c_maxmsglen, NULL, 0, 0);
if (calstream == NULL) {
return;
}
* in. This will almost never happen.
*/
if (icalcomponent_isa(cal) != ICAL_VCALENDAR_COMPONENT) {
- ical_write_to_cal(&CC->user, cal);
+ ical_write_to_cal(NULL, cal);
}
/*
* In the more likely event that we're looking at a VCALENDAR with the VEVENT
for (c = icalcomponent_get_first_component(cal, ICAL_ANY_COMPONENT);
(c != NULL);
c = icalcomponent_get_next_component(cal, ICAL_ANY_COMPONENT)) {
- ical_write_to_cal(&CC->user, c);
+ ical_write_to_cal(NULL, c);
}
}
/* Set expiration policy to manual; otherwise objects will be lost! */
if (lgetroom(&qr, USERCALENDARROOM)) {
- lprintf(CTDL_CRIT, "Couldn't get the user calendar room!\n");
+ CtdlLogPrintf(CTDL_CRIT, "Couldn't get the user calendar room!\n");
return;
}
qr.QRep.expire_mode = EXPIRE_MANUAL;
/* Set expiration policy to manual; otherwise objects will be lost! */
if (lgetroom(&qr, USERTASKSROOM)) {
- lprintf(CTDL_CRIT, "Couldn't get the user calendar room!\n");
+ CtdlLogPrintf(CTDL_CRIT, "Couldn't get the user calendar room!\n");
return;
}
qr.QRep.expire_mode = EXPIRE_MANUAL;
/* Set expiration policy to manual; otherwise objects will be lost! */
if (lgetroom(&qr, USERNOTESROOM)) {
- lprintf(CTDL_CRIT, "Couldn't get the user calendar room!\n");
+ CtdlLogPrintf(CTDL_CRIT, "Couldn't get the user calendar room!\n");
return;
}
qr.QRep.expire_mode = EXPIRE_MANUAL;
icalproperty *attendee = NULL;
char summary_string[SIZ];
icalproperty *summary = NULL;
+ size_t reqsize;
if (cal == NULL) {
- lprintf(CTDL_ERR, "ERROR: trying to reply to NULL event?\n");
+ CtdlLogPrintf(CTDL_ERR, "ERROR: trying to reply to NULL event?\n");
return;
}
/* Clone the event */
the_request = icalcomponent_new_clone(cal);
if (the_request == NULL) {
- lprintf(CTDL_ERR, "ERROR: cannot clone calendar object\n");
+ CtdlLogPrintf(CTDL_ERR, "ERROR: cannot clone calendar object\n");
return;
}
}
}
- lprintf(CTDL_DEBUG, "<%d> attendees: <%s>\n", num_attendees, attendees_string);
+ CtdlLogPrintf(CTDL_DEBUG, "<%d> attendees: <%s>\n", num_attendees, attendees_string);
/* If there are no attendees, there are no invitations to send, so...
* don't bother putting one together! Punch out, Maverick!
/* Encapsulate the VEVENT component into a complete VCALENDAR */
encaps = icalcomponent_new_vcalendar();
if (encaps == NULL) {
- lprintf(CTDL_DEBUG, "Error at %s:%d - could not allocate component!\n",
+ CtdlLogPrintf(CTDL_DEBUG, "Error at %s:%d - could not allocate component!\n",
__FILE__, __LINE__);
icalcomponent_free(the_request);
return;
icalcomponent_free(encaps); /* Don't need this anymore. */
if (serialized_request == NULL) return;
- request_message_text = malloc(strlen(serialized_request) + SIZ);
+ reqsize = strlen(serialized_request) + SIZ;
+ request_message_text = malloc(reqsize);
if (request_message_text != NULL) {
- sprintf(request_message_text,
+ snprintf(request_message_text, reqsize,
"Content-type: text/calendar\r\n\r\n%s\r\n",
serialized_request
);
"",
summary_string, /* Use summary for subject */
NULL,
- request_message_text);
+ request_message_text,
+ NULL);
if (msg != NULL) {
- valid = validate_recipients(attendees_string);
- CtdlSubmitMsg(msg, valid, "");
+ valid = validate_recipients(attendees_string, NULL, 0);
+ CtdlSubmitMsg(msg, valid, "", QP_EADDR);
CtdlFreeMessage(msg);
free_recipients(valid);
}
icalproperty *organizer = NULL;
char organizer_string[SIZ];
- lprintf(CTDL_DEBUG, "ical_saving_vevent() has been called!\n");
+ CtdlLogPrintf(CTDL_DEBUG, "ical_saving_vevent() has been called!\n");
/* Don't send out invitations unless the client wants us to. */
if (CIT_ICAL->server_generated_invitations == 0) {
* 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 ( (strcasecmp(cbtype, "text/calendar"))
+ && (strcasecmp(cbtype, "application/ics")) ) {
return;
}
}
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! */
if (msg->cm_format_type != 4) {
- lprintf(CTDL_DEBUG, "Rejecting non-RFC822 message\n");
+ CtdlLogPrintf(CTDL_DEBUG, "Rejecting non-RFC822 message\n");
return(1); /* You tried to save a non-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);
- lprintf(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);
}
icalcomponent *cal;
/* We're only interested in calendar items here. */
- if (strcasecmp(cbtype, "text/calendar")) {
+ if ( (strcasecmp(cbtype, "text/calendar"))
+ && (strcasecmp(cbtype, "application/ics")) ) {
return;
}
* ical_obj_beforesave() sees it there, it'll set the Exclusive msgid
* to that string.
*/
- if (!strcasecmp(cbtype, "text/calendar")) {
+ if ( (!strcasecmp(cbtype, "text/calendar"))
+ || (!strcasecmp(cbtype, "application/ics")) ) {
cal = icalcomponent_new_from_string(content);
if (cal != NULL) {
ical_saving_vevent(cal);
/*
- * 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.
*/
}
-#endif /* CITADEL_WITH_CALENDAR_SERVICE */
+
+void serv_calendar_destroy(void)
+{
+ icaltimezone_free_builtin_timezones();
+}
/*
* Register this module with the Citadel server.
*/
CTDL_MODULE_INIT(calendar)
{
-#ifdef CITADEL_WITH_CALENDAR_SERVICE
- CtdlRegisterMessageHook(ical_obj_beforesave, EVT_BEFORESAVE);
- CtdlRegisterMessageHook(ical_obj_aftersave, EVT_AFTERSAVE);
- CtdlRegisterSessionHook(ical_create_room, EVT_LOGIN);
- CtdlRegisterProtoHook(cmd_ical, "ICAL", "Citadel iCal commands");
- CtdlRegisterSessionHook(ical_session_startup, EVT_START);
- CtdlRegisterSessionHook(ical_session_shutdown, EVT_STOP);
- CtdlRegisterFixedOutputHook("text/calendar", ical_fixed_output);
-#endif
-
+ if (!threading)
+ {
+ CtdlRegisterMessageHook(ical_obj_beforesave, EVT_BEFORESAVE);
+ CtdlRegisterMessageHook(ical_obj_aftersave, EVT_AFTERSAVE);
+ CtdlRegisterSessionHook(ical_create_room, EVT_LOGIN);
+ CtdlRegisterProtoHook(cmd_ical, "ICAL", "Citadel iCal commands");
+ CtdlRegisterSessionHook(ical_session_startup, EVT_START);
+ CtdlRegisterSessionHook(ical_session_shutdown, EVT_STOP);
+ CtdlRegisterFixedOutputHook("text/calendar", ical_fixed_output);
+ CtdlRegisterFixedOutputHook("application/ics", ical_fixed_output);
+ CtdlRegisterCleanupHook(serv_calendar_destroy);
+ }
+
/* return our Subversion id for the Log */
return "$Id$";
}
-
-
-void serv_calendar_destroy(void)
-{
-#ifdef CITADEL_WITH_CALENDAR_SERVICE
- icaltimezone_free_builtin_timezones();
-#endif
-}