4 * Message journaling functions.
14 #if TIME_WITH_SYS_TIME
15 # include <sys/time.h>
19 # include <sys/time.h>
32 #include <libcitadel.h>
38 #include "sysdep_decls.h"
39 #include "citserver.h"
46 #include "internet_addressing.h"
47 #include "serv_vcard.h" /* Needed for vcard_getuser and extract_inet_email_addrs */
48 #include "journaling.h"
50 #include "ctdl_module.h"
53 struct jnlq
*jnlq
= NULL
; /* journal queue */
56 * Hand off a copy of a message to be journalized.
58 void JournalBackgroundSubmit(struct CtdlMessage
*msg
,
59 char *saved_rfc822_version
,
60 struct recptypes
*recps
) {
62 struct jnlq
*jptr
= NULL
;
64 /* Avoid double journaling! */
65 if (msg
->cm_fields
['J'] != NULL
) {
66 free(saved_rfc822_version
);
70 jptr
= (struct jnlq
*)malloc(sizeof(struct jnlq
));
72 free(saved_rfc822_version
);
75 memset(jptr
, 0, sizeof(struct jnlq
));
76 if (recps
!= NULL
) memcpy(&jptr
->recps
, recps
, sizeof(struct recptypes
));
77 if (msg
->cm_fields
['A'] != NULL
) jptr
->from
= strdup(msg
->cm_fields
['A']);
78 if (msg
->cm_fields
['N'] != NULL
) jptr
->node
= strdup(msg
->cm_fields
['N']);
79 if (msg
->cm_fields
['F'] != NULL
) jptr
->rfca
= strdup(msg
->cm_fields
['F']);
80 if (msg
->cm_fields
['U'] != NULL
) jptr
->subj
= strdup(msg
->cm_fields
['U']);
81 if (msg
->cm_fields
['I'] != NULL
) jptr
->msgn
= strdup(msg
->cm_fields
['I']);
82 jptr
->rfc822
= saved_rfc822_version
;
84 /* Add to the queue */
85 begin_critical_section(S_JOURNAL_QUEUE
);
88 end_critical_section(S_JOURNAL_QUEUE
);
93 * Convert a local user name to an internet email address for the journal
97 * TODODRW: change this into a CtdlModuleDo type function that returns alternative address info
98 * for this local user. Something like CtdlModuleGoGetAddr(char *localuser, int type, char *alt_addr, size_t alt_addr_len)
99 * where type can be ADDR_EMAIL, ADDR_FIDO, ADDR_UUCP, ADDR_WEB, ADDR_POSTAL etc etc.
100 * This then begs the question of what should be returned. Is it wise to return a single char* using a comma as a
101 * delimiter? Or would it be better to return a linked list of some kind?
103 void local_to_inetemail(char *inetemail
, char *localuser
, size_t inetemail_len
) {
107 strcpy(inetemail
, "");
108 if (getuser(&us
, localuser
) != 0) {
112 v
= vcard_get_user(&us
);
117 extract_inet_email_addrs(inetemail
, inetemail_len
, NULL
, 0, v
, 1);
123 * Called by JournalRunQueue() to send an individual message.
125 void JournalRunQueueMsg(struct jnlq
*jmsg
) {
127 struct CtdlMessage
*journal_msg
= NULL
;
128 struct recptypes
*journal_recps
= NULL
;
129 char *message_text
= NULL
;
130 char mime_boundary
[256];
136 journal_recps
= validate_recipients(config
.c_journal_dest
, NULL
, 0);
137 if (journal_recps
!= NULL
) {
139 if ( (journal_recps
->num_local
> 0)
140 || (journal_recps
->num_internet
> 0)
141 || (journal_recps
->num_ignet
> 0)
142 || (journal_recps
->num_room
> 0)
146 * Construct journal message.
147 * Note that we are transferring ownership of some of the memory here.
149 journal_msg
= malloc(sizeof(struct CtdlMessage
));
150 memset(journal_msg
, 0, sizeof(struct CtdlMessage
));
151 journal_msg
->cm_magic
= CTDLMESSAGE_MAGIC
;
152 journal_msg
->cm_anon_type
= MES_NORMAL
;
153 journal_msg
->cm_format_type
= FMT_RFC822
;
154 journal_msg
->cm_fields
['J'] = strdup("is journal");
155 journal_msg
->cm_fields
['A'] = jmsg
->from
;
156 journal_msg
->cm_fields
['N'] = jmsg
->node
;
157 journal_msg
->cm_fields
['F'] = jmsg
->rfca
;
158 journal_msg
->cm_fields
['U'] = jmsg
->subj
;
160 sprintf(mime_boundary
, "--Citadel-Journal-%08lx-%04x--", time(NULL
), ++seq
);
161 message_text
= malloc(strlen(jmsg
->rfc822
) + sizeof(struct recptypes
) + 1024);
164 * Here is where we begin to compose the journalized message.
165 * NOTE: the superfluous "Content-Identifer: ExJournalReport" header was
166 * requested by a paying customer, and yes, it is intentionally
167 * spelled wrong. Do NOT remove or change it.
169 sprintf(message_text
,
170 "Content-type: multipart/mixed; boundary=\"%s\"\r\n"
171 "Content-Identifer: ExJournalReport\r\n"
172 "MIME-Version: 1.0\r\n"
175 "Content-type: text/plain\r\n"
181 ( journal_msg
->cm_fields
['A'] ? journal_msg
->cm_fields
['A'] : "(null)" )
184 if (journal_msg
->cm_fields
['F']) {
185 sprintf(&message_text
[strlen(message_text
)], "<%s>",
186 journal_msg
->cm_fields
['F']);
188 else if (journal_msg
->cm_fields
['N']) {
189 sprintf(&message_text
[strlen(message_text
)], "@ %s",
190 journal_msg
->cm_fields
['N']);
193 sprintf(&message_text
[strlen(message_text
)],
195 "Message-ID: <%s>\r\n"
201 if (jmsg
->recps
.num_local
> 0) {
202 for (i
=0; i
<jmsg
->recps
.num_local
; ++i
) {
203 extract_token(recipient
, jmsg
->recps
.recp_local
,
204 i
, '|', sizeof recipient
);
205 local_to_inetemail(inetemail
, recipient
, sizeof inetemail
);
206 sprintf(&message_text
[strlen(message_text
)],
207 " %s <%s>\r\n", recipient
, inetemail
);
211 if (jmsg
->recps
.num_ignet
> 0) {
212 for (i
=0; i
<jmsg
->recps
.num_ignet
; ++i
) {
213 extract_token(recipient
, jmsg
->recps
.recp_ignet
,
214 i
, '|', sizeof recipient
);
215 sprintf(&message_text
[strlen(message_text
)],
216 " %s\r\n", recipient
);
220 if (jmsg
->recps
.num_internet
> 0) {
221 for (i
=0; i
<jmsg
->recps
.num_internet
; ++i
) {
222 extract_token(recipient
, jmsg
->recps
.recp_internet
,
223 i
, '|', sizeof recipient
);
224 sprintf(&message_text
[strlen(message_text
)],
225 " %s\r\n", recipient
);
229 sprintf(&message_text
[strlen(message_text
)],
232 "Content-type: message/rfc822\r\n"
242 journal_msg
->cm_fields
['M'] = message_text
;
246 /* Submit journal message */
247 CtdlSubmitMsg(journal_msg
, journal_recps
, "", 0);
248 CtdlFreeMessage(journal_msg
);
251 free_recipients(journal_recps
);
254 /* We are responsible for freeing this memory. */
262 void JournalRunQueue(void) {
263 struct jnlq
*jptr
= NULL
;
265 while (jnlq
!= NULL
) {
266 begin_critical_section(S_JOURNAL_QUEUE
);
271 end_critical_section(S_JOURNAL_QUEUE
);
272 JournalRunQueueMsg(jptr
);