1 // Message journaling functions.
3 // Copyright (c) 1987-2022 by the citadel.org team
5 // This program is open source software. Use, duplication, or disclosure
6 // is subject to the terms of the GNU General Public License, version 3.
7 // The program is distributed without any warranty, expressed or implied.
10 #include <libcitadel.h>
11 #include "ctdl_module.h"
12 #include "citserver.h"
15 #include "serv_vcard.h" /* Needed for vcard_getuser and extract_inet_email_addrs */
16 #include "internet_addressing.h"
17 #include "journaling.h"
19 struct jnlq *jnlq = NULL; /* journal queue */
22 * Hand off a copy of a message to be journalized.
24 void JournalBackgroundSubmit(struct CtdlMessage *msg,
25 StrBuf *saved_rfc822_version,
26 struct recptypes *recps) {
28 struct jnlq *jptr = NULL;
30 /* Avoid double journaling! */
31 if (!CM_IsEmpty(msg, eJournal)) {
32 FreeStrBuf(&saved_rfc822_version);
36 jptr = (struct jnlq *)malloc(sizeof(struct jnlq));
38 FreeStrBuf(&saved_rfc822_version);
41 memset(jptr, 0, sizeof(struct jnlq));
42 if (recps != NULL) memcpy(&jptr->recps, recps, sizeof(struct recptypes));
43 if (!CM_IsEmpty(msg, eAuthor)) jptr->from = strdup(msg->cm_fields[eAuthor]);
44 if (!CM_IsEmpty(msg, erFc822Addr)) jptr->rfca = strdup(msg->cm_fields[erFc822Addr]);
45 if (!CM_IsEmpty(msg, eMsgSubject)) jptr->subj = strdup(msg->cm_fields[eMsgSubject]);
46 if (!CM_IsEmpty(msg, emessageId)) jptr->msgn = strdup(msg->cm_fields[emessageId]);
47 jptr->rfc822 = SmashStrBuf(&saved_rfc822_version);
49 /* Add to the queue */
50 begin_critical_section(S_JOURNAL_QUEUE);
53 end_critical_section(S_JOURNAL_QUEUE);
58 * Convert a local user name to an internet email address for the journal
59 * FIXME - grab the user's Internet email address from the user record, not from vCard !!!!
61 void local_to_inetemail(char *inetemail, char *localuser, size_t inetemail_len) {
65 strcpy(inetemail, "");
66 if (CtdlGetUser(&us, localuser) != 0) {
70 v = vcard_get_user(&us);
75 extract_inet_email_addrs(inetemail, inetemail_len, NULL, 0, v, 1);
81 * Called by JournalRunQueue() to send an individual message.
83 void JournalRunQueueMsg(struct jnlq *jmsg) {
85 struct CtdlMessage *journal_msg = NULL;
86 struct recptypes *journal_recps = NULL;
87 StrBuf *message_text = NULL;
88 char mime_boundary[256];
98 journal_recps = validate_recipients(CtdlGetConfigStr("c_journal_dest"), NULL, 0);
99 if (journal_recps != NULL) {
101 if ( (journal_recps->num_local > 0)
102 || (journal_recps->num_internet > 0)
103 || (journal_recps->num_room > 0)
107 * Construct journal message.
108 * Note that we are transferring ownership of some of the memory here.
110 journal_msg = malloc(sizeof(struct CtdlMessage));
111 memset(journal_msg, 0, sizeof(struct CtdlMessage));
112 journal_msg->cm_magic = CTDLMESSAGE_MAGIC;
113 journal_msg->cm_anon_type = MES_NORMAL;
114 journal_msg->cm_format_type = FMT_RFC822;
115 CM_SetField(journal_msg, eJournal, HKEY("is journal"));
117 if (!IsEmptyStr(jmsg->from)) {
118 CM_SetField(journal_msg, eAuthor, jmsg->from, -1);
121 if (!IsEmptyStr(jmsg->rfca)) {
122 CM_SetField(journal_msg, erFc822Addr, jmsg->rfca, -1);
125 if (!IsEmptyStr(jmsg->subj)) {
126 CM_SetField(journal_msg, eMsgSubject, jmsg->subj, -1);
129 mblen = snprintf(mime_boundary, sizeof(mime_boundary),
130 "--Citadel-Journal-%08lx-%04x--", time(NULL), ++seq);
132 if (!IsEmptyStr(jmsg->rfc822)) {
133 rfc822len = strlen(jmsg->rfc822);
139 message_text = NewStrBufPlain(NULL, rfc822len + sizeof(struct recptypes) + 1024);
142 * Here is where we begin to compose the journalized message.
143 * (The "ExJournalReport" header is consumed by some email retention services which assume the journaling agent is Exchange.)
145 StrBufAppendBufPlain(
147 HKEY("Content-type: multipart/mixed; boundary=\""),
151 StrBufAppendBufPlain(message_text, mime_boundary, mblen, 0);
153 StrBufAppendBufPlain(
156 "Content-Identifier: ExJournalReport\r\n"
157 "MIME-Version: 1.0\r\n"
163 StrBufAppendBufPlain(message_text, mime_boundary, mblen, 0);
165 StrBufAppendBufPlain(
168 "Content-type: text/plain\r\n"
172 if (CM_IsEmpty(journal_msg, eAuthor))
173 StrBufAppendBufPlain(
175 journal_msg->cm_fields[eAuthor], -1, 0);
177 StrBufAppendBufPlain(
181 if (!CM_IsEmpty(journal_msg, erFc822Addr)) {
182 StrBufAppendPrintf(message_text, " <%s>",
183 journal_msg->cm_fields[erFc822Addr]);
186 StrBufAppendBufPlain(message_text, HKEY("\r\nMessage-ID: <"), 0);
187 StrBufAppendBufPlain(message_text, jmsg->msgn, -1, 0);
188 StrBufAppendBufPlain(message_text, HKEY(">\r\nRecipients:\r\n"), 0);
190 if (jmsg->recps.num_local > 0) {
191 for (i=0; i<jmsg->recps.num_local; ++i) {
192 extract_token(recipient, jmsg->recps.recp_local, i, '|', sizeof recipient);
193 local_to_inetemail(inetemail, recipient, sizeof inetemail);
194 StrBufAppendPrintf(message_text, " %s <%s>\r\n", recipient, inetemail);
198 if (jmsg->recps.num_internet > 0) {
199 for (i=0; i<jmsg->recps.num_internet; ++i) {
200 extract_token(recipient, jmsg->recps.recp_internet, i, '|', sizeof recipient);
201 StrBufAppendPrintf(message_text, " %s\r\n", recipient);
205 StrBufAppendBufPlain(message_text, HKEY("\r\n" "--"), 0);
206 StrBufAppendBufPlain(message_text, mime_boundary, mblen, 0);
207 StrBufAppendBufPlain(message_text, HKEY("\r\nContent-type: message/rfc822\r\n\r\n"), 0);
208 StrBufAppendBufPlain(message_text, jmsg->rfc822, rfc822len, 0);
209 StrBufAppendBufPlain(message_text, HKEY("--"), 0);
210 StrBufAppendBufPlain(message_text, mime_boundary, mblen, 0);
211 StrBufAppendBufPlain(message_text, HKEY("--\r\n"), 0);
213 CM_SetAsFieldSB(journal_msg, eMesageText, &message_text);
219 /* Submit journal message */
220 CtdlSubmitMsg(journal_msg, journal_recps, "");
221 CM_Free(journal_msg);
224 free_recipients(journal_recps);
227 /* We are responsible for freeing this memory. */
235 void JournalRunQueue(void) {
236 struct jnlq *jptr = NULL;
238 while (jnlq != NULL) {
239 begin_critical_section(S_JOURNAL_QUEUE);
244 end_critical_section(S_JOURNAL_QUEUE);
245 JournalRunQueueMsg(jptr);