* Finished the code to accept incoming calendar REPLY messages and
authorArt Cancro <ajc@citadel.org>
Mon, 9 Dec 2002 06:07:30 +0000 (06:07 +0000)
committerArt Cancro <ajc@citadel.org>
Mon, 9 Dec 2002 06:07:30 +0000 (06:07 +0000)
  merge/save the updated event in the user's calendar.

citadel/ChangeLog
citadel/docs/sysop.txt
citadel/messages/goodbye
citadel/messages/hello
citadel/messages/newuser
citadel/msgbase.c
citadel/serv_calendar.c
citadel/serv_calendar.h

index 8ecd5d16a74ccdf0103ff58d2b3d27729bd38f7c..ab3f2aa31bd4772d4a2e02382fd8f35dc5788ec5 100644 (file)
@@ -1,4 +1,8 @@
  $Log$
+ Revision 601.86  2002/12/09 06:07:29  ajc
+ * Finished the code to accept incoming calendar REPLY messages and
+   merge/save the updated event in the user's calendar.
+
  Revision 601.85  2002/12/08 06:01:48  ajc
  * More work on the reply handler.  Wrote functions to locate the message
    containing the invitation being replied to.  Just need to write the
@@ -4292,4 +4296,3 @@ Sat Jul 11 00:20:48 EDT 1998 Nathan Bryant <bryant@cs.usm.maine.edu>
 
 Fri Jul 10 1998 Art Cancro <ajc@uncensored.citadel.org>
        * Initial CVS import
-
index 525ff3c4b907f6de92536878a948b95f9af5057f..6403c13d395b505e1c29ed3e6664c17288da2211 100644 (file)
@@ -262,6 +262,8 @@ files that will be automatically substituted with other strings.  They are:
  ^usernum     = The user number of the user reading the help file
  ^sysadm      = The name of the system administraor (i.e., you)
  ^variantname = The name of the BBS software you're running
+ ^bbsdir      = The directory on the host system in which you have
+                installed the Citadel system.
  
    So, for example, you could create a help file which looked like:
  
index 654807543b804c49753d1e91266c519b8034158d..c239f37a730fa2f29122ad56014a1ff4228a1f7c 100644 (file)
@@ -1,7 +1,7 @@
  
-  < this logoff banner resides in ./messages/goodbye >
+  < this logoff banner resides in ^bbsdir/messages/goodbye >
  
- Thanks for calling ^humannode - please call again soon!
+ Thanks for visiting ^humannode - please come back soon!
  
  Also be sure to visit UNCENSORED! BBS at uncensored.citadel.org
 
index 77444f1fdd65f11e9353211b9ea22f01da87bce6..f7643dd47f77826f223b08ad4d22ac5952ffd642 100644 (file)
@@ -1,3 +1,5 @@
-  
- < this logon banner resides in ./messages/hello >
  
+ Welcome to ^humannode!
+ This logon banner resides in ^bbsdir/messages/hello -- please customize it for your site.
+  
index 6dfecc8c764366046e11ed8f0d5c0a17b1566a2a..5bf66db4a5d4f1479cfd7cc6edb8d74596b2982d 100644 (file)
@@ -1,3 +1,3 @@
  
- < this new user policy resides in ./messages/newuser > 
+ < this new user policy resides in ^bbsdir/messages/newuser > 
  
index 2c0bd0f507f7959397d01adf90b30926941bea63..e11fb12b1ce7f6a526cd8c8bfa2bc4c9000241aa 100644 (file)
@@ -604,6 +604,7 @@ void do_help_subst(char *buffer)
        help_subst(buffer, "^variantname", CITADEL);
        snprintf(buf2, sizeof buf2, "%d", config.c_maxsessions);
        help_subst(buffer, "^maxsessions", buf2);
+       help_subst(buffer, "^bbsdir", BBSDIR);
 }
 
 
index b175fd9195d21f0bea7124cdda89ef8ef35c1d48..4e87415402e5ce2034f19803dc45c420cc56061a 100644 (file)
@@ -41,6 +41,8 @@ struct ical_respond_data {
        icalcomponent *cal;
 };
 
+/* Session-local data for calendaring. */
+long SYM_CIT_ICAL;
 
 /*
  * Write a calendar object into the specified user's calendar room.
@@ -413,6 +415,91 @@ void ical_locate_original_event(char *name, char *filename, char *partnum, char
 }
 
 
+/*
+ * Merge updated attendee information from a REPLY into an existing event.
+ */
+void ical_merge_attendee_reply(icalcomponent *event, icalcomponent *reply) {
+       icalcomponent *c;
+       icalproperty *e_attendee, *r_attendee;
+
+       /* First things first.  If we're not looking at a VEVENT component,
+        * recurse through subcomponents until we find one.
+        */
+       if (icalcomponent_isa(event) != ICAL_VEVENT_COMPONENT) {
+               for (c = icalcomponent_get_first_component(event, ICAL_VEVENT_COMPONENT);
+                   c != NULL;
+                   c = icalcomponent_get_next_component(event, ICAL_VEVENT_COMPONENT) ) {
+                       ical_merge_attendee_reply(c, reply);
+               }
+               return;
+       }
+
+       /* Now do the same thing with the reply.
+        */
+       if (icalcomponent_isa(reply) != ICAL_VEVENT_COMPONENT) {
+               for (c = icalcomponent_get_first_component(reply, ICAL_VEVENT_COMPONENT);
+                   c != NULL;
+                   c = icalcomponent_get_next_component(reply, ICAL_VEVENT_COMPONENT) ) {
+                       ical_merge_attendee_reply(event, c);
+               }
+               return;
+       }
+
+       /* Clone the reply, because we're going to rip its guts out. */
+       reply = icalcomponent_new_clone(reply);
+
+       /* At this point we're looking at the correct subcomponents.
+        * Iterate through the attendees looking for a match.
+        */
+STARTOVER:
+       for (e_attendee = icalcomponent_get_first_property(event, ICAL_ATTENDEE_PROPERTY);
+           e_attendee != NULL;
+           e_attendee = icalcomponent_get_next_property(event, ICAL_ATTENDEE_PROPERTY)) {
+
+               for (r_attendee = icalcomponent_get_first_property(reply, ICAL_ATTENDEE_PROPERTY);
+                   r_attendee != NULL;
+                   r_attendee = icalcomponent_get_next_property(reply, ICAL_ATTENDEE_PROPERTY)) {
+
+                       /* Check to see if these two attendees match...
+                        */
+                       if (!strcasecmp(
+                          icalproperty_get_attendee(e_attendee),
+                          icalproperty_get_attendee(r_attendee)
+                       )) {
+                               /* ...and if they do, remove the attendee from the event
+                                * and replace it with the attendee from the reply.  (The
+                                * reply's copy will have the same address, but an updated
+                                * status.)
+                                */
+                               TRACE;
+                               icalcomponent_remove_property(event, e_attendee);
+                               TRACE;
+                               icalproperty_free(e_attendee);
+                               TRACE;
+                               icalcomponent_remove_property(reply, r_attendee);
+                               TRACE;
+                               icalcomponent_add_property(event, r_attendee);
+                               TRACE;
+
+                               /* Since we diddled both sets of attendees, we have to start
+                                * the iteration over again.  This will not create an infinite
+                                * loop because we removed the attendee from the reply.  (That's
+                                * why we cloned the reply, and that's what we mean by "ripping
+                                * its guts out.")
+                                */
+                               goto STARTOVER;
+                       }
+       
+               }
+       }
+
+       /* Free the *clone* of the reply. */
+       icalcomponent_free(reply);
+}
+
+
+
+
 /*
  * Handle an incoming RSVP (object with method==ICAL_METHOD_REPLY) for a
  * calendar event.  The object has already been deserialized for us; all
@@ -430,6 +517,9 @@ int ical_update_my_calendar_with_reply(icalcomponent *cal) {
        struct CtdlMessage *msg;
        struct original_event_container oec;
        icalcomponent *original_event;
+       char *serialized_event = NULL;
+       char roomname[ROOMNAMELEN];
+       char *message_text = NULL;
 
        /* Figure out just what event it is we're dealing with */
        strcpy(uid, "--==<< InVaLiD uId >>==--");
@@ -487,14 +577,42 @@ int ical_update_my_calendar_with_reply(icalcomponent *cal) {
        original_event = oec.c;
        if (original_event == NULL) {
                lprintf(3, "ERROR: Original_component is NULL.\n");
-               return(1);
+               return(2);
        }
 
-       /* FIXME finish this */
-       /* merge "cal" into "original_event" */
-       /* reserialize "original_event" and save to disk */
+       /* Merge the attendee's updated status into the event */
+       ical_merge_attendee_reply(original_event, cal);
 
-       icalcomponent_free(original_event);
+       /* Serialize it */
+       serialized_event = strdoop(icalcomponent_as_ical_string(original_event));
+       icalcomponent_free(original_event);     /* Don't need this anymore. */
+       if (serialized_event == NULL) return(2);
+
+       MailboxName(roomname, sizeof roomname, &CC->usersupp, USERCALENDARROOM);
+
+       message_text = mallok(strlen(serialized_event) + SIZ);
+       if (message_text != NULL) {
+               sprintf(message_text,
+                       "Content-type: text/calendar\r\n\r\n%s\r\n",
+                       serialized_event
+               );
+
+               msg = CtdlMakeMessage(&CC->usersupp,
+                       "",                     /* No recipient */
+                       roomname,
+                       0, FMT_RFC822,
+                       "",
+                       "",             /* no subject */
+                       message_text);
+       
+               if (msg != NULL) {
+                       CIT_ICAL->avoid_sending_invitations = 1;
+                       CtdlSubmitMsg(msg, NULL, roomname);
+                       CtdlFreeMessage(msg);
+                       CIT_ICAL->avoid_sending_invitations = 0;
+               }
+       }
+       phree(serialized_event);
        return(0);
 }
 
@@ -569,8 +687,8 @@ void ical_handle_rsvp(long msgnum, char *partnum, char *action) {
 
                /* Now that we've processed this message, we don't need it
                 * anymore.  So delete it.  FIXME uncomment this when ready!
-               CtdlDeleteMessages(CC->quickroom.QRname, msgnum, "");
                 */
+               CtdlDeleteMessages(CC->quickroom.QRname, msgnum, "");
 
                /* Free the memory we allocated and return a response. */
                icalcomponent_free(ird.cal);
@@ -1043,6 +1161,11 @@ void ical_saving_vevent(icalcomponent *cal) {
        icalproperty *organizer = NULL;
        char organizer_string[SIZ];
 
+       /* Don't send out invitations if we've been asked not to. */
+       if (CIT_ICAL->avoid_sending_invitations) {
+               return;
+       }
+
        strcpy(organizer_string, "");
        /*
         * The VEVENT subcomponent is the one we're interested in.
@@ -1263,6 +1386,11 @@ int ical_obj_aftersave(struct CtdlMessage *msg)
 }
 
 
+void ical_session_startup(void) {
+       CtdlAllocUserData(SYM_CIT_ICAL, sizeof(struct cit_ical));
+}
+
+
 #endif /* HAVE_ICAL_H */
 
 /*
@@ -1275,6 +1403,7 @@ char *Dynamic_Module_Init(void)
        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);
 #endif
        return "$Id$";
 }
index 059ba2d0d66cff28a07d816c86dd1d65fe68a137..39f4e6d63c1cf33a7cbd2fa82b649c72e5f4afa3 100644 (file)
@@ -5,5 +5,10 @@
  *
  */
 
+extern long SYM_CIT_ICAL;
 
-/* Hrm, we don't have anything to put here yet... */
+struct cit_ical {
+        int avoid_sending_invitations;
+};
+
+#define CIT_ICAL ((struct cit_ical *)CtdlGetUserData(SYM_CIT_ICAL))