citadel
About: Citadel is an advanced messaging and collaboration system for groupware and BBS applications (preferred OS: Linux).
  Fossies Dox: citadel.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

journaling.c
Go to the documentation of this file.
1/*
2 * Message journaling functions.
3 *
4 * Copyright (c) 1987-2020 by the citadel.org team
5 *
6 * This program is open source software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 3.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 */
14
15#include <stdio.h>
16#include <libcitadel.h>
17#include "ctdl_module.h"
18#include "citserver.h"
19#include "config.h"
20#include "user_ops.h"
21#include "serv_vcard.h" /* Needed for vcard_getuser and extract_inet_email_addrs */
22#include "internet_addressing.h"
23#include "journaling.h"
24
25struct jnlq *jnlq = NULL; /* journal queue */
26
27/*
28 * Hand off a copy of a message to be journalized.
29 */
31 StrBuf *saved_rfc822_version,
32 struct recptypes *recps) {
33
34 struct jnlq *jptr = NULL;
35
36 /* Avoid double journaling! */
37 if (!CM_IsEmpty(msg, eJournal)) {
38 FreeStrBuf(&saved_rfc822_version);
39 return;
40 }
41
42 jptr = (struct jnlq *)malloc(sizeof(struct jnlq));
43 if (jptr == NULL) {
44 FreeStrBuf(&saved_rfc822_version);
45 return;
46 }
47 memset(jptr, 0, sizeof(struct jnlq));
48 if (recps != NULL) memcpy(&jptr->recps, recps, sizeof(struct recptypes));
49 if (!CM_IsEmpty(msg, eAuthor)) jptr->from = strdup(msg->cm_fields[eAuthor]);
50 if (!CM_IsEmpty(msg, erFc822Addr)) jptr->rfca = strdup(msg->cm_fields[erFc822Addr]);
51 if (!CM_IsEmpty(msg, eMsgSubject)) jptr->subj = strdup(msg->cm_fields[eMsgSubject]);
52 if (!CM_IsEmpty(msg, emessageId)) jptr->msgn = strdup(msg->cm_fields[emessageId]);
53 jptr->rfc822 = SmashStrBuf(&saved_rfc822_version);
54
55 /* Add to the queue */
57 jptr->next = jnlq;
58 jnlq = jptr;
60}
61
62
63/*
64 * Convert a local user name to an internet email address for the journal
65 * FIXME - grab the user's Internet email address from the user record, not from vCard !!!!
66 */
67void local_to_inetemail(char *inetemail, char *localuser, size_t inetemail_len) {
68 struct ctdluser us;
69 struct vCard *v;
70
71 strcpy(inetemail, "");
72 if (CtdlGetUser(&us, localuser) != 0) {
73 return;
74 }
75
76 v = vcard_get_user(&us);
77 if (v == NULL) {
78 return;
79 }
80
81 extract_inet_email_addrs(inetemail, inetemail_len, NULL, 0, v, 1);
82 vcard_free(v);
83}
84
85
86/*
87 * Called by JournalRunQueue() to send an individual message.
88 */
89void JournalRunQueueMsg(struct jnlq *jmsg) {
90
91 struct CtdlMessage *journal_msg = NULL;
92 struct recptypes *journal_recps = NULL;
93 StrBuf *message_text = NULL;
94 char mime_boundary[256];
95 long mblen;
96 long rfc822len;
97 char recipient[256];
98 char inetemail[256];
99 static int seq = 0;
100 int i;
101
102 if (jmsg == NULL)
103 return;
104 journal_recps = validate_recipients(CtdlGetConfigStr("c_journal_dest"), NULL, 0);
105 if (journal_recps != NULL) {
106
107 if ( (journal_recps->num_local > 0)
108 || (journal_recps->num_internet > 0)
109 || (journal_recps->num_room > 0)
110 ) {
111
112 /*
113 * Construct journal message.
114 * Note that we are transferring ownership of some of the memory here.
115 */
116 journal_msg = malloc(sizeof(struct CtdlMessage));
117 memset(journal_msg, 0, sizeof(struct CtdlMessage));
118 journal_msg->cm_magic = CTDLMESSAGE_MAGIC;
119 journal_msg->cm_anon_type = MES_NORMAL;
120 journal_msg->cm_format_type = FMT_RFC822;
121 CM_SetField(journal_msg, eJournal, HKEY("is journal"));
122
123 if (!IsEmptyStr(jmsg->from)) {
124 CM_SetField(journal_msg, eAuthor, jmsg->from, -1);
125 }
126
127 if (!IsEmptyStr(jmsg->rfca)) {
128 CM_SetField(journal_msg, erFc822Addr, jmsg->rfca, -1);
129 }
130
131 if (!IsEmptyStr(jmsg->subj)) {
132 CM_SetField(journal_msg, eMsgSubject, jmsg->subj, -1);
133 }
134
135 mblen = snprintf(mime_boundary, sizeof(mime_boundary),
136 "--Citadel-Journal-%08lx-%04x--", time(NULL), ++seq);
137
138 if (!IsEmptyStr(jmsg->rfc822)) {
139 rfc822len = strlen(jmsg->rfc822);
140 }
141 else {
142 rfc822len = 0;
143 }
144
145 message_text = NewStrBufPlain(NULL, rfc822len + sizeof(struct recptypes) + 1024);
146
147 /*
148 * Here is where we begin to compose the journalized message.
149 * (The "ExJournalReport" header is consumed by some email retention services which assume the journaling agent is Exchange.)
150 */
151 StrBufAppendBufPlain(
152 message_text,
153 HKEY("Content-type: multipart/mixed; boundary=\""),
154 0
155 );
156
157 StrBufAppendBufPlain(message_text, mime_boundary, mblen, 0);
158
159 StrBufAppendBufPlain(
160 message_text,
161 HKEY("\"\r\n"
162 "Content-Identifier: ExJournalReport\r\n"
163 "MIME-Version: 1.0\r\n"
164 "\n"
165 "--"),
166 0
167 );
168
169 StrBufAppendBufPlain(message_text, mime_boundary, mblen, 0);
170
171 StrBufAppendBufPlain(
172 message_text,
173 HKEY("\r\n"
174 "Content-type: text/plain\r\n"
175 "\r\n"
176 "Sender: "), 0);
177
178 if (CM_IsEmpty(journal_msg, eAuthor))
179 StrBufAppendBufPlain(
180 message_text,
181 journal_msg->cm_fields[eAuthor], -1, 0);
182 else
183 StrBufAppendBufPlain(
184 message_text,
185 HKEY("(null)"), 0);
186
187 if (!CM_IsEmpty(journal_msg, erFc822Addr)) {
188 StrBufAppendPrintf(message_text, " <%s>",
189 journal_msg->cm_fields[erFc822Addr]);
190 }
191
192 StrBufAppendBufPlain(message_text, HKEY("\r\nMessage-ID: <"), 0);
193 StrBufAppendBufPlain(message_text, jmsg->msgn, -1, 0);
194 StrBufAppendBufPlain(message_text, HKEY(">\r\nRecipients:\r\n"), 0);
195
196 if (jmsg->recps.num_local > 0) {
197 for (i=0; i<jmsg->recps.num_local; ++i) {
198 extract_token(recipient, jmsg->recps.recp_local, i, '|', sizeof recipient);
199 local_to_inetemail(inetemail, recipient, sizeof inetemail);
200 StrBufAppendPrintf(message_text, " %s <%s>\r\n", recipient, inetemail);
201 }
202 }
203
204 if (jmsg->recps.num_internet > 0) {
205 for (i=0; i<jmsg->recps.num_internet; ++i) {
206 extract_token(recipient, jmsg->recps.recp_internet, i, '|', sizeof recipient);
207 StrBufAppendPrintf(message_text, " %s\r\n", recipient);
208 }
209 }
210
211 StrBufAppendBufPlain(message_text, HKEY("\r\n" "--"), 0);
212 StrBufAppendBufPlain(message_text, mime_boundary, mblen, 0);
213 StrBufAppendBufPlain(message_text, HKEY("\r\nContent-type: message/rfc822\r\n\r\n"), 0);
214 StrBufAppendBufPlain(message_text, jmsg->rfc822, rfc822len, 0);
215 StrBufAppendBufPlain(message_text, HKEY("--"), 0);
216 StrBufAppendBufPlain(message_text, mime_boundary, mblen, 0);
217 StrBufAppendBufPlain(message_text, HKEY("--\r\n"), 0);
218
219 CM_SetAsFieldSB(journal_msg, eMesageText, &message_text);
220 free(jmsg->rfc822);
221 free(jmsg->msgn);
222 jmsg->rfc822 = NULL;
223 jmsg->msgn = NULL;
224
225 /* Submit journal message */
226 CtdlSubmitMsg(journal_msg, journal_recps, "");
227 CM_Free(journal_msg);
228 }
229
230 free_recipients(journal_recps);
231 }
232
233 /* We are responsible for freeing this memory. */
234 free(jmsg);
235}
236
237
238/*
239 * Run the queue.
240 */
241void JournalRunQueue(void) {
242 struct jnlq *jptr = NULL;
243
244 while (jnlq != NULL) {
246 if (jnlq != NULL) {
247 jptr = jnlq;
248 jnlq = jnlq->next;
249 }
251 JournalRunQueueMsg(jptr);
252 }
253}
254
255
#define MES_NORMAL
Definition: citadel.h:135
char * CtdlGetConfigStr(char *key)
Definition: config.c:384
int CtdlGetUser(struct ctdluser *usbuf, char *name)
Definition: user_ops.c:75
struct recptypes * validate_recipients(char *supplied_recipients, const char *RemoteIdentifier, int Flags)
void free_recipients(struct recptypes *valid)
void JournalBackgroundSubmit(struct CtdlMessage *msg, StrBuf *saved_rfc822_version, struct recptypes *recps)
Definition: journaling.c:30
void JournalRunQueueMsg(struct jnlq *jmsg)
Definition: journaling.c:89
struct jnlq * jnlq
Definition: journaling.c:25
void local_to_inetemail(char *inetemail, char *localuser, size_t inetemail_len)
Definition: journaling.c:67
void JournalRunQueue(void)
Definition: journaling.c:241
void CM_Free(struct CtdlMessage *msg)
Definition: msgbase.c:310
int CM_IsEmpty(struct CtdlMessage *Msg, eMsgField which)
Definition: msgbase.c:137
long CtdlSubmitMsg(struct CtdlMessage *msg, struct recptypes *recps, const char *force)
Definition: msgbase.c:2603
void CM_SetField(struct CtdlMessage *Msg, eMsgField which, const char *buf, long length)
Definition: msgbase.c:142
void CM_SetAsFieldSB(struct CtdlMessage *Msg, eMsgField which, StrBuf **buf)
Definition: msgbase.c:258
void * malloc(size_t)
void free(void *)
struct vCard * vcard_get_user(struct ctdluser *u)
Definition: serv_vcard.c:477
void extract_inet_email_addrs(char *emailaddrbuf, size_t emailaddrbuf_len, char *secemailaddrbuf, size_t secemailaddrbuf_len, struct vCard *v, int local_addrs_only)
Definition: serv_vcard.c:82
#define CTDLMESSAGE_MAGIC
Definition: server.h:42
@ emessageId
Definition: server.h:311
@ eMesageText
Definition: server.h:315
@ erFc822Addr
Definition: server.h:310
@ eAuthor
Definition: server.h:307
@ eMsgSubject
Definition: server.h:320
@ eJournal
Definition: server.h:312
#define FMT_RFC822
Definition: server.h:178
@ S_JOURNAL_QUEUE
Definition: server.h:149
int snprintf(char *buf, size_t max, const char *fmt,...)
Definition: snprintf.c:69
int cm_magic
Definition: server.h:34
char cm_anon_type
Definition: server.h:35
char * cm_fields[256]
Definition: server.h:37
char cm_format_type
Definition: server.h:36
Definition: journaling.h:1
char * rfc822
Definition: journaling.h:9
char * subj
Definition: journaling.h:7
char * msgn
Definition: journaling.h:8
struct jnlq * next
Definition: journaling.h:2
char * rfca
Definition: journaling.h:6
struct recptypes recps
Definition: journaling.h:3
char * from
Definition: journaling.h:4
int num_internet
Definition: server.h:50
int num_room
Definition: server.h:52
char * recp_local
Definition: server.h:55
char * recp_internet
Definition: server.h:56
int num_local
Definition: server.h:49
void begin_critical_section(int which_one)
Definition: threads.c:67
void end_critical_section(int which_one)
Definition: threads.c:85