1 /******************************************************************************
2 * HPT --- FTN NetMail/EchoMail Tosser
3 ******************************************************************************
4 * carbon.c : functions for making carbon copy
5 *
6 * by Max Chernogor <mihz@ua.fm>, 2:464/108@fidonet
7 *
8 * This file is part of HPT.
9 *
10 * HPT is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by the
12 * Free Software Foundation; either version 2, or (at your option) any
13 * later version.
14 *
15 * HPT is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with HPT; see the file COPYING. If not, write to the Free
22 * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
23 *****************************************************************************
24 * $Id$
25 */
26
27
28 #include <stdlib.h>
29 #include <string.h>
30
31 #include <huskylib/compiler.h>
32
33 #ifdef HAS_PROCESS_H
34 # include <process.h>
35 #endif
36
37 #ifdef HAS_IO_H
38 #include <io.h>
39 #endif
40
41 #ifdef HAS_UNISTD_H
42 #include <unistd.h>
43 #endif
44
45 #ifdef HAS_DOS_H
46 #include <dos.h>
47 #endif
48
49 #include <fidoconf/fidoconf.h>
50 #include <fidoconf/common.h>
51 #include <huskylib/recode.h>
52 #include <huskylib/temp.h>
53 #include <huskylib/xstr.h>
54 #include <smapi/msgapi.h>
55
56 #include <areafix/areafix.h>
57 #include "global.h"
58 #include "toss.h"
59
60 extern s_statToss statToss;
61
MessForCC(s_message * msg)62 s_message* MessForCC(s_message *msg)
63 {
64 s_message* CCmsg;
65
66 if(config->carbonCount == 0)
67 return NULL;
68
69 CCmsg = (s_message*) safe_calloc(1,sizeof(s_message));
70
71 CCmsg->origAddr.zone = msg->origAddr.zone;
72 CCmsg->origAddr.net = msg->origAddr.net;
73 CCmsg->origAddr.node = msg->origAddr.node;
74 CCmsg->origAddr.point = msg->origAddr.point;
75
76 CCmsg->destAddr.zone = msg->destAddr.zone;
77 CCmsg->destAddr.net = msg->destAddr.net ;
78 CCmsg->destAddr.node = msg->destAddr.node;
79 CCmsg->destAddr.point = msg->destAddr.point;
80
81 xstrcat(&(CCmsg->fromUserName), msg->fromUserName);
82 xstrcat(&(CCmsg->toUserName), msg->toUserName);
83 xstrcat(&(CCmsg->subjectLine), msg->subjectLine);
84 xstrcat(&(CCmsg->text), msg->text);
85
86 strcpy( (char*)CCmsg->datetime, (char*)msg->datetime );
87 CCmsg->attributes = msg->attributes;
88 CCmsg->textLength = msg->textLength;
89 CCmsg->netMail = msg->netMail;
90 CCmsg->recode = msg->recode;
91
92 return CCmsg;
93 }
94
processExternal(s_area * echo,s_message * msg,s_carbon carbon)95 int processExternal (s_area *echo, s_message *msg,s_carbon carbon)
96 {
97 FILE *msgfp = NULL;
98 char *fname = NULL;
99 char *progname = carbon.areaName, *execstr = NULL, *p = NULL;
100 int rc;
101
102 w_log(LL_CARBON, "Carbon external from area %s to program \"%s\"%s%s%s: msg from \"%s\" %s to \"%s\"%s%s",
103 echo->areaName? echo->areaName:"netmail",
104 progname? progname:"",
105 carbon.reason? " at reason \"":"", carbon.reason? carbon.reason:"", carbon.reason? "\"":"",
106 msg->fromUserName, aka2str(msg->origAddr), msg->toUserName,
107 msg->netMail? " ":"", msg->netMail? aka2str(msg->destAddr):""
108 );
109
110 #ifdef HAS_popen_close
111 if (*progname == '|') {
112 msgfp = popen(progname + 1, "w");
113 } else
114 #endif
115 msgfp = createTempTextFile(config->tempDir, &fname);
116
117 if (!msgfp) {
118 w_log(LL_ERR, "external process %s: cannot create file", progname);
119 return 1;
120 } else
121 w_log(LL_FILE,"toss.c:processExternal() opened %s %s", fname?"file":"pipe", fname?fname:progname);
122 /* Output header info */
123 if (!msg->netMail) fprintf(msgfp, "Area: %s\n", echo->areaName);
124 fprintf(msgfp, "From: \"%s\" %s\n", msg->fromUserName, aka2str(msg->origAddr));
125 fprintf(msgfp, "To: \"%s\" %s\n", msg->toUserName, aka2str(msg->destAddr));
126 fprintf(msgfp, "Date: \"%s\"\n", msg->datetime);
127 fprintf(msgfp, "Subject: \"%s\"\n\n", msg->subjectLine);
128 /* Output msg text */
129 for (p = msg->text; *p ; p++)
130 if (*p == '\r')
131 fputc('\n', msgfp);
132 else
133 fputc(*p, msgfp);
134 fputc('\n', msgfp);
135 #ifdef HAS_popen_close
136 if (*progname == '|') {
137 pclose(msgfp);
138 rc = 0;
139 } else
140 #endif
141 {
142 /* Execute external program */
143 fclose(msgfp);
144 execstr = safe_malloc(strlen(progname)+strlen(fname)+3);
145 if (*progname == '|')
146 sprintf(execstr, "%s < %s", progname+1, fname);
147 else sprintf(execstr, "%s %s", progname, fname);
148 #ifdef __NT__
149 CharToOem(execstr, execstr); /* this is really need? */
150 #endif
151 rc = cmdcall(execstr);
152 nfree(execstr);
153 unlink(fname);
154 nfree(fname);
155 }
156 /* if (rc == -1 || rc == 127) */
157 if (rc) /* system() return exit status returned by shell */
158 w_log(LL_ERR, "Execution of external program failed. Cmd is: \"%s\", return code %d", execstr, rc);
159 return 0;
160
161 }
162
163 /* area - area to carbon messages, echo - original echo area */
processCarbonCopy(s_area * area,s_area * echo,s_message * msg,s_carbon carbon)164 int processCarbonCopy (s_area *area, s_area *echo, s_message *msg, s_carbon carbon)
165 {
166 char *p, *text, *line, *old_text, *reason = carbon.reason;
167 int i, old_textLength, aexport = carbon.aexport, rc = 0;
168
169 statToss.CC++;
170
171 old_textLength = msg->textLength;
172 old_text = msg->text;
173 i = old_textLength;
174
175 /* recoding from internal to transport charSet if needed */
176 /* this must be jub of putMsgInArea.
177 if (config->outtab) {
178 if (msg->recode & REC_TXT) {
179 recodeToTransportCharset((char*)msg->text);
180 msg->recode &= ~REC_TXT;
181 }
182 if (msg->recode & REC_HDR) {
183 recodeToTransportCharset((char*)msg->fromUserName);
184 recodeToTransportCharset((char*)msg->toUserName);
185 recodeToTransportCharset((char*)msg->subjectLine);
186 msg->recode &= ~REC_HDR;
187 }
188 if (reason) recodeToTransportCharset((char*)reason);
189 }
190 */
191 msg->text = NULL;
192 msg->textLength = 0;
193
194 line = old_text;
195
196 if (!msg->netMail) {
197 xstrscat(&msg->text,
198 (aexport) ? "AREA:" : "",
199 (aexport) ? area->areaName : "",
200 (aexport) ? "\r" : "",
201 "\001AREA:", echo->areaName,
202 "\r" , NULLP);
203 }
204 if (strncmp(line, "AREA:", 5) == 0) {
205 /* jump over AREA:xxxxx\r */
206 line+=5;
207 while (*line && *line != '\r') line++;
208 if (*line) line++;
209 }
210
211 while(*line == '\001')
212 {
213 p = strchr(line, '\r');
214 if(!p)
215 break;
216 /* Temporary make it \0 terminated string */
217 *p = '\0';
218 xstrcat(&msg->text,line);
219 /* and then we *must* put '\r' back. */
220 xstrcat(&msg->text, "\r");
221 *p = '\r';
222 line = p+1;
223 }
224
225 text = line; /* may be old_test or old_text w/o begining kluges */
226
227 if (!msg->netMail) {
228 if ((!config->carbonKeepSb) && (!area->keepsb)) {
229 line = strrstr(text, " * Origin:");
230 if (NULL != (p = strstr(line ? line : text,"\rSEEN-BY:")))
231 i = (size_t) (p - text) + 1;
232 }
233 xstrscat(&msg->text,
234 msg->text ? (msg->text[strlen(msg->text)-1] == '\r' ?"":"\r") : "" ,
235 (config->carbonExcludeFwdFrom) ? "" : " * Forwarded from area '",
236 (config->carbonExcludeFwdFrom) ? "" : echo->areaName,
237 (config->carbonExcludeFwdFrom) ? "" : "'\r",
238 (reason) ? reason : "",
239 (reason) ? "\r" : "", NULLP);
240 msg->textLength = strlen(msg->text);
241 }
242
243 xstralloc(&msg->text,i); /* add i bytes */
244 strncat(msg->text,text,i); /* copy rest of msg */
245 msg->textLength += i;
246
247 if (!aexport) {
248 if (msg->netMail) rc = putMsgInArea(area,msg,0,MSGSENT);
249 else rc = putMsgInArea(area,msg,0,0);
250 area->imported++; /* area has got new messages */
251 }
252 else if (!msg->netMail) {
253 rc = processEMMsg(msg, *area->useAka, 1, 0);
254 } else
255 rc = processNMMsg(msg, NULL, area, 1, 0);
256
257 w_log(LL_CARBON, "Carbon %s from %s to %s%s%s%s: msg from \"%s\" %s to \"%s\"%s%s. Result code is %d", carbon.move? "move":"copy",
258 echo->areaName? echo->areaName:"netmail",
259 area->areaName? area->areaName:"netmail",
260 reason? " at reason \"":"", reason? reason:"", reason? "\"":"",
261 msg->fromUserName, aka2str(msg->origAddr), msg->toUserName,
262 msg->netMail? " ":"", msg->netMail? aka2str(msg->destAddr):"",
263 rc
264 );
265
266 nfree(msg->text);
267 msg->textLength = old_textLength;
268 msg->text = old_text;
269 msg->recode &= ~REC_TXT; /* old text is always in Transport Charset */
270 if (config->intab && reason) recodeToInternalCharset((char*)reason);
271
272 return rc;
273 }
274
275
276 /* Does carbon copying */
277 /* Return value: 0 if nothing happend, 1 if there was a carbon copy,
278 > 1 if there was a carbon move or carbon delete*/
carbonCopy(s_message * msg,XMSG * xmsg,s_area * echo)279 int carbonCopy(s_message *msg, XMSG *xmsg, s_area *echo)
280 {
281 unsigned int i, rc = 0, result=0;
282 char *testptr = NULL, *testptr2 = NULL, *pattern = NULL;
283 s_area *area = NULL;
284 s_carbon *cb=&(config->carbons[0]);
285 s_area **copiedTo = NULL;
286 int copiedToCount = 0;
287 int ncop;
288
289 w_log( LL_FUNC, "carbonCopy() begin");
290
291 if(!msg)
292 return 0;
293 if (echo->ccoff==1)
294 return 0;
295 if (echo->msgbType==MSGTYPE_PASSTHROUGH && config->exclPassCC)
296 return 0;
297
298 for (i=0; i<config->carbonCount; i++,++cb) {
299 /* Dont come to use netmail on echomail and vise verse */
300 if (!(cb->rule & CC_AND) /* move and netmail have meaning only in last carbon in group */
301 && cb->move != 2 /* type of mail doesn't matter for CarbonDelete */
302 && !msg->netMail != !cb->netMail) continue; /* if types differ the rule doesn't apply */
303
304 area = cb->area;
305
306 if(!(cb->rule&CC_AND)) /* not AND & not AND-NOT */
307 {
308 if (!cb->extspawn && /* fix for extspawn */
309 cb->areaName != NULL && /* fix for carbonDelete */
310 /* dont CC to the echo the mail comes from */
311 !sstricmp(echo->areaName,area->areaName)
312 )
313 continue;
314 }
315 switch (cb->ctype) {
316 case ct_to:
317 result=patimat(msg->toUserName,cb->str);
318 break;
319
320 case ct_from:
321 result=patimat(msg->fromUserName,cb->str);
322 break;
323
324 case ct_kludge:
325 case ct_msgtext:
326 testptr=msg->text;
327 /* skip area: kludge */
328 if (strncmp(testptr, "AREA:", 5) == 0)
329 {
330 if ((testptr = strchr(testptr, '\r')) != NULL)
331 testptr++;
332 }
333 /* cb->str is substring, so pattern must be "*str*" */
334 pattern=safe_malloc(strlen(cb->str)+3);
335 *pattern='*';
336 sstrcpy(pattern+1, cb->str);
337 strcat(pattern, "*");
338 result=0;
339
340 /* check the message line by line */
341 while (testptr) {
342 testptr2 = strchr(testptr, '\r');
343 if ((*testptr == '\001' && cb->ctype == ct_kludge) ||
344 (*testptr != '\001' && cb->ctype == ct_msgtext)) {
345 if (testptr2) *testptr2 = '\0';
346 result = patimat(testptr, pattern);
347 if (testptr2) *testptr2 = '\r';
348 if (result) break;
349 }
350 if (testptr2)
351 testptr = testptr2+1;
352 else
353 break;
354 }
355 nfree(pattern);
356 break;
357
358 case ct_subject:
359 result=patimat(msg->subjectLine,cb->str);
360 break;
361
362 case ct_addr:
363 result=!addrComp(msg->origAddr, cb->addr);
364 break;
365
366 case ct_fromarea:
367 result=patimat(echo->areaName,cb->str);
368 break;
369
370 case ct_group:
371 if(echo->group!=NULL){
372 /* cb->str for example Fido,xxx,.. */
373 testptr=cb->str;
374 do{
375 if(NULL==(testptr=fc_stristr(echo->group,testptr)))
376 break;
377 testptr+=strlen(echo->group);
378 result=(*testptr==',' || *testptr==' ' || !*testptr);
379 testptr-=strlen(echo->group);
380 ++testptr;
381 }while(!result);
382 }
383 break;
384 }
385
386 if(cb->rule&CC_NOT) /* NOT on/off */
387 result=!result;
388
389 switch(cb->rule&CC_AND){ /* what operation with next result */
390 case CC_OR: /* OR */
391 if (result && area && cb->move!=2 && !config->carbonAndQuit) {
392 /* check if we've done cc to dest area already */
393 for (ncop=0; ncop < copiedToCount && result; ncop++)
394 if (area == copiedTo[ncop]) result = 0;
395 if (result) {
396 copiedTo = safe_realloc (copiedTo, (copiedToCount+1) * sizeof (s_area *));
397 copiedTo[copiedToCount] = area;
398 copiedToCount++;
399 }
400 }
401
402 if(result){
403 /* make cc */
404 /* Set value: 1 if copy 3 if move */
405 rc = cb->move ? 3 : 1;
406 if(cb->extspawn)
407 processExternal(echo,msg,*cb);
408 else
409 if (cb->areaName && cb->move!=2)
410 {
411 if (!processCarbonCopy(area,echo,msg,*cb))
412 rc &= 1;
413 }
414 /* delete CarbonMove and CarbonDelete messages */
415 if (cb->move && xmsg) xmsg->attr |= MSGKILL;
416 if (cb->move == 2) {
417 /* FIXME: Is there any reason in this case? */
418 w_log( LL_CARBON, "Carbon delete from %s %s%s%s: msg from \"%s\" %s to \"%s\"%s%s.",
419 echo->areaName? echo->areaName:"netmail",
420 cb->reason? " at reason \"":"", cb->reason? cb->reason:"", cb->reason? "\"":"",
421 msg->fromUserName, aka2str(msg->origAddr), msg->toUserName,
422 msg->netMail? " ":"", msg->netMail? aka2str(msg->destAddr):""
423 );
424 }
425 if (config->carbonAndQuit)
426 /* not skip quit or delete */
427 if ((cb->areaName && *cb->areaName!='*') || cb->move==2) {
428 return rc;
429 }
430 }
431 break;
432 case CC_AND: /* AND & AND-NOT */
433 if(!result){
434 /* following expressions can be skipped until OR */
435 for (++i,++cb; i<config->carbonCount; i++,++cb)
436 if(!(cb->rule&CC_AND)) /* AND & AND-NOT */
437 break; /* this is the last in the AND expr. chain */
438 }
439 /* else result==TRUE, so continue with next expr. */
440 break;
441 }
442 } /* end for() */
443
444 if (copiedTo) nfree (copiedTo);
445 w_log( LL_FUNC, "carbonCopy() rc=%d", rc);
446 return rc;
447 }
448
449
450
451