From 158e8958500476d1115c7b70f6c81a87bb0ade47 Mon Sep 17 00:00:00 2001 From: Wilfried Goesgens Date: Wed, 25 Sep 2013 00:37:08 +0200 Subject: [PATCH] Convert CtdlMessages to respect cm_lengths[] - move application specific code during message saving behind abstract handlers - IGNET spoorling - SMTP Spooling - ExtNotify Spooling - add new Message Hook: EVT_AFTERUSRMBOXSAVE - Put the volatile message ID to the message struct earlier --- citadel/event_client.h | 2 +- citadel/include/ctdl_module.h | 7 +- citadel/internet_addressing.c | 18 +- citadel/internet_addressing.h | 27 +- citadel/journaling.c | 8 +- citadel/journaling.h | 4 +- citadel/modules/blog/serv_blog.c | 2 +- citadel/modules/calendar/serv_calendar.c | 12 +- citadel/modules/clamav/serv_virus.c | 2 +- citadel/modules/ctdlproto/serv_messages.c | 8 +- citadel/modules/extnotify/extnotify_main.c | 44 ++ citadel/modules/imap/imap_acl.c | 2 +- citadel/modules/inetcfg/serv_inetcfg.c | 2 +- citadel/modules/network/serv_netmail.c | 6 +- citadel/modules/network/serv_netspool.c | 2 +- citadel/modules/network/serv_network.c | 78 +++- citadel/modules/notes/serv_notes.c | 2 +- citadel/modules/rssclient/rss_atom_parser.h | 2 +- citadel/modules/sieve/serv_sieve.c | 2 +- citadel/modules/smtp/serv_smtp.c | 6 +- citadel/modules/smtp/serv_smtpeventclient.c | 3 +- citadel/modules/smtp/serv_smtpqueue.c | 69 +++- citadel/modules/smtp/smtp_clienthandlers.h | 1 + citadel/modules/smtp/smtp_util.c | 2 +- citadel/modules/spam/serv_spam.c | 2 +- citadel/modules/vcard/serv_vcard.c | 6 +- citadel/modules/wiki/serv_wiki.c | 2 +- citadel/msgbase.c | 434 ++++++++------------ citadel/msgbase.h | 26 +- citadel/serv_extensions.c | 10 +- citadel/serv_extensions.h | 2 +- citadel/server.h | 24 ++ citadel/user_ops.c | 2 +- 33 files changed, 476 insertions(+), 343 deletions(-) diff --git a/citadel/event_client.h b/citadel/event_client.h index 99d4259f6..e12397927 100644 --- a/citadel/event_client.h +++ b/citadel/event_client.h @@ -204,7 +204,7 @@ struct AsyncIO { /* Saving / loading a message async from / to disk */ ReadAsyncMsg *ReadMsg; struct CtdlMessage *AsyncMsg; - struct recptypes *AsyncRcp; + recptypes *AsyncRcp; /* Context specific data; Hint: put AsyncIO in there */ void *Data; /* application specific data */ diff --git a/citadel/include/ctdl_module.h b/citadel/include/ctdl_module.h index 8950a47ed..ca447f595 100644 --- a/citadel/include/ctdl_module.h +++ b/citadel/include/ctdl_module.h @@ -134,10 +134,10 @@ void CtdlUnregisterUserHook(void (*fcn_ptr)(struct ctdluser *), int EventType); void CtdlRegisterXmsgHook(int (*fcn_ptr)(char *, char *, char *, char *), int order); void CtdlUnregisterXmsgHook(int (*fcn_ptr)(char *, char *, char *, char *), int order); -void CtdlRegisterMessageHook(int (*handler)(struct CtdlMessage *), - int EventType); -void CtdlUnregisterMessageHook(int (*handler)(struct CtdlMessage *), +void CtdlRegisterMessageHook(int (*handler)(struct CtdlMessage *, recptypes*), int EventType); +void CtdlUnregisterMessageHook(int (*handler)(struct CtdlMessage *, recptypes *), + int EventType); void CtdlRegisterNetprocHook(int (*handler)(struct CtdlMessage *, char *) ); void CtdlUnregisterNetprocHook(int (*handler)(struct CtdlMessage *, char *) ); @@ -537,4 +537,5 @@ void CtdlUserLogout(void); long CtdlLocateMessageByEuid(char *euid, struct ctdlroom *qrbuf); + #endif /* CTDL_MODULE_H */ diff --git a/citadel/internet_addressing.c b/citadel/internet_addressing.c index bc60368e6..507347307 100644 --- a/citadel/internet_addressing.c +++ b/citadel/internet_addressing.c @@ -331,7 +331,7 @@ int CtdlHostAlias(char *fqdn) { */ int CtdlIsMe(char *addr, int addr_buf_len) { - struct recptypes *recp; + recptypes *recp; int i; recp = validate_recipients(addr, NULL, 0); @@ -531,11 +531,11 @@ int alias(char *name) * * Caller needs to free the result using free_recipients() */ -struct recptypes *validate_recipients(const char *supplied_recipients, - const char *RemoteIdentifier, - int Flags) { +recptypes *validate_recipients(const char *supplied_recipients, + const char *RemoteIdentifier, + int Flags) { struct CitContext *CCC = CC; - struct recptypes *ret; + recptypes *ret; char *recipients = NULL; char *org_recp; char this_recp[256]; @@ -554,11 +554,11 @@ struct recptypes *validate_recipients(const char *supplied_recipients, int in_quotes = 0; /* Initialize */ - ret = (struct recptypes *) malloc(sizeof(struct recptypes)); + ret = (recptypes *) malloc(sizeof(recptypes)); if (ret == NULL) return(NULL); /* Set all strings to null and numeric values to zero */ - memset(ret, 0, sizeof(struct recptypes)); + memset(ret, 0, sizeof(recptypes)); if (supplied_recipients == NULL) { recipients = strdup(""); @@ -785,9 +785,9 @@ struct recptypes *validate_recipients(const char *supplied_recipients, /* - * Destructor for struct recptypes + * Destructor for recptypes */ -void free_recipients(struct recptypes *valid) { +void free_recipients(recptypes *valid) { if (valid == NULL) { return; diff --git a/citadel/internet_addressing.h b/citadel/internet_addressing.h index 74e581883..87d35b923 100644 --- a/citadel/internet_addressing.h +++ b/citadel/internet_addressing.h @@ -1,5 +1,6 @@ #include "server.h" +#include "ctdl_module.h" struct internet_address_list { struct internet_address_list *next; @@ -8,33 +9,12 @@ struct internet_address_list { char ial_name[SIZ]; }; -/* Data structure returned by validate_recipients() */ -struct recptypes { - int recptypes_magic; - int num_local; - int num_internet; - int num_ignet; - int num_room; - int num_error; - char *errormsg; - char *recp_local; - char *recp_internet; - char *recp_ignet; - char *recp_room; - char *recp_orgroom; - char *display_recp; - char *bounce_to; - char *envelope_from; - char *sending_room; -}; - -#define RECPTYPES_MAGIC 0xfeeb -struct recptypes *validate_recipients(const char *recipients, +recptypes *validate_recipients(const char *recipients, const char *RemoteIdentifier, int Flags); -void free_recipients(struct recptypes *); +void free_recipients(recptypes *); int fuzzy_match(struct ctdluser *us, char *matchstring); @@ -53,6 +33,7 @@ int CtdlDirectoryLookup(char *target, char *internet_addr, size_t targbuflen); struct CtdlMessage *convert_internet_message(char *rfc822); struct CtdlMessage *convert_internet_message_buf(StrBuf **rfc822); +int CtdlIsMe(char *addr, int addr_buf_len); int CtdlHostAlias(char *fqdn); char *harvest_collected_addresses(struct CtdlMessage *msg); diff --git a/citadel/journaling.c b/citadel/journaling.c index 3dae10749..eb9e378e7 100644 --- a/citadel/journaling.c +++ b/citadel/journaling.c @@ -20,7 +20,7 @@ struct jnlq *jnlq = NULL; /* journal queue */ */ void JournalBackgroundSubmit(struct CtdlMessage *msg, StrBuf *saved_rfc822_version, - struct recptypes *recps) { + recptypes *recps) { struct jnlq *jptr = NULL; @@ -36,7 +36,7 @@ void JournalBackgroundSubmit(struct CtdlMessage *msg, return; } memset(jptr, 0, sizeof(struct jnlq)); - if (recps != NULL) memcpy(&jptr->recps, recps, sizeof(struct recptypes)); + if (recps != NULL) memcpy(&jptr->recps, recps, sizeof(recptypes)); if (!CM_IsEmpty(msg, eAuthor)) jptr->from = strdup(msg->cm_fields[eAuthor]); if (!CM_IsEmpty(msg, eNodeName)) jptr->node = strdup(msg->cm_fields[eNodeName]); if (!CM_IsEmpty(msg, erFc822Addr)) jptr->rfca = strdup(msg->cm_fields[erFc822Addr]); @@ -88,7 +88,7 @@ void local_to_inetemail(char *inetemail, char *localuser, size_t inetemail_len) void JournalRunQueueMsg(struct jnlq *jmsg) { struct CtdlMessage *journal_msg = NULL; - struct recptypes *journal_recps = NULL; + recptypes *journal_recps = NULL; StrBuf *message_text = NULL; char mime_boundary[256]; long mblen; @@ -128,7 +128,7 @@ void JournalRunQueueMsg(struct jnlq *jmsg) { "--Citadel-Journal-%08lx-%04x--", time(NULL), ++seq); rfc822len = strlen(jmsg->rfc822); - message_text = NewStrBufPlain(NULL, rfc822len + sizeof(struct recptypes) + 1024); + message_text = NewStrBufPlain(NULL, rfc822len + sizeof(recptypes) + 1024); /* * Here is where we begin to compose the journalized message. diff --git a/citadel/journaling.h b/citadel/journaling.h index 4a66781ae..74c79816a 100644 --- a/citadel/journaling.h +++ b/citadel/journaling.h @@ -1,6 +1,6 @@ struct jnlq { struct jnlq *next; - struct recptypes recps; + recptypes recps; char *from; char *node; char *rfca; @@ -11,6 +11,6 @@ struct jnlq { void JournalBackgroundSubmit(struct CtdlMessage *msg, StrBuf *saved_rfc822_version, - struct recptypes *recps); + recptypes *recps); void JournalRunQueueMsg(struct jnlq *jmsg); void JournalRunQueue(void); diff --git a/citadel/modules/blog/serv_blog.c b/citadel/modules/blog/serv_blog.c index 891c2cccf..0402e0190 100644 --- a/citadel/modules/blog/serv_blog.c +++ b/citadel/modules/blog/serv_blog.c @@ -62,7 +62,7 @@ * Pre-save hook for saving a message in a blog room. * (Do we want to only do this for top-level messages?) */ -int blog_upload_beforesave(struct CtdlMessage *msg) { +int blog_upload_beforesave(struct CtdlMessage *msg, recptypes *recp) { /* Only run this hook for blog rooms */ if (CC->room.QRdefaultview != VIEW_BLOG) { diff --git a/citadel/modules/calendar/serv_calendar.c b/citadel/modules/calendar/serv_calendar.c index 1acd28251..8d3fe42cb 100644 --- a/citadel/modules/calendar/serv_calendar.c +++ b/citadel/modules/calendar/serv_calendar.c @@ -185,13 +185,13 @@ void ical_send_a_reply(icalcomponent *request, char *action) { icalproperty *summary = NULL; char summary_string[SIZ]; icalproperty *me_attend = NULL; - struct recptypes *recp = NULL; + recptypes *recp = NULL; icalparameter *partstat = NULL; char *serialized_reply = NULL; char *reply_message_text = NULL; const char *ch; struct CtdlMessage *msg = NULL; - struct recptypes *valid = NULL; + recptypes *valid = NULL; *organizer_string = '\0'; strcpy(summary_string, "Calendar item"); @@ -1439,7 +1439,7 @@ void ical_freebusy(char *who) { icalcomponent *encaps = NULL; icalcomponent *fb = NULL; int found_user = (-1); - struct recptypes *recp = NULL; + recptypes *recp = NULL; char buf[256]; char host[256]; char type[256]; @@ -1999,7 +1999,7 @@ void ical_send_out_invitations(icalcomponent *top_level_cal, icalcomponent *cal) icalcomponent *encaps = NULL; char *request_message_text = NULL; struct CtdlMessage *msg = NULL; - struct recptypes *valid = NULL; + recptypes *valid = NULL; char attendees_string[SIZ]; int num_attendees = 0; char this_attendee[256]; @@ -2393,7 +2393,7 @@ void ical_obj_beforesave_backend(char *name, char *filename, char *partnum, * 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) +int ical_obj_beforesave(struct CtdlMessage *msg, recptypes *recp) { /* First determine if this is a calendar or tasks room */ if ( (CC->room.QRdefaultview != VIEW_CALENDAR) @@ -2461,7 +2461,7 @@ void ical_obj_aftersave_backend(char *name, char *filename, char *partnum, * (This will start back end tasks such as automatic generation of invitations, * if such actions are appropriate.) */ -int ical_obj_aftersave(struct CtdlMessage *msg) +int ical_obj_aftersave(struct CtdlMessage *msg, recptypes *recp) { char roomname[ROOMNAMELEN]; diff --git a/citadel/modules/clamav/serv_virus.c b/citadel/modules/clamav/serv_virus.c index ae24461aa..81f53e13a 100644 --- a/citadel/modules/clamav/serv_virus.c +++ b/citadel/modules/clamav/serv_virus.c @@ -70,7 +70,7 @@ /* * Connect to the clamd server and scan a message. */ -int clamd(struct CtdlMessage *msg) { +int clamd(struct CtdlMessage *msg, recptypes *recp) { int sock = (-1); int streamsock = (-1); char clamhosts[SIZ]; diff --git a/citadel/modules/ctdlproto/serv_messages.c b/citadel/modules/ctdlproto/serv_messages.c index 08aaf566f..f7ac4575e 100644 --- a/citadel/modules/ctdlproto/serv_messages.c +++ b/citadel/modules/ctdlproto/serv_messages.c @@ -332,10 +332,10 @@ void cmd_ent0(char *entargs) int anonymous = 0; char errmsg[SIZ]; int err = 0; - struct recptypes *valid = NULL; - struct recptypes *valid_to = NULL; - struct recptypes *valid_cc = NULL; - struct recptypes *valid_bcc = NULL; + recptypes *valid = NULL; + recptypes *valid_to = NULL; + recptypes *valid_cc = NULL; + recptypes *valid_bcc = NULL; char subject[SIZ]; int subject_required = 0; int do_confirm = 0; diff --git a/citadel/modules/extnotify/extnotify_main.c b/citadel/modules/extnotify/extnotify_main.c index ef253c876..46c9ab8ea 100644 --- a/citadel/modules/extnotify/extnotify_main.c +++ b/citadel/modules/extnotify/extnotify_main.c @@ -465,12 +465,56 @@ void create_extnotify_queue(void) { } } +int extnotify_after_mbox_save(struct CtdlMessage *msg, + recptypes *recps) + +{ + /* If this is private, local mail, make a copy in the + * recipient's mailbox and bump the reference count. + */ + if (!IsEmptyStr(config.c_funambol_host) || !IsEmptyStr(config.c_pager_program)) + { + /* Generate a instruction message for the Funambol notification + * server, in the same style as the SMTP queue + */ + StrBuf *instr; + struct CtdlMessage *imsg; + + instr = NewStrBufPlain(NULL, 1024); + StrBufPrintf(instr, + "Content-type: "SPOOLMIME"\n" + "\n" + "msgid|%s\n" + "submitted|%ld\n" + "bounceto|%s\n", + msg->cm_fields[eVltMsgNum], + (long)time(NULL), //todo: time() is expensive! + recps->bounce_to + ); + + imsg = malloc(sizeof(struct CtdlMessage)); + memset(imsg, 0, sizeof(struct CtdlMessage)); + imsg->cm_magic = CTDLMESSAGE_MAGIC; + imsg->cm_anon_type = MES_NORMAL; + imsg->cm_format_type = FMT_RFC822; + CM_SetField(imsg, eMsgSubject, HKEY("QMSG")); + CM_SetField(imsg, eAuthor, HKEY("Citadel")); + CM_SetField(imsg, eJournal, HKEY("do not journal")); + CM_SetAsFieldSB(imsg, eMesageText, &instr); + CM_SetField(imsg, eExtnotify, recps->recp_local, strlen(recps->recp_local)); + CtdlSubmitMsg(imsg, NULL, FNBL_QUEUE_ROOM, 0); + CM_Free(imsg); + } + return 0; +} CTDL_MODULE_INIT(extnotify) { if (!threading) { create_extnotify_queue(); + CtdlRegisterMessageHook(extnotify_after_mbox_save, EVT_AFTERUSRMBOXSAVE); + CtdlRegisterSessionHook(do_extnotify_queue, EVT_TIMER, PRIO_SEND + 10); } /* return our module name for the log */ diff --git a/citadel/modules/imap/imap_acl.c b/citadel/modules/imap/imap_acl.c index 0ca96dfc8..b1c1f0fe8 100644 --- a/citadel/modules/imap/imap_acl.c +++ b/citadel/modules/imap/imap_acl.c @@ -221,7 +221,7 @@ void imap_listrights(int num_parms, ConstStr *Params) { char savedroom[ROOMNAMELEN]; int msgs, new; int ret; - struct recptypes *valid; + recptypes *valid; struct ctdluser temp; if (num_parms != 4) { diff --git a/citadel/modules/inetcfg/serv_inetcfg.c b/citadel/modules/inetcfg/serv_inetcfg.c index 7c0bedaa1..c37dd24fb 100644 --- a/citadel/modules/inetcfg/serv_inetcfg.c +++ b/citadel/modules/inetcfg/serv_inetcfg.c @@ -85,7 +85,7 @@ void inetcfg_setTo(struct CtdlMessage *msg) { * This handler detects changes being made to the system's Internet * configuration. */ -int inetcfg_aftersave(struct CtdlMessage *msg) { +int inetcfg_aftersave(struct CtdlMessage *msg, recptypes *recp) { char *ptr; int linelen; diff --git a/citadel/modules/network/serv_netmail.c b/citadel/modules/network/serv_netmail.c index d71cbdbfb..b06da93f1 100644 --- a/citadel/modules/network/serv_netmail.c +++ b/citadel/modules/network/serv_netmail.c @@ -180,7 +180,7 @@ void network_deliver_digest(SpoolControl *sc) char *pbuf; struct CtdlMessage *msg = NULL; long msglen; - struct recptypes *valid; + recptypes *valid; char bounce_to[256]; if (sc->Users[listrecp] == NULL) @@ -354,7 +354,7 @@ void network_process_list(SpoolControl *sc, struct CtdlMessage *omsg, long *dele */ void network_deliver_list(struct CtdlMessage *msg, SpoolControl *sc, const char *RoomName) { - struct recptypes *valid; + recptypes *valid; char bounce_to[256]; /* Don't do this if there were no recipients! */ @@ -385,7 +385,7 @@ void network_process_participate(SpoolControl *sc, struct CtdlMessage *omsg, lon struct CtdlMessage *msg = NULL; int ok_to_participate = 0; StrBuf *Buf = NULL; - struct recptypes *valid; + recptypes *valid; /* * Process client-side list participations for this room diff --git a/citadel/modules/network/serv_netspool.c b/citadel/modules/network/serv_netspool.c index c75e682fb..5b90ef23d 100644 --- a/citadel/modules/network/serv_netspool.c +++ b/citadel/modules/network/serv_netspool.c @@ -420,7 +420,7 @@ void network_process_buffer(char *buffer, long size, HashList *working_ignetcfg, struct CtdlMessage *msg = NULL; long pos; int field; - struct recptypes *recp = NULL; + recptypes *recp = NULL; char target_room[ROOMNAMELEN]; struct ser_ret sermsg; char filename[PATH_MAX]; diff --git a/citadel/modules/network/serv_network.c b/citadel/modules/network/serv_network.c index 998a83df1..32bf49564 100644 --- a/citadel/modules/network/serv_network.c +++ b/citadel/modules/network/serv_network.c @@ -350,7 +350,7 @@ void network_bounce(struct CtdlMessage *msg, char *reason) char buf[SIZ]; char bouncesource[SIZ]; char recipient[SIZ]; - struct recptypes *valid = NULL; + recptypes *valid = NULL; char force_room[ROOMNAMELEN]; static int serialnum = 0; long len; @@ -589,6 +589,80 @@ void network_cleanup_function(void) } +int ignet_aftersave(struct CtdlMessage *msg, + recptypes *recps) /* recipients (if mail) */ +{ + /* For IGnet mail, we have to save a new copy into the spooler for + * each recipient, with the R and D fields set to the recipient and + * destination-node. This has two ugly side effects: all other + * recipients end up being unlisted in this recipient's copy of the + * message, and it has to deliver multiple messages to the same + * node. We'll revisit this again in a year or so when everyone has + * a network spool receiver that can handle the new style messages. + */ + if ((recps != NULL) && (recps->num_ignet > 0)) + { + char *recipient; + int rv = 0; + struct ser_ret smr; + FILE *network_fp = NULL; + char submit_filename[128]; + static int seqnum = 1; + int i; + char *hold_R, *hold_D, *RBuf, *DBuf; + long hrlen, hdlen, rblen, dblen, count, rlen; + CitContext *CCC = MyContext(); + + CM_GetAsField(msg, eRecipient, &hold_R, &hrlen);; + CM_GetAsField(msg, eDestination, &hold_D, &hdlen);; + + count = num_tokens(recps->recp_ignet, '|'); + rlen = strlen(recps->recp_ignet); + recipient = malloc(rlen + 1); + RBuf = malloc(rlen + 1); + DBuf = malloc(rlen + 1); + for (i=0; irecp_ignet, i, + '|', rlen + 1); + + rblen = extract_token(RBuf, recipient, 0, '@', rlen + 1); + dblen = extract_token(DBuf, recipient, 1, '@', rlen + 1); + + CM_SetAsField(msg, eRecipient, &RBuf, rblen);; + CM_SetAsField(msg, eDestination, &DBuf, dblen);; + CtdlSerializeMessage(&smr, msg); + if (smr.len > 0) { + snprintf(submit_filename, sizeof submit_filename, + "%s/netmail.%04lx.%04x.%04x", + ctdl_netin_dir, + (long) getpid(), + CCC->cs_pid, + ++seqnum); + + network_fp = fopen(submit_filename, "wb+"); + if (network_fp != NULL) { + rv = fwrite(smr.ser, smr.len, 1, network_fp); + if (rv == -1) { + MSG_syslog(LOG_EMERG, "CtdlSubmitMsg(): Couldn't write network spool file: %s\n", + strerror(errno)); + } + fclose(network_fp); + } + free(smr.ser); + } + CM_GetAsField(msg, eRecipient, &RBuf, &rblen);; + CM_GetAsField(msg, eDestination, &DBuf, &dblen);; + } + free(RBuf); + free(DBuf); + free(recipient); + CM_SetAsField(msg, eRecipient, &hold_R, hrlen); + CM_SetAsField(msg, eDestination, &hold_D, hdlen); + return 1; + } + return 0; +} + /* * Module entry point */ @@ -602,6 +676,8 @@ CTDL_MODULE_INIT(network) { if (!threading) { + CtdlRegisterMessageHook(ignet_aftersave, EVT_AFTERSAVE); + CtdlFillSystemContext(&networker_spool_CC, "CitNetSpool"); CtdlRegisterDebugFlagHook(HKEY("networkqueue"), SetNetQDebugEnabled, &NetQDebugEnabled); CtdlRegisterSessionHook(network_cleanup_function, EVT_STOP, PRIO_STOP + 30); diff --git a/citadel/modules/notes/serv_notes.c b/citadel/modules/notes/serv_notes.c index 9c1c944d9..839d5d537 100644 --- a/citadel/modules/notes/serv_notes.c +++ b/citadel/modules/notes/serv_notes.c @@ -80,7 +80,7 @@ void notes_extract_vnote(char *name, char *filename, char *partnum, char *disp, * and modern vNote format notes) and does its best to learn the subject (summary) * and EUID (uid) of the note for Citadel's own nefarious purposes. */ -int serv_notes_beforesave(struct CtdlMessage *msg) +int serv_notes_beforesave(struct CtdlMessage *msg, recptypes *recp) { char *p; int a, i; diff --git a/citadel/modules/rssclient/rss_atom_parser.h b/citadel/modules/rssclient/rss_atom_parser.h index ad0f8b2c4..da4c6161f 100644 --- a/citadel/modules/rssclient/rss_atom_parser.h +++ b/citadel/modules/rssclient/rss_atom_parser.h @@ -110,7 +110,7 @@ struct rss_aggregator { StrBuf *Key; rss_item *Item; - struct recptypes recp; + recptypes recp; HashPos *Pos; HashList *Messages; networker_save_message *ThisMsg; diff --git a/citadel/modules/sieve/serv_sieve.c b/citadel/modules/sieve/serv_sieve.c index ecdaafd78..daf067331 100644 --- a/citadel/modules/sieve/serv_sieve.c +++ b/citadel/modules/sieve/serv_sieve.c @@ -106,7 +106,7 @@ int ctdl_redirect(sieve2_context_t *s, void *my) { struct ctdl_sieve *cs = (struct ctdl_sieve *)my; struct CtdlMessage *msg = NULL; - struct recptypes *valid = NULL; + recptypes *valid = NULL; char recp[256]; safestrncpy(recp, sieve2_getvalue_string(s, "address"), sizeof recp); diff --git a/citadel/modules/smtp/serv_smtp.c b/citadel/modules/smtp/serv_smtp.c index 681e0c740..9ac94212a 100644 --- a/citadel/modules/smtp/serv_smtp.c +++ b/citadel/modules/smtp/serv_smtp.c @@ -668,7 +668,7 @@ void smtp_rcpt(long offset, long flags) { struct CitContext *CCC = CC; char message_to_spammer[SIZ]; - struct recptypes *valid = NULL; + recptypes *valid = NULL; citsmtp *sSMTP = SMTP; if (StrLength(sSMTP->from) == 0) { @@ -767,7 +767,7 @@ void smtp_data(long offset, long flags) struct CtdlMessage *msg = NULL; long msgnum = (-1L); char nowstamp[SIZ]; - struct recptypes *valid; + recptypes *valid; int scan_errors; int i; citsmtp *sSMTP = SMTP; @@ -896,7 +896,7 @@ void smtp_data(long offset, long flags) scan_errors = 0; } else { - scan_errors = PerformMessageHooks(msg, EVT_SMTPSCAN); + scan_errors = PerformMessageHooks(msg, valid, EVT_SMTPSCAN); } if (scan_errors > 0) { /* We don't want this message! */ diff --git a/citadel/modules/smtp/serv_smtpeventclient.c b/citadel/modules/smtp/serv_smtpeventclient.c index 47c1d605e..3be726e85 100644 --- a/citadel/modules/smtp/serv_smtpeventclient.c +++ b/citadel/modules/smtp/serv_smtpeventclient.c @@ -356,7 +356,7 @@ eNextState mx_connect_ip(AsyncIO *IO) SmtpOutMsg *Msg = IO->Data; SetSMTPState(IO, eSTMPconnecting); - EVS_syslog(LOG_DEBUG, "%s\n", __FUNCTION__); + EVS_syslog(LOG_DEBUG, "%s(%s)\n", __FUNCTION__, (Msg->IsRelay)? "Relay":"Remote"); IO->ConnectMe = Msg->pCurrRelay; Msg->State = eConnectMX; @@ -656,6 +656,7 @@ void smtp_try_one_queue_entry(OneQueItem *MyQItem, resolve_mx_records); } else { /* oh... via relay host */ + Msg->IsRelay = 1; if (Msg->pCurrRelay->IsIP) { SetSMTPState(&Msg->IO, eSTMPconnecting); QueueEventContext(&Msg->IO, diff --git a/citadel/modules/smtp/serv_smtpqueue.c b/citadel/modules/smtp/serv_smtpqueue.c index 99b9d0795..b2196a887 100644 --- a/citadel/modules/smtp/serv_smtpqueue.c +++ b/citadel/modules/smtp/serv_smtpqueue.c @@ -523,7 +523,7 @@ void smtpq_do_bounce(OneQueItem *MyQItem, StrBuf *OMsgTxt, ParsedURL *Relay) StrBuf *boundary; StrBuf *Msg = NULL; StrBuf *BounceMB; - struct recptypes *valid; + recptypes *valid; time_t now; HashPos *It; @@ -1205,6 +1205,70 @@ void cmd_smtp(char *argbuf) { } +int smtp_aftersave(struct CtdlMessage *msg, + recptypes *recps) +{ + /* For internet mail, generate delivery instructions. + * Yes, this is recursive. Deal with it. Infinite recursion does + * not happen because the delivery instructions message does not + * contain a recipient. + */ + if ((recps != NULL) && (recps->num_internet > 0)) { + struct CtdlMessage *imsg = NULL; + char recipient[SIZ]; + CitContext *CCC = MyContext(); + StrBuf *SpoolMsg = NewStrBuf(); + long nTokens; + int i; + + MSGM_syslog(LOG_DEBUG, "Generating delivery instructions\n"); + + StrBufPrintf(SpoolMsg, + "Content-type: "SPOOLMIME"\n" + "\n" + "msgid|%s\n" + "submitted|%ld\n" + "bounceto|%s\n", + msg->cm_fields[eVltMsgNum], + (long)time(NULL), + recps->bounce_to); + + if (recps->envelope_from != NULL) { + StrBufAppendBufPlain(SpoolMsg, HKEY("envelope_from|"), 0); + StrBufAppendBufPlain(SpoolMsg, recps->envelope_from, -1, 0); + StrBufAppendBufPlain(SpoolMsg, HKEY("\n"), 0); + } + if (recps->sending_room != NULL) { + StrBufAppendBufPlain(SpoolMsg, HKEY("source_room|"), 0); + StrBufAppendBufPlain(SpoolMsg, recps->sending_room, -1, 0); + StrBufAppendBufPlain(SpoolMsg, HKEY("\n"), 0); + } + + nTokens = num_tokens(recps->recp_internet, '|'); + for (i = 0; i < nTokens; i++) { + long len; + len = extract_token(recipient, recps->recp_internet, i, '|', sizeof recipient); + if (len > 0) { + StrBufAppendBufPlain(SpoolMsg, HKEY("remote|"), 0); + StrBufAppendBufPlain(SpoolMsg, recipient, len, 0); + StrBufAppendBufPlain(SpoolMsg, HKEY("|0||\n"), 0); + } + } + + imsg = malloc(sizeof(struct CtdlMessage)); + memset(imsg, 0, sizeof(struct CtdlMessage)); + imsg->cm_magic = CTDLMESSAGE_MAGIC; + imsg->cm_anon_type = MES_NORMAL; + imsg->cm_format_type = FMT_RFC822; + CM_SetField(imsg, eMsgSubject, HKEY("QMSG")); + CM_SetField(imsg, eAuthor, HKEY("Citadel")); + CM_SetField(imsg, eJournal, HKEY("do not journal")); + CM_SetAsFieldSB(imsg, eMesageText, &SpoolMsg); + CtdlSubmitMsg(imsg, NULL, SMTP_SPOOLOUT_ROOM, QP_EADDR); + CM_Free(imsg); + } + return 0; +} CTDL_MODULE_INIT(smtp_queu) { @@ -1224,8 +1288,7 @@ CTDL_MODULE_INIT(smtp_queu) if ((pstr != NULL) && (*pstr != '\0')) delay_msec = atol(pstr) * 1000; /* this many seconds. */ - - + CtdlRegisterMessageHook(smtp_aftersave, EVT_AFTERSAVE); CtdlFillSystemContext(&smtp_queue_CC, "SMTP_Send"); ActiveQItems = NewHash(1, lFlathash); diff --git a/citadel/modules/smtp/smtp_clienthandlers.h b/citadel/modules/smtp/smtp_clienthandlers.h index dedab4ba4..3e18261a2 100644 --- a/citadel/modules/smtp/smtp_clienthandlers.h +++ b/citadel/modules/smtp/smtp_clienthandlers.h @@ -70,6 +70,7 @@ typedef struct _stmp_out_msg { char mailfrom[1024]; long SendLogin; long Flags; + long IsRelay; } SmtpOutMsg; diff --git a/citadel/modules/smtp/smtp_util.c b/citadel/modules/smtp/smtp_util.c index dae60b6da..675001ea0 100644 --- a/citadel/modules/smtp/smtp_util.c +++ b/citadel/modules/smtp/smtp_util.c @@ -119,7 +119,7 @@ void smtp_do_bounce(char *instr, StrBuf *OMsgTxt) time_t submitted = 0L; struct CtdlMessage *bmsg = NULL; int give_up = 0; - struct recptypes *valid; + recptypes *valid; int successful_bounce = 0; static int seq = 0; StrBuf *BounceMB; diff --git a/citadel/modules/spam/serv_spam.c b/citadel/modules/spam/serv_spam.c index 77365b16c..f9a823d9e 100644 --- a/citadel/modules/spam/serv_spam.c +++ b/citadel/modules/spam/serv_spam.c @@ -70,7 +70,7 @@ /* * Connect to the SpamAssassin server and scan a message. */ -int spam_assassin(struct CtdlMessage *msg) { +int spam_assassin(struct CtdlMessage *msg, recptypes *recp) { int sock = (-1); char sahosts[SIZ]; int num_sahosts; diff --git a/citadel/modules/vcard/serv_vcard.c b/citadel/modules/vcard/serv_vcard.c index 393cf7210..3d62c83d0 100644 --- a/citadel/modules/vcard/serv_vcard.c +++ b/citadel/modules/vcard/serv_vcard.c @@ -329,7 +329,7 @@ void vcard_extract_vcard(char *name, char *filename, char *partnum, char *disp, * function accordingly (delete the user's existing vCard in the config room * and in the global address book). */ -int vcard_upload_beforesave(struct CtdlMessage *msg) { +int vcard_upload_beforesave(struct CtdlMessage *msg, recptypes *recp) { struct CitContext *CCC = CC; char *s; char buf[SIZ]; @@ -504,7 +504,7 @@ int vcard_upload_beforesave(struct CtdlMessage *msg) { * function accordingly (copy the vCard from the config room to the global * address book). */ -int vcard_upload_aftersave(struct CtdlMessage *msg) { +int vcard_upload_aftersave(struct CtdlMessage *msg, recptypes *recp) { struct CitContext *CCC = CC; char *ptr; int linelen; @@ -1172,7 +1172,7 @@ void check_get(void) { if (strncasecmp(cmdbuf, "GET ", 4)==0) { - struct recptypes *rcpt; + recptypes *rcpt; char *argbuf = &cmdbuf[4]; extract_token(internet_addr, argbuf, 0, '|', sizeof internet_addr); diff --git a/citadel/modules/wiki/serv_wiki.c b/citadel/modules/wiki/serv_wiki.c index 79a961f45..e68055d05 100644 --- a/citadel/modules/wiki/serv_wiki.c +++ b/citadel/modules/wiki/serv_wiki.c @@ -70,7 +70,7 @@ char *wwm = "9999999999.WikiWaybackMachine"; * Before allowing a wiki page save to execute, we have to perform version control. * This involves fetching the old version of the page if it exists. */ -int wiki_upload_beforesave(struct CtdlMessage *msg) { +int wiki_upload_beforesave(struct CtdlMessage *msg, recptypes *recp) { struct CitContext *CCC = CC; long old_msgnum = (-1L); struct CtdlMessage *old_msg = NULL; diff --git a/citadel/msgbase.c b/citadel/msgbase.c index d4a933e76..d9629700f 100644 --- a/citadel/msgbase.c +++ b/citadel/msgbase.c @@ -136,6 +136,7 @@ void CM_SetField(struct CtdlMessage *Msg, eMsgField which, const char *buf, long Msg->cm_fields[which] = malloc(length + 1); memcpy(Msg->cm_fields[which], buf, length); Msg->cm_fields[which][length] = '\0'; + Msg->cm_lengths[which] = length; } void CM_SetFieldLONG(struct CtdlMessage *Msg, eMsgField which, long lvalue) @@ -150,8 +151,11 @@ void CM_CutFieldAt(struct CtdlMessage *Msg, eMsgField WhichToCut, long maxlen) if (Msg->cm_fields[WhichToCut] == NULL) return; - if (strlen(Msg->cm_fields[WhichToCut]) > maxlen) + if (Msg->cm_lengths[WhichToCut] > maxlen) + { Msg->cm_fields[WhichToCut][maxlen] = '\0'; + Msg->cm_lengths[WhichToCut] = maxlen; + } } void CM_FlushField(struct CtdlMessage *Msg, eMsgField which) @@ -159,6 +163,7 @@ void CM_FlushField(struct CtdlMessage *Msg, eMsgField which) if (Msg->cm_fields[which] != NULL) free (Msg->cm_fields[which]); Msg->cm_fields[which] = NULL; + Msg->cm_lengths[which] = 0; } void CM_Flush(struct CtdlMessage *Msg) { @@ -181,13 +186,17 @@ void CM_CopyField(struct CtdlMessage *Msg, eMsgField WhichToPutTo, eMsgField Whi if (Msg->cm_fields[WhichtToCopy] != NULL) { - len = strlen(Msg->cm_fields[WhichtToCopy]); + len = Msg->cm_lengths[WhichtToCopy]; Msg->cm_fields[WhichToPutTo] = malloc(len + 1); memcpy(Msg->cm_fields[WhichToPutTo], Msg->cm_fields[WhichtToCopy], len); Msg->cm_fields[WhichToPutTo][len] = '\0'; + Msg->cm_lengths[WhichToPutTo] = len; } else + { Msg->cm_fields[WhichToPutTo] = NULL; + Msg->cm_lengths[WhichToPutTo] = 0; + } } @@ -198,7 +207,7 @@ void CM_PrependToField(struct CtdlMessage *Msg, eMsgField which, const char *buf long newmsgsize; char *new; - oldmsgsize = strlen(Msg->cm_fields[which]) + 1; + oldmsgsize = Msg->cm_lengths[which] + 1; newmsgsize = length + oldmsgsize; new = malloc(newmsgsize); @@ -206,11 +215,13 @@ void CM_PrependToField(struct CtdlMessage *Msg, eMsgField which, const char *buf memcpy(new + length, Msg->cm_fields[which], oldmsgsize); free(Msg->cm_fields[which]); Msg->cm_fields[which] = new; + Msg->cm_lengths[which] = newmsgsize - 1; } else { Msg->cm_fields[which] = malloc(length + 1); memcpy(Msg->cm_fields[which], buf, length); Msg->cm_fields[which][length] = '\0'; + Msg->cm_lengths[which] = length; } } @@ -221,6 +232,7 @@ void CM_SetAsField(struct CtdlMessage *Msg, eMsgField which, char **buf, long le Msg->cm_fields[which] = *buf; *buf = NULL; + Msg->cm_lengths[which] = length; } void CM_SetAsFieldSB(struct CtdlMessage *Msg, eMsgField which, StrBuf **buf) @@ -228,6 +240,7 @@ void CM_SetAsFieldSB(struct CtdlMessage *Msg, eMsgField which, StrBuf **buf) if (Msg->cm_fields[which] != NULL) free (Msg->cm_fields[which]); + Msg->cm_lengths[which] = StrLength(*buf); Msg->cm_fields[which] = SmashStrBuf(buf); } @@ -235,9 +248,10 @@ void CM_GetAsField(struct CtdlMessage *Msg, eMsgField which, char **ret, long *r { if (Msg->cm_fields[which] != NULL) { - *retlen = strlen(Msg->cm_fields[which]); + *retlen = Msg->cm_lengths[which]; *ret = Msg->cm_fields[which]; Msg->cm_fields[which] = NULL; + Msg->cm_lengths[which] = 0; } else { @@ -268,6 +282,7 @@ void CM_FreeContents(struct CtdlMessage *msg) for (i = 0; i < 256; ++i) if (msg->cm_fields[i] != NULL) { free(msg->cm_fields[i]); + msg->cm_lengths[i] = 0; } msg->cm_magic = 0; /* just in case */ @@ -289,12 +304,13 @@ void CM_Free(struct CtdlMessage *msg) int CM_DupField(eMsgField i, struct CtdlMessage *OrgMsg, struct CtdlMessage *NewMsg) { long len; - len = strlen(OrgMsg->cm_fields[i]); + len = OrgMsg->cm_lengths[i]; NewMsg->cm_fields[i] = malloc(len + 1); if (NewMsg->cm_fields[i] == NULL) return 0; memcpy(NewMsg->cm_fields[i], OrgMsg->cm_fields[i], len); NewMsg->cm_fields[i][len] = '\0'; + NewMsg->cm_lengths[i] = len; return 1; } @@ -353,8 +369,9 @@ int CtdlMsgCmp(struct CtdlMessage *msg, struct CtdlMessage *template) { if (IsEmptyStr(template->cm_fields[i])) continue; return 1; } - if (strcasecmp(msg->cm_fields[i], - template->cm_fields[i])) return 1; + if ((template->cm_lengths[i] != msg->cm_lengths[i]) || + (strcasecmp(msg->cm_fields[i], template->cm_fields[i]))) + return 1; } } @@ -1084,6 +1101,7 @@ struct CtdlMessage *CtdlFetchMessage(long msgnum, int with_body) char *upper_bound; cit_uint8_t ch; cit_uint8_t field_header; + eMsgField which; MSG_syslog(LOG_DEBUG, "CtdlFetchMessage(%ld, %d)\n", msgnum, with_body); dmsgtext = cdb_fetch(CDB_MSGMAIN, &msgnum, sizeof(long)); @@ -1123,8 +1141,9 @@ struct CtdlMessage *CtdlFetchMessage(long msgnum, int with_body) break; } field_header = *mptr++; + which = field_header; len = strlen(mptr); - CM_SetField(ret, field_header, mptr, len); + CM_SetField(ret, which, mptr, len); mptr += len + 1; /* advance to next field */ @@ -1149,7 +1168,7 @@ struct CtdlMessage *CtdlFetchMessage(long msgnum, int with_body) } /* Perform "before read" hooks (aborting if any return nonzero) */ - if (PerformMessageHooks(ret, EVT_BEFOREREAD) > 0) { + if (PerformMessageHooks(ret, NULL, EVT_BEFOREREAD) > 0) { CM_Free(ret); return NULL; } @@ -2438,6 +2457,7 @@ long send_message(struct CtdlMessage *msg) { struct ser_ret smr; int is_bigmsg = 0; char *holdM = NULL; + long oldMLen = 0; /* Get a new message number */ newmsgid = get_new_message_number(); @@ -2454,10 +2474,12 @@ long send_message(struct CtdlMessage *msg) { /* If the message is big, set its body aside for storage elsewhere */ if (!CM_IsEmpty(msg, eMesageText)) { - if (strlen(msg->cm_fields[eMesageText]) > BIGMSG) { + if (msg->cm_lengths[eMesageText] > BIGMSG) { is_bigmsg = 1; holdM = msg->cm_fields[eMesageText]; msg->cm_fields[eMesageText] = NULL; + oldMLen = msg->cm_lengths[eMesageText]; + msg->cm_lengths[eMesageText] = 0; } } @@ -2485,7 +2507,7 @@ long send_message(struct CtdlMessage *msg) { &newmsgid, (int)sizeof(long), holdM, - (strlen(holdM) + 1) + (oldMLen + 1) ); } retval = newmsgid; @@ -2513,11 +2535,8 @@ void CtdlSerializeMessage(struct ser_ret *ret, /* return values */ struct CtdlMessage *msg) /* unserialized msg */ { struct CitContext *CCC = CC; - size_t wlen, fieldlen; + size_t wlen; int i; - long lengths[NDiskFields]; - - memset(lengths, 0, sizeof(lengths)); /* * Check for valid message format @@ -2532,10 +2551,7 @@ void CtdlSerializeMessage(struct ser_ret *ret, /* return values */ ret->len = 3; for (i=0; i < NDiskFields; ++i) if (msg->cm_fields[FieldOrder[i]] != NULL) - { - lengths[i] = strlen(msg->cm_fields[FieldOrder[i]]); - ret->len += lengths[i] + 2; - } + ret->len += msg->cm_lengths[FieldOrder[i]] + 2; ret->ser = malloc(ret->len); if (ret->ser == NULL) { @@ -2554,14 +2570,13 @@ void CtdlSerializeMessage(struct ser_ret *ret, /* return values */ for (i=0; i < NDiskFields; ++i) if (msg->cm_fields[FieldOrder[i]] != NULL) { - fieldlen = lengths[i]; ret->ser[wlen++] = (char)FieldOrder[i]; memcpy(&ret->ser[wlen], msg->cm_fields[FieldOrder[i]], - fieldlen+1); + msg->cm_lengths[FieldOrder[i]] + 1); - wlen = wlen + fieldlen + 1; + wlen = wlen + msg->cm_lengths[FieldOrder[i]] + 1; } if (ret->len != wlen) { @@ -2606,37 +2621,28 @@ void ReplicationChecks(struct CtdlMessage *msg) { * Save a message to disk and submit it into the delivery system. */ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ - struct recptypes *recps, /* recipients (if mail) */ + recptypes *recps, /* recipients (if mail) */ const char *force, /* force a particular room? */ int flags /* should the message be exported clean? */ ) { - char submit_filename[128]; char hold_rm[ROOMNAMELEN]; char actual_rm[ROOMNAMELEN]; char force_room[ROOMNAMELEN]; char content_type[SIZ]; /* We have to learn this */ char recipient[SIZ]; + char bounce_to[1024]; const char *room; long newmsgid; const char *mptr = NULL; struct ctdluser userbuf; int a, i; struct MetaData smi; - FILE *network_fp = NULL; - static int seqnum = 1; - struct CtdlMessage *imsg = NULL; - char *instr = NULL; - size_t instr_alloc = 0; - struct ser_ret smr; - char *hold_R, *hold_D; char *collected_addresses = NULL; struct addresses_to_be_filed *aptr = NULL; StrBuf *saved_rfc822_version = NULL; int qualified_for_journaling = 0; CitContext *CCC = MyContext(); - char bounce_to[1024] = ""; - int rv = 0; MSGM_syslog(LOG_DEBUG, "CtdlSubmitMsg() called\n"); if (CM_IsValidMsg(msg) == 0) return(-1); /* self check */ @@ -2742,7 +2748,7 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ /* Perform "before save" hooks (aborting if any return nonzero) */ MSGM_syslog(LOG_DEBUG, "Performing before-save hooks\n"); - if (PerformMessageHooks(msg, EVT_BEFORESAVE) > 0) return(-3); + if (PerformMessageHooks(msg, recps, EVT_BEFORESAVE) > 0) return(-3); /* * If this message has an Exclusive ID, and the room is replication @@ -2825,180 +2831,60 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ CtdlPutUserLock(&CCC->user); /* Decide where bounces need to be delivered */ - if ((recps != NULL) && (recps->bounce_to != NULL)) { - safestrncpy(bounce_to, recps->bounce_to, sizeof bounce_to); - } - else if (CCC->logged_in) { - snprintf(bounce_to, sizeof bounce_to, "%s@%s", CCC->user.fullname, config.c_nodename); - } - else { - snprintf(bounce_to, sizeof bounce_to, "%s@%s", msg->cm_fields[eAuthor], msg->cm_fields[eNodeName]); + if ((recps != NULL) && (recps->bounce_to == NULL)) + { + if (CCC->logged_in) + snprintf(bounce_to, sizeof bounce_to, "%s@%s", + CCC->user.fullname, config.c_nodename); + else + snprintf(bounce_to, sizeof bounce_to, "%s@%s", + msg->cm_fields[eAuthor], msg->cm_fields[eNodeName]); + recps->bounce_to = bounce_to; } + + CM_SetFieldLONG(msg, eVltMsgNum, newmsgid); + /* If this is private, local mail, make a copy in the * recipient's mailbox and bump the reference count. */ if ((recps != NULL) && (recps->num_local > 0)) - for (i=0; irecp_local, '|'); ++i) { - long recipientlen; - recipientlen = extract_token(recipient, - recps->recp_local, i, - '|', sizeof recipient); - MSG_syslog(LOG_DEBUG, "Delivering private local mail to <%s>\n", - recipient); + { + char *pch; + int ntokens; + + pch = recps->recp_local; + recps->recp_local = recipient; + ntokens = num_tokens(pch, '|'); + for (i=0; i\n", recipient); if (CtdlGetUser(&userbuf, recipient) == 0) { CtdlMailboxName(actual_rm, sizeof actual_rm, &userbuf, MAILROOM); CtdlSaveMsgPointerInRoom(actual_rm, newmsgid, 0, msg); CtdlBumpNewMailCounter(userbuf.usernum); - if (!IsEmptyStr(config.c_funambol_host) || !IsEmptyStr(config.c_pager_program)) { - /* Generate a instruction message for the Funambol notification - * server, in the same style as the SMTP queue - */ - long instrlen; - instr_alloc = 1024; - instr = malloc(instr_alloc); - instrlen = snprintf( - instr, instr_alloc, - "Content-type: %s\n\nmsgid|%ld\nsubmitted|%ld\n" - "bounceto|%s\n", - SPOOLMIME, - newmsgid, - (long)time(NULL), //todo: time() is expensive! - bounce_to - ); - - imsg = malloc(sizeof(struct CtdlMessage)); - memset(imsg, 0, sizeof(struct CtdlMessage)); - imsg->cm_magic = CTDLMESSAGE_MAGIC; - imsg->cm_anon_type = MES_NORMAL; - imsg->cm_format_type = FMT_RFC822; - CM_SetField(imsg, eMsgSubject, HKEY("QMSG")); - CM_SetField(imsg, eAuthor, HKEY("Citadel")); - CM_SetField(imsg, eJournal, HKEY("do not journal")); - CM_SetAsField(imsg, eMesageText, &instr, instrlen); - CM_SetField(imsg, eExtnotify, recipient, recipientlen); - CtdlSubmitMsg(imsg, NULL, FNBL_QUEUE_ROOM, 0); - CM_Free(imsg); - } + PerformMessageHooks(msg, recps, EVT_AFTERUSRMBOXSAVE); } else { MSG_syslog(LOG_DEBUG, "No user <%s>\n", recipient); CtdlSaveMsgPointerInRoom(config.c_aideroom, newmsgid, 0, msg); } } + recps->recp_local = pch; + } /* Perform "after save" hooks */ MSGM_syslog(LOG_DEBUG, "Performing after-save hooks\n"); - CM_SetFieldLONG(msg, eVltMsgNum, newmsgid); - PerformMessageHooks(msg, EVT_AFTERSAVE); + PerformMessageHooks(msg, recps, EVT_AFTERSAVE); CM_FlushField(msg, eVltMsgNum); - /* For IGnet mail, we have to save a new copy into the spooler for - * each recipient, with the R and D fields set to the recipient and - * destination-node. This has two ugly side effects: all other - * recipients end up being unlisted in this recipient's copy of the - * message, and it has to deliver multiple messages to the same - * node. We'll revisit this again in a year or so when everyone has - * a network spool receiver that can handle the new style messages. - */ - if ((recps != NULL) && (recps->num_ignet > 0)) - for (i=0; irecp_ignet, '|'); ++i) { - extract_token(recipient, recps->recp_ignet, i, - '|', sizeof recipient); - - hold_R = msg->cm_fields[eRecipient]; - hold_D = msg->cm_fields[eDestination]; - msg->cm_fields[eRecipient] = malloc(SIZ); - msg->cm_fields[eDestination] = malloc(128); - extract_token(msg->cm_fields[eRecipient], recipient, 0, '@', SIZ); - extract_token(msg->cm_fields[eDestination], recipient, 1, '@', 128); - - CtdlSerializeMessage(&smr, msg); - if (smr.len > 0) { - snprintf(submit_filename, sizeof submit_filename, - "%s/netmail.%04lx.%04x.%04x", - ctdl_netin_dir, - (long) getpid(), CCC->cs_pid, ++seqnum); - network_fp = fopen(submit_filename, "wb+"); - if (network_fp != NULL) { - rv = fwrite(smr.ser, smr.len, 1, network_fp); - if (rv == -1) { - MSG_syslog(LOG_EMERG, "CtdlSubmitMsg(): Couldn't write network spool file: %s\n", - strerror(errno)); - } - fclose(network_fp); - } - free(smr.ser); - } - - free(msg->cm_fields[eRecipient]); - free(msg->cm_fields[eDestination]); - msg->cm_fields[eRecipient] = hold_R; - msg->cm_fields[eDestination] = hold_D; - } - /* Go back to the room we started from */ MSG_syslog(LOG_DEBUG, "Returning to original room %s\n", hold_rm); if (strcasecmp(hold_rm, CCC->room.QRname)) CtdlUserGoto(hold_rm, 0, 1, NULL, NULL); - /* For internet mail, generate delivery instructions. - * Yes, this is recursive. Deal with it. Infinite recursion does - * not happen because the delivery instructions message does not - * contain a recipient. - */ - if ((recps != NULL) && (recps->num_internet > 0)) { - StrBuf *SpoolMsg = NewStrBuf(); - long nTokens; - - MSGM_syslog(LOG_DEBUG, "Generating delivery instructions\n"); - - StrBufPrintf(SpoolMsg, - "Content-type: "SPOOLMIME"\n" - "\n" - "msgid|%ld\n" - "submitted|%ld\n" - "bounceto|%s\n", - newmsgid, - (long)time(NULL), - bounce_to); - - if (recps->envelope_from != NULL) { - StrBufAppendBufPlain(SpoolMsg, HKEY("envelope_from|"), 0); - StrBufAppendBufPlain(SpoolMsg, recps->envelope_from, -1, 0); - StrBufAppendBufPlain(SpoolMsg, HKEY("\n"), 0); - } - if (recps->sending_room != NULL) { - StrBufAppendBufPlain(SpoolMsg, HKEY("source_room|"), 0); - StrBufAppendBufPlain(SpoolMsg, recps->sending_room, -1, 0); - StrBufAppendBufPlain(SpoolMsg, HKEY("\n"), 0); - } - - nTokens = num_tokens(recps->recp_internet, '|'); - for (i = 0; i < nTokens; i++) { - long len; - len = extract_token(recipient, recps->recp_internet, i, '|', sizeof recipient); - if (len > 0) { - StrBufAppendBufPlain(SpoolMsg, HKEY("remote|"), 0); - StrBufAppendBufPlain(SpoolMsg, recipient, len, 0); - StrBufAppendBufPlain(SpoolMsg, HKEY("|0||\n"), 0); - } - } - - imsg = malloc(sizeof(struct CtdlMessage)); - memset(imsg, 0, sizeof(struct CtdlMessage)); - imsg->cm_magic = CTDLMESSAGE_MAGIC; - imsg->cm_anon_type = MES_NORMAL; - imsg->cm_format_type = FMT_RFC822; - imsg->cm_fields[eMsgSubject] = strdup("QMSG"); - imsg->cm_fields[eAuthor] = strdup("Citadel"); - imsg->cm_fields[eJournal] = strdup("do not journal"); - imsg->cm_fields[eMesageText] = SmashStrBuf(&SpoolMsg); /* imsg owns this memory now */ - CtdlSubmitMsg(imsg, NULL, SMTP_SPOOLOUT_ROOM, QP_EADDR); - CM_Free(imsg); - } - /* * Any addresses to harvest for someone's address book? */ @@ -3051,6 +2937,9 @@ long CtdlSubmitMsg(struct CtdlMessage *msg, /* message to save */ } } + if ((recps != NULL) && (recps->bounce_to == bounce_to)) + recps->bounce_to = NULL; + /* Done. */ return(newmsgid); } @@ -3068,7 +2957,7 @@ void quickie_message(const char *from, const char *subject) { struct CtdlMessage *msg; - struct recptypes *recp = NULL; + recptypes *recp = NULL; msg = malloc(sizeof(struct CtdlMessage)); memset(msg, 0, sizeof(struct CtdlMessage)); @@ -3433,6 +3322,45 @@ char *CtdlReadMessageBody(char *terminator, /* token signalling EOT */ return SmashStrBuf(&Message); } +struct CtdlMessage *CtdlMakeMessage( + struct ctdluser *author, /* author's user structure */ + char *recipient, /* NULL if it's not mail */ + char *recp_cc, /* NULL if it's not mail */ + char *room, /* room where it's going */ + int type, /* see MES_ types in header file */ + int format_type, /* variformat, plain text, MIME... */ + char *fake_name, /* who we're masquerading as */ + char *my_email, /* which of my email addresses to use (empty is ok) */ + char *subject, /* Subject (optional) */ + char *supplied_euid, /* ...or NULL if this is irrelevant */ + char *preformatted_text, /* ...or NULL to read text from client */ + char *references /* Thread references */ +) +{ + return CtdlMakeMessageLen( + author, /* author's user structure */ + recipient, /* NULL if it's not mail */ + (recipient)?strlen(recipient) : 0, + recp_cc, /* NULL if it's not mail */ + (recp_cc)?strlen(recp_cc): 0, + room, /* room where it's going */ + (room)?strlen(room): 0, + type, /* see MES_ types in header file */ + format_type, /* variformat, plain text, MIME... */ + fake_name, /* who we're masquerading as */ + (fake_name)?strlen(fake_name): 0, + my_email, /* which of my email addresses to use (empty is ok) */ + (my_email)?strlen(my_email): 0, + subject, /* Subject (optional) */ + (subject)?strlen(subject): 0, + supplied_euid, /* ...or NULL if this is irrelevant */ + (supplied_euid)?strlen(supplied_euid):0, + preformatted_text, /* ...or NULL to read text from client */ + (preformatted_text)?strlen(preformatted_text) : 0, + references, /* Thread references */ + (references)?strlen(references):0); + +} /* * Build a binary message to be saved on disk. @@ -3442,21 +3370,34 @@ char *CtdlReadMessageBody(char *terminator, /* token signalling EOT */ * the rest of the fields when CM_Free() is called.) */ -struct CtdlMessage *CtdlMakeMessage( +struct CtdlMessage *CtdlMakeMessageLen( struct ctdluser *author, /* author's user structure */ char *recipient, /* NULL if it's not mail */ + long rcplen, char *recp_cc, /* NULL if it's not mail */ + long cclen, char *room, /* room where it's going */ + long roomlen, int type, /* see MES_ types in header file */ int format_type, /* variformat, plain text, MIME... */ char *fake_name, /* who we're masquerading as */ + long fnlen, char *my_email, /* which of my email addresses to use (empty is ok) */ + long myelen, char *subject, /* Subject (optional) */ + long subjlen, char *supplied_euid, /* ...or NULL if this is irrelevant */ + long euidlen, char *preformatted_text, /* ...or NULL to read text from client */ - char *references /* Thread references */ - ) { - char dest_node[256]; + long textlen, + char *references, /* Thread references */ + long reflen + ) +{ + struct CitContext *CCC = CC; + /* Don't confuse the poor folks if it's not routed mail. * / + char dest_node[256] = "";*/ + long blen; char buf[1024]; struct CtdlMessage *msg; StrBuf *FakeAuthor; @@ -3468,68 +3409,57 @@ struct CtdlMessage *CtdlMakeMessage( msg->cm_anon_type = type; msg->cm_format_type = format_type; - /* Don't confuse the poor folks if it's not routed mail. */ - strcpy(dest_node, ""); - - if (recipient != NULL) striplt(recipient); - if (recp_cc != NULL) striplt(recp_cc); + if (recipient != NULL) rcplen = striplt(recipient); + if (recp_cc != NULL) cclen = striplt(recp_cc); /* Path or Return-Path */ - if (my_email == NULL) my_email = ""; - - if (!IsEmptyStr(my_email)) { - msg->cm_fields[eMessagePath] = strdup(my_email); + if (myelen > 0) { + CM_SetField(msg, eMessagePath, my_email, myelen); } else { - snprintf(buf, sizeof buf, "%s", author->fullname); - msg->cm_fields[eMessagePath] = strdup(buf); + CM_SetField(msg, eMessagePath, author->fullname, strlen(author->fullname)); } convert_spaces_to_underscores(msg->cm_fields[eMessagePath]); - snprintf(buf, sizeof buf, "%ld", (long)time(NULL)); /* timestamp */ - msg->cm_fields[eTimestamp] = strdup(buf); + blen = snprintf(buf, sizeof buf, "%ld", (long)time(NULL)); + CM_SetField(msg, eTimestamp, buf, blen); - if ((fake_name != NULL) && (fake_name[0])) { /* author */ - FakeAuthor = NewStrBufPlain (fake_name, -1); + if (fnlen > 0) { + FakeAuthor = NewStrBufPlain (fake_name, fnlen); } else { FakeAuthor = NewStrBufPlain (author->fullname, -1); } StrBufRFC2047encode(&FakeEncAuthor, FakeAuthor); - msg->cm_fields[eAuthor] = SmashStrBuf(&FakeEncAuthor); - FreeStrBuf(&FakeAuthor); + CM_SetAsFieldSB(msg, eAuthor, &FakeEncAuthor); - if (CC->room.QRflags & QR_MAILBOX) { /* room */ - msg->cm_fields[eOriginalRoom] = strdup(&CC->room.QRname[11]); + if (CCC->room.QRflags & QR_MAILBOX) { /* room */ + CM_SetField(msg, eOriginalRoom, &CCC->room.QRname[11], strlen(&CCC->room.QRname[11])); } else { - msg->cm_fields[eOriginalRoom] = strdup(CC->room.QRname); + CM_SetField(msg, eOriginalRoom, CCC->room.QRname, strlen(CCC->room.QRname)); } - msg->cm_fields[eNodeName] = strdup(NODENAME); /* nodename */ - msg->cm_fields[eHumanNode] = strdup(HUMANNODE); /* hnodename */ + CM_SetField(msg, eNodeName, NODENAME, strlen(NODENAME)); + CM_SetField(msg, eHumanNode, HUMANNODE, strlen(HUMANNODE)); - if ((recipient != NULL) && (recipient[0] != 0)) { - msg->cm_fields[eRecipient] = strdup(recipient); - } - if ((recp_cc != NULL) && (recp_cc[0] != 0)) { - msg->cm_fields[eCarbonCopY] = strdup(recp_cc); + if (rcplen > 0) { + CM_SetField(msg, eRecipient, recipient, rcplen); } - if (dest_node[0] != 0) { - msg->cm_fields[eDestination] = strdup(dest_node); + if (cclen > 0) { + CM_SetField(msg, eCarbonCopY, recp_cc, cclen); } - if (!IsEmptyStr(my_email)) { - msg->cm_fields[erFc822Addr] = strdup(my_email); + if (myelen > 0) { + CM_SetField(msg, erFc822Addr, my_email, myelen); } - else if ( (author == &CC->user) && (!IsEmptyStr(CC->cs_inet_email)) ) { - msg->cm_fields[erFc822Addr] = strdup(CC->cs_inet_email); + else if ( (author == &CCC->user) && (!IsEmptyStr(CCC->cs_inet_email)) ) { + CM_SetField(msg, erFc822Addr, CCC->cs_inet_email, strlen(CCC->cs_inet_email)); } if (subject != NULL) { long length; - striplt(subject); - length = strlen(subject); + length = striplt(subject); if (length > 0) { long i; long IsAscii; @@ -3539,30 +3469,31 @@ struct CtdlMessage *CtdlMakeMessage( (IsAscii = isascii(subject[i]) != 0 )) i++; if (IsAscii != 0) - msg->cm_fields[eMsgSubject] = strdup(subject); + CM_SetField(msg, eMsgSubject, subject, subjlen); else /* ok, we've got utf8 in the string. */ { - msg->cm_fields[eMsgSubject] = rfc2047encode(subject, length); + char *rfc2047Subj; + rfc2047Subj = rfc2047encode(subject, length); + CM_SetAsField(msg, eMsgSubject, &rfc2047Subj, strlen(rfc2047Subj)); } } } - if (supplied_euid != NULL) { - msg->cm_fields[eExclusiveID] = strdup(supplied_euid); + if (euidlen > 0) { + CM_SetField(msg, eExclusiveID, supplied_euid, euidlen); } - if ((references != NULL) && (!IsEmptyStr(references))) { - if (msg->cm_fields[eWeferences] != NULL) - free(msg->cm_fields[eWeferences]); - msg->cm_fields[eWeferences] = strdup(references); + if (reflen > 0) { + CM_SetField(msg, eWeferences, references, reflen); } if (preformatted_text != NULL) { - msg->cm_fields[eMesageText] = preformatted_text; + CM_SetField(msg, eMesageText, preformatted_text, textlen); } else { - msg->cm_fields[eMesageText] = CtdlReadMessageBody(HKEY("000"), config.c_maxmsglen, NULL, 0, 0); + preformatted_text = CtdlReadMessageBody(HKEY("000"), config.c_maxmsglen, NULL, 0, 0); + CM_SetField(msg, eMesageText, preformatted_text, strlen(preformatted_text)); } return(msg); @@ -3996,7 +3927,7 @@ void CtdlWriteObject(char *req_room, /* Room to stuff it in */ struct ctdlroom qrbuf; char roomname[ROOMNAMELEN]; struct CtdlMessage *msg; - char *encoded_message = NULL; + StrBuf *encoded_message = NULL; if (is_mailbox != NULL) { CtdlMailboxName(roomname, sizeof roomname, is_mailbox, req_room); @@ -4008,39 +3939,28 @@ void CtdlWriteObject(char *req_room, /* Room to stuff it in */ MSG_syslog(LOG_DEBUG, "Raw length is %ld\n", (long)raw_length); if (is_binary) { - encoded_message = malloc((size_t) (((raw_length * 134) / 100) + 4096 ) ); + encoded_message = NewStrBufPlain(NULL, (size_t) (((raw_length * 134) / 100) + 4096 ) ); } else { - encoded_message = malloc((size_t)(raw_length + 4096)); + encoded_message = NewStrBufPlain(NULL, (size_t)(raw_length + 4096)); } - sprintf(encoded_message, "Content-type: %s\n", content_type); + StrBufAppendBufPlain(encoded_message, HKEY("Content-type: "), 0); + StrBufAppendBufPlain(encoded_message, content_type, -1, 0); + StrBufAppendBufPlain(encoded_message, HKEY("\n"), 0); if (is_binary) { - sprintf(&encoded_message[strlen(encoded_message)], - "Content-transfer-encoding: base64\n\n" - ); + StrBufAppendBufPlain(encoded_message, HKEY("Content-transfer-encoding: base64\n\n"), 0); } else { - sprintf(&encoded_message[strlen(encoded_message)], - "Content-transfer-encoding: 7bit\n\n" - ); + StrBufAppendBufPlain(encoded_message, HKEY("Content-transfer-encoding: 7bit\n\n"), 0); } if (is_binary) { - CtdlEncodeBase64( - &encoded_message[strlen(encoded_message)], - raw_message, - (int)raw_length, - 0 - ); + StrBufBase64Append(encoded_message, NULL, raw_message, raw_length, 0); } else { - memcpy( - &encoded_message[strlen(encoded_message)], - raw_message, - (int)(raw_length+1) - ); + StrBufAppendBufPlain(encoded_message, raw_message, raw_length, 0); } MSGM_syslog(LOG_DEBUG, "Allocating\n"); @@ -4049,13 +3969,13 @@ void CtdlWriteObject(char *req_room, /* Room to stuff it in */ msg->cm_magic = CTDLMESSAGE_MAGIC; msg->cm_anon_type = MES_NORMAL; msg->cm_format_type = 4; - msg->cm_fields[eAuthor] = strdup(CCC->user.fullname); - msg->cm_fields[eOriginalRoom] = strdup(req_room); - msg->cm_fields[eNodeName] = strdup(config.c_nodename); - msg->cm_fields[eHumanNode] = strdup(config.c_humannode); + CM_SetField(msg, eAuthor, CCC->user.fullname, strlen(CCC->user.fullname)); + CM_SetField(msg, eOriginalRoom, req_room, strlen(req_room)); + CM_SetField(msg, eNodeName, config.c_nodename, strlen(config.c_nodename)); + CM_SetField(msg, eHumanNode, config.c_humannode, strlen(config.c_humannode)); msg->cm_flags = flags; - msg->cm_fields[eMesageText] = encoded_message; + CM_SetAsFieldSB(msg, eMesageText, &encoded_message); /* Create the requested room if we have to. */ if (CtdlGetRoom(&qrbuf, roomname) != 0) { diff --git a/citadel/msgbase.h b/citadel/msgbase.h index 7780d69fc..058c902e5 100644 --- a/citadel/msgbase.h +++ b/citadel/msgbase.h @@ -77,7 +77,7 @@ void memfmout (char *mptr, const char *nl); void output_mime_parts(char *); long send_message (struct CtdlMessage *); void loadtroom (void); -long CtdlSubmitMsg(struct CtdlMessage *, struct recptypes *, const char *, int); +long CtdlSubmitMsg(struct CtdlMessage *, recptypes *, const char *, int); void quickie_message(const char *from, const char *fromaddr, @@ -211,7 +211,29 @@ struct CtdlMessage *CtdlMakeMessage( char *preformatted_text, /* ...or NULL to read text from client */ char *references /* Thread references */ ); -int CtdlIsMe(char *addr, int addr_buf_len); + +struct CtdlMessage *CtdlMakeMessageLen( + struct ctdluser *author, /* author's user structure */ + char *recipient, /* NULL if it's not mail */ + long rcplen, + char *recp_cc, /* NULL if it's not mail */ + long cclen, + char *room, /* room where it's going */ + long roomlen, + int type, /* see MES_ types in header file */ + int format_type, /* variformat, plain text, MIME... */ + char *fake_name, /* who we're masquerading as */ + long fnlen, + char *my_email, /* which of my email addresses to use (empty is ok) */ + long myelen, + char *subject, /* Subject (optional) */ + long subjlen, + char *supplied_euid, /* ...or NULL if this is irrelevant */ + long euidlen, + char *preformatted_text, /* ...or NULL to read text from client */ + long textlen, + char *references, /* Thread references */ + long reflen); /* * loading messages async via an FD: diff --git a/citadel/serv_extensions.c b/citadel/serv_extensions.c index 387b8754d..4b4e44c08 100644 --- a/citadel/serv_extensions.c +++ b/citadel/serv_extensions.c @@ -101,7 +101,7 @@ UserFunctionHook *UserHookTable = NULL; typedef struct MessageFunctionHook MessageFunctionHook; struct MessageFunctionHook { MessageFunctionHook *next; - int (*h_function_pointer) (struct CtdlMessage *msg); + int (*h_function_pointer) (struct CtdlMessage *msg, recptypes *recps); int eventtype; }; MessageFunctionHook *MessageHookTable = NULL; @@ -730,7 +730,7 @@ void CtdlDestroyUserHooks(void) } -void CtdlRegisterMessageHook(int (*handler)(struct CtdlMessage *), +void CtdlRegisterMessageHook(int (*handler)(struct CtdlMessage *, recptypes *), int EventType) { @@ -748,7 +748,7 @@ void CtdlRegisterMessageHook(int (*handler)(struct CtdlMessage *), } -void CtdlUnregisterMessageHook(int (*handler)(struct CtdlMessage *), +void CtdlUnregisterMessageHook(int (*handler)(struct CtdlMessage *, recptypes *), int EventType) { MessageFunctionHook *cur, *p, *last; @@ -1379,7 +1379,7 @@ void PerformUserHooks(ctdluser *usbuf, int EventType) } } -int PerformMessageHooks(struct CtdlMessage *msg, int EventType) +int PerformMessageHooks(struct CtdlMessage *msg, recptypes *recps, int EventType) { MessageFunctionHook *fcn = NULL; int total_retval = 0; @@ -1397,7 +1397,7 @@ int PerformMessageHooks(struct CtdlMessage *msg, int EventType) */ for (fcn = MessageHookTable; fcn != NULL; fcn = fcn->next) { if (fcn->eventtype == EventType) { - total_retval = total_retval + (*fcn->h_function_pointer) (msg); + total_retval = total_retval + (*fcn->h_function_pointer) (msg, recps); } } diff --git a/citadel/serv_extensions.h b/citadel/serv_extensions.h index 53973fe90..8591737ae 100644 --- a/citadel/serv_extensions.h +++ b/citadel/serv_extensions.h @@ -82,7 +82,7 @@ void CtdlDestroyXmsgHooks(void); void CtdlDestroyMessageHook(void); -int PerformMessageHooks(struct CtdlMessage *, int EventType); +int PerformMessageHooks(struct CtdlMessage *, recptypes *recps, int EventType); void CtdlDestroyNetprocHooks(void); diff --git a/citadel/server.h b/citadel/server.h index 10e8bee73..6aedb5463 100644 --- a/citadel/server.h +++ b/citadel/server.h @@ -21,6 +21,7 @@ struct CtdlMessage { char cm_anon_type; /* Anonymous or author-visible */ char cm_format_type; /* Format type */ char *cm_fields[256]; /* Data fields */ + long cm_lengths[256]; /* size of datafields */ unsigned int cm_flags; /* How to handle (NOT SAVED TO DISK) */ }; @@ -28,6 +29,28 @@ struct CtdlMessage { #define CM_SKIP_HOOKS 0x01 /* Don't run server-side handlers */ +/* Data structure returned by validate_recipients() */ +typedef struct __recptypes { + int recptypes_magic; + int num_local; + int num_internet; + int num_ignet; + int num_room; + int num_error; + char *errormsg; + char *recp_local; + char *recp_internet; + char *recp_ignet; + char *recp_room; + char *recp_orgroom; + char *display_recp; + char *bounce_to; + char *envelope_from; + char *sending_room; +} recptypes; + +#define RECPTYPES_MAGIC 0xfeeb + #define CTDLEXIT_SHUTDOWN 0 /* Normal shutdown; do NOT auto-restart */ @@ -224,6 +247,7 @@ struct cdbdata { #define EVT_BEFORESAVE 201 #define EVT_AFTERSAVE 202 #define EVT_SMTPSCAN 203 /* called before submitting a msg from SMTP */ +#define EVT_AFTERUSRMBOXSAVE 204 /* called afte a message was saved into a users inbox */ /* Priority levels for paging functions (lower is better) */ enum { XMSG_PRI_LOCAL, /* Other users on -this- server */ diff --git a/citadel/user_ops.c b/citadel/user_ops.c index 0b50d129b..e55807dd3 100644 --- a/citadel/user_ops.c +++ b/citadel/user_ops.c @@ -653,7 +653,7 @@ int CtdlLoginExistingUser(char *authname, const char *trythisname) else { /* native auth mode */ - struct recptypes *valid = NULL; + recptypes *valid = NULL; /* First, try to log in as if the supplied name is a display name */ found_user = CtdlGetUser(&CC->user, username); -- 2.30.2