]> code.citadel.org Git - citadel.git/blob - citadel/server/journaling.c
Modified some of the server source files to carry the new and improved version of...
[citadel.git] / citadel / server / journaling.c
1 // Message journaling functions.
2 //
3 // Copyright (c) 1987-2022 by the citadel.org team
4 //
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.
8
9 #include <stdio.h>
10 #include <libcitadel.h>
11 #include "ctdl_module.h"
12 #include "citserver.h"
13 #include "config.h"
14 #include "user_ops.h"
15 #include "serv_vcard.h"                 /* Needed for vcard_getuser and extract_inet_email_addrs */
16 #include "internet_addressing.h"
17 #include "journaling.h"
18
19 struct jnlq *jnlq = NULL;       /* journal queue */
20
21 /*
22  * Hand off a copy of a message to be journalized.
23  */
24 void JournalBackgroundSubmit(struct CtdlMessage *msg,
25                         StrBuf *saved_rfc822_version,
26                         struct recptypes *recps) {
27
28         struct jnlq *jptr = NULL;
29
30         /* Avoid double journaling! */
31         if (!CM_IsEmpty(msg, eJournal)) {
32                 FreeStrBuf(&saved_rfc822_version);
33                 return;
34         }
35
36         jptr = (struct jnlq *)malloc(sizeof(struct jnlq));
37         if (jptr == NULL) {
38                 FreeStrBuf(&saved_rfc822_version);
39                 return;
40         }
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);
48
49         /* Add to the queue */
50         begin_critical_section(S_JOURNAL_QUEUE);
51         jptr->next = jnlq;
52         jnlq = jptr;
53         end_critical_section(S_JOURNAL_QUEUE);
54 }
55
56
57 /*
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 !!!!
60  */
61 void local_to_inetemail(char *inetemail, char *localuser, size_t inetemail_len) {
62         struct ctdluser us;
63         struct vCard *v;
64
65         strcpy(inetemail, "");
66         if (CtdlGetUser(&us, localuser) != 0) {
67                 return;
68         }
69
70         v = vcard_get_user(&us);
71         if (v == NULL) {
72                 return;
73         }
74
75         extract_inet_email_addrs(inetemail, inetemail_len, NULL, 0, v, 1);
76         vcard_free(v);
77 }
78
79
80 /*
81  * Called by JournalRunQueue() to send an individual message.
82  */
83 void JournalRunQueueMsg(struct jnlq *jmsg) {
84
85         struct CtdlMessage *journal_msg = NULL;
86         struct recptypes *journal_recps = NULL;
87         StrBuf *message_text = NULL;
88         char mime_boundary[256];
89         long mblen;
90         long rfc822len;
91         char recipient[256];
92         char inetemail[256];
93         static int seq = 0;
94         int i;
95
96         if (jmsg == NULL)
97                 return;
98         journal_recps = validate_recipients(CtdlGetConfigStr("c_journal_dest"), NULL, 0);
99         if (journal_recps != NULL) {
100
101                 if (  (journal_recps->num_local > 0)
102                    || (journal_recps->num_internet > 0)
103                    || (journal_recps->num_room > 0)
104                 ) {
105
106                         /*
107                          * Construct journal message.
108                          * Note that we are transferring ownership of some of the memory here.
109                          */
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"));
116
117                         if (!IsEmptyStr(jmsg->from)) {
118                                 CM_SetField(journal_msg, eAuthor, jmsg->from, -1);
119                         }
120
121                         if (!IsEmptyStr(jmsg->rfca)) {
122                                 CM_SetField(journal_msg, erFc822Addr, jmsg->rfca, -1);
123                         }
124
125                         if (!IsEmptyStr(jmsg->subj)) {
126                                 CM_SetField(journal_msg, eMsgSubject, jmsg->subj, -1);
127                         }
128
129                         mblen = snprintf(mime_boundary, sizeof(mime_boundary),
130                                          "--Citadel-Journal-%08lx-%04x--", time(NULL), ++seq);
131
132                         if (!IsEmptyStr(jmsg->rfc822)) {
133                                 rfc822len = strlen(jmsg->rfc822);
134                         }
135                         else {
136                                 rfc822len = 0;
137                         }
138
139                         message_text = NewStrBufPlain(NULL, rfc822len + sizeof(struct recptypes) + 1024);
140
141                         /*
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.)
144                          */
145                         StrBufAppendBufPlain(
146                                 message_text, 
147                                 HKEY("Content-type: multipart/mixed; boundary=\""),
148                                 0
149                         );
150
151                         StrBufAppendBufPlain(message_text, mime_boundary, mblen, 0);
152
153                         StrBufAppendBufPlain(
154                                 message_text, 
155                                 HKEY("\"\r\n"
156                                      "Content-Identifier: ExJournalReport\r\n"
157                                      "MIME-Version: 1.0\r\n"
158                                      "\n"
159                                      "--"),
160                                 0
161                         );
162
163                         StrBufAppendBufPlain(message_text, mime_boundary, mblen, 0);
164
165                         StrBufAppendBufPlain(
166                                 message_text, 
167                                 HKEY("\r\n"
168                                      "Content-type: text/plain\r\n"
169                                      "\r\n"
170                                      "Sender: "), 0);
171
172                         if (CM_IsEmpty(journal_msg, eAuthor))
173                                 StrBufAppendBufPlain(
174                                         message_text, 
175                                         journal_msg->cm_fields[eAuthor], -1, 0);
176                         else
177                                 StrBufAppendBufPlain(
178                                         message_text, 
179                                         HKEY("(null)"), 0);
180
181                         if (!CM_IsEmpty(journal_msg, erFc822Addr)) {
182                                 StrBufAppendPrintf(message_text, " <%s>",
183                                                    journal_msg->cm_fields[erFc822Addr]);
184                         }
185
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);
189
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);
195                                 }
196                         }
197
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);
202                                 }
203                         }
204
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);
212
213                         CM_SetAsFieldSB(journal_msg, eMesageText, &message_text);
214                         free(jmsg->rfc822);
215                         free(jmsg->msgn);
216                         jmsg->rfc822 = NULL;
217                         jmsg->msgn = NULL;
218                         
219                         /* Submit journal message */
220                         CtdlSubmitMsg(journal_msg, journal_recps, "");
221                         CM_Free(journal_msg);
222                 }
223
224                 free_recipients(journal_recps);
225         }
226
227         /* We are responsible for freeing this memory. */
228         free(jmsg);
229 }
230
231
232 /*
233  * Run the queue.
234  */
235 void JournalRunQueue(void) {
236         struct jnlq *jptr = NULL;
237
238         while (jnlq != NULL) {
239                 begin_critical_section(S_JOURNAL_QUEUE);
240                 if (jnlq != NULL) {
241                         jptr = jnlq;
242                         jnlq = jnlq->next;
243                 }
244                 end_critical_section(S_JOURNAL_QUEUE);
245                 JournalRunQueueMsg(jptr);
246         }
247 }