1
2 // ------------------------------------------------------------------
3 // GoldED+
4 // Copyright (C) 1990-1999 Odinn Sorensen
5 // Copyright (C) 1999-2000 Alexander S. Aganichev
6 // ------------------------------------------------------------------
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License as
9 // published by the Free Software Foundation; either version 2 of the
10 // License, or (at your option) any later version.
11 //
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 // General Public License for more details.
16 //
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software
19 // Foundation, Inc., 59 Temple Place, Suite 330, Boston,
20 // MA 02111-1307 USA
21 // ------------------------------------------------------------------
22 // $Id: geline.cpp,v 1.82 2011/12/01 10:13:51 stas_degteff Exp $
23 // ------------------------------------------------------------------
24 // Conversion of a raw message to a linked list of lines.
25 // ------------------------------------------------------------------
26
27 #include <cstdarg>
28 #include <limits.h>
29 #include <golded.h>
30 #include <gstrmail.h>
31 #include <gutlcode.h>
32 #include <ghdrmime.h>
33
34 #if defined(__USE_ALLOCA__)
35 #include <malloc.h>
36 #endif
37
38 #ifdef HAS_ICONV
39 #include <iconv.h>
40 #endif
41
42
43 // ------------------------------------------------------------------
44
45 #ifdef __UNIX__
46 #define GOLDMARK '^' // xwindow fonts has no square sign :(
47 #else
48 #define GOLDMARK '\xFD'
49 #endif
50
51
52 // ------------------------------------------------------------------
53
54 const int BODYLINE = 0;
55 const int HEADERLINE = 1;
56 const int USERDEFINED = 2;
57 const int RFC_X = 3;
58
59 enum {
60 MASK_FTS = 0x1000,
61 FTS_AREA,
62 FTS_INTL,
63 FTS_FMPT,
64 FTS_TOPT,
65 FTS_MSGID,
66 FTS_REPLY,
67 FTS_SEENBY,
68 FTS_PATH,
69 FTS_ZZZZ
70 };
71
72 enum {
73 MASK_FSC = 0x2000,
74 FSC_CHARSET,
75 FSC_CHRC,
76 FSC_CHRS,
77 FSC_CODEPAGE,
78 FSC_DOMAIN,
79 FSC_EID,
80 FSC_ENC,
81 FSC_ENCLFILE,
82 FSC_FLAGS,
83 FSC_FWDFROM,
84 FSC_FWDORIG,
85 FSC_FWDTO,
86 FSC_FWDDEST,
87 FSC_FWDSUBJ,
88 FSC_FWDAREA,
89 FSC_FWDMSGID,
90 FSC_I51,
91 FSC_MSGTO,
92 FSC_PID,
93 FSC_PTH,
94 FSC_REPLYADDR,
95 FSC_REPLYTO,
96 FSC_SPLIT,
97 FSC_SPTH,
98 FSC_TID,
99 FSC_ZZZZ
100 };
101
102 enum {
103 MASK_XXX = 0x8000,
104 XXX_ACUPDATE,
105 XXX_DESTADDR,
106 XXX_ENCRYPTION,
107 XXX_EOT,
108 XXX_GATECHK,
109 XXX_GID,
110 XXX_GIF,
111 XXX_GMD,
112 XXX_GROUP,
113 XXX_MOOD,
114 XXX_MSGSEQ,
115 XXX_NOTE,
116 XXX_ORIGID,
117 XXX_ORIGINAL,
118 XXX_ORIGREF,
119 XXX_RECD,
120 XXX_RFC,
121 XXX_RFD,
122 XXX_RID,
123 XXX_ROUTE,
124 XXX_SN,
125 XXX_SOT,
126 XXX_TCL1,
127 XXX_TCL2,
128 XXX_TZUTCINFO,
129 XXX_TZUTC,
130 XXX_TZ,
131 XXX_VIA,
132 XXX_XID,
133 XXX_ZZZZ
134 };
135
136 enum {
137 MASK_RFC = 0x4000,
138 RFC_ALSO_CONTROL,
139 RFC_APPARENTLY_TO,
140 RFC_APPROVED,
141 RFC_ARTICLE_NAMES,
142 RFC_ARTICLE_UPDATES,
143 RFC_BCC,
144 RFC_CC,
145 RFC_COMMENT,
146 RFC_COMMENTS,
147 RFC_CONTENT_DESCRIPTION,
148 RFC_CONTENT_DISPOSITION,
149 RFC_CONTENT_ID,
150 RFC_CONTENT_LENGTH,
151 RFC_CONTENT_TRANSFER_ENCODING,
152 RFC_CONTENT_TYPE,
153 RFC_CONTROL,
154 RFC_DATE,
155 RFC_DELIVERED_TO,
156 RFC_DELIVERY_DATE,
157 RFC_DISTRIBUTION,
158 RFC_ENCRYPTED,
159 RFC_ERRORS_TO,
160 RFC_EXPIRES,
161 RFC_FOLLOWUP_TO,
162 RFC_FROM,
163 RFC_FROMX,
164 RFC_IN_REPLY_TO,
165 RFC_KEYWORDS,
166 RFC_LINES,
167 RFC_MAILING_LIST, // This one is actually _not_ RFC
168 RFC_MESSAGE_ID,
169 RFC_MIME_VERSION,
170 RFC_NEWSGROUPS,
171 RFC_NEWS_SOFTWARE,
172 RFC_NNTP_POSTING_DATE,
173 RFC_NNTP_POSTING_HOST,
174 RFC_NNTP_POSTING_USER,
175 RFC_OLD_DATE,
176 RFC_ORGANIZATION,
177 RFC_ORIGINATOR,
178 RFC_PATH,
179 RFC_PRECEDENCE,
180 RFC_PRIORITY,
181 RFC_RECEIVED,
182 RFC_REFERENCES,
183 RFC_REPLY_TO,
184 RFC_RETURN_PATH,
185 RFC_RETURN_RECEIPT_TO,
186 RFC_SEE_ALSO,
187 RFC_SENDER,
188 RFC_STATUS,
189 RFC_SUBJECT,
190 RFC_SUMMARY,
191 RFC_SUPERSEDES,
192 RFC_TO,
193 RFC_VERSION,
194 RFC_XREF,
195 RFC_X_CHARSET,
196 RFC_X_CHAR_ESC,
197 RFC_X_FTN_TO,
198 RFC_X_MAILER,
199 RFC_X_NEWSREADER,
200 RFC_X_TO,
201 RFC_RNEWS,
202 RFC_ZZZZ
203 };
204
205 #define MASK_ALL (MASK_FTS|MASK_FSC|MASK_RFC|MASK_XXX)
206
207
208 // ------------------------------------------------------------------
209
210 struct Kludges {
211 char* key;
212 uint num;
213 byte req;
214 };
215
216
217 // ------------------------------------------------------------------
218
219 const byte KCRQ_NONE = 0x0000;
220 const byte KCRQ_COLON = 0x0001;
221 const byte KCRQ_CASE = 0x0002;
222
223
224 // ------------------------------------------------------------------
225
226 static const Kludges fts_list[] = {
227
228 { "AREA" , FTS_AREA , KCRQ_CASE },
229 { "INTL" , FTS_INTL , KCRQ_CASE },
230 { "FMPT" , FTS_FMPT , KCRQ_CASE },
231 { "TOPT" , FTS_TOPT , KCRQ_CASE },
232 { "MSGID" , FTS_MSGID , KCRQ_CASE },
233 { "REPLY" , FTS_REPLY , KCRQ_CASE },
234 { "SEEN-BY" , FTS_SEENBY , KCRQ_CASE },
235 { "PATH" , FTS_PATH , KCRQ_CASE },
236 { "" , FTS_ZZZZ , KCRQ_NONE },
237 };
238
239
240 // ------------------------------------------------------------------
241
242 static const Kludges fsc_list[] = {
243
244 { "CHARSET" , FSC_CHARSET , KCRQ_CASE },
245 { "CHRC" , FSC_CHRC , KCRQ_CASE },
246 { "CHRS" , FSC_CHRS , KCRQ_CASE },
247 { "CODEPAGE" , FSC_CODEPAGE , KCRQ_CASE },
248 { "DOMAIN" , FSC_DOMAIN , KCRQ_CASE },
249 { "EID" , FSC_EID , KCRQ_CASE },
250 { "ENC" , FSC_ENC , KCRQ_CASE },
251 { "ENCLFILE" , FSC_ENCLFILE , KCRQ_CASE },
252 { "FLAGS" , FSC_FLAGS , KCRQ_CASE },
253 { "FWDFROM" , FSC_FWDFROM , KCRQ_CASE },
254 { "FWDORIG" , FSC_FWDORIG , KCRQ_CASE },
255 { "FWDTO" , FSC_FWDTO , KCRQ_CASE },
256 { "FWDDEST" , FSC_FWDDEST , KCRQ_CASE },
257 { "FWDSUBJ" , FSC_FWDSUBJ , KCRQ_CASE },
258 { "FWDAREA" , FSC_FWDAREA , KCRQ_CASE },
259 { "FWDMSGID" , FSC_FWDMSGID , KCRQ_CASE },
260 { "I51" , FSC_I51 , KCRQ_CASE },
261 { "MSGTO" , FSC_MSGTO , KCRQ_CASE },
262 { "PID" , FSC_PID , KCRQ_CASE },
263 { "PTH" , FSC_PTH , KCRQ_CASE },
264 { "REPLYADDR" , FSC_REPLYADDR , KCRQ_CASE },
265 { "REPLYTO" , FSC_REPLYTO , KCRQ_CASE },
266 { "SPLIT" , FSC_SPLIT , KCRQ_CASE },
267 { "SPTH" , FSC_SPTH , KCRQ_CASE },
268 { "TID" , FSC_TID , KCRQ_CASE },
269 { "" , FSC_ZZZZ , KCRQ_NONE },
270 };
271
272
273 // ------------------------------------------------------------------
274
275 static const Kludges xxx_list[] = {
276
277 { "ACUPDATE" , XXX_ACUPDATE , KCRQ_CASE },
278 { "DESTADDR" , XXX_DESTADDR , KCRQ_CASE },
279 { "ENCRYPTION" , XXX_ENCRYPTION , KCRQ_CASE },
280 { "EOT" , XXX_EOT , KCRQ_CASE },
281 { "GATECHK" , XXX_GATECHK , KCRQ_CASE },
282 { "GID" , XXX_GID , KCRQ_CASE },
283 { "GIF" , XXX_GIF , KCRQ_CASE },
284 { "GMD" , XXX_GMD , KCRQ_CASE },
285 { "GROUP" , XXX_GROUP , KCRQ_CASE },
286 { "MOOD" , XXX_MOOD , KCRQ_CASE },
287 { "MSGSEQ" , XXX_MSGSEQ , KCRQ_CASE },
288 { "NOTE" , XXX_NOTE , KCRQ_CASE },
289 { "ORIGID" , XXX_ORIGID , KCRQ_CASE },
290 { "Original" , XXX_ORIGINAL , KCRQ_NONE },
291 { "ORIGREF" , XXX_ORIGREF , KCRQ_CASE },
292 { "Recd" , XXX_RECD , KCRQ_CASE },
293 { "RFC" , XXX_RFC , KCRQ_CASE },
294 { "RFD" , XXX_RFD , KCRQ_CASE },
295 { "RID" , XXX_RID , KCRQ_CASE },
296 { "#ROUTE" , XXX_ROUTE , KCRQ_CASE },
297 { "SN" , XXX_SN , KCRQ_CASE },
298 { "SOT" , XXX_SOT , KCRQ_CASE },
299 { "TCL1" , XXX_TCL1 , KCRQ_CASE },
300 { "TCL2" , XXX_TCL2 , KCRQ_CASE },
301 { "TZUTCINFO" , XXX_TZUTCINFO , KCRQ_CASE },
302 { "TZUTC" , XXX_TZUTC , KCRQ_CASE },
303 { "TZ" , XXX_TZ , KCRQ_CASE },
304 { "Via" , XXX_VIA , KCRQ_NONE },
305 { "XID" , XXX_XID , KCRQ_CASE },
306 { "" , XXX_ZZZZ , KCRQ_NONE }
307 };
308
309
310 // ------------------------------------------------------------------
311
312 static const Kludges rfc_list[] = {
313
314 { "Also-Control" , RFC_ALSO_CONTROL , KCRQ_COLON },
315 { "Apparently-To" , RFC_APPARENTLY_TO , KCRQ_COLON },
316 { "Approved" , RFC_APPROVED , KCRQ_COLON },
317 { "Article-Names" , RFC_ARTICLE_NAMES , KCRQ_COLON },
318 { "Article-Updates" , RFC_ARTICLE_UPDATES , KCRQ_COLON },
319 { "Bcc" , RFC_BCC , KCRQ_COLON },
320 { "Cc" , RFC_CC , KCRQ_COLON },
321 { "Comment" , RFC_COMMENT , KCRQ_COLON },
322 { "Comments" , RFC_COMMENTS , KCRQ_COLON },
323 { "Content-Description" , RFC_CONTENT_DESCRIPTION , KCRQ_COLON },
324 { "Content-Disposition" , RFC_CONTENT_DISPOSITION , KCRQ_COLON },
325 { "Content-ID" , RFC_CONTENT_ID , KCRQ_COLON },
326 { "Content-Length" , RFC_CONTENT_LENGTH , KCRQ_COLON },
327 { "Content-Transfer-Encoding" , RFC_CONTENT_TRANSFER_ENCODING , KCRQ_COLON },
328 { "Content-Type" , RFC_CONTENT_TYPE , KCRQ_COLON },
329 { "Control" , RFC_CONTROL , KCRQ_COLON },
330 { "Date" , RFC_DATE , KCRQ_COLON },
331 { "Delivered-To" , RFC_DELIVERED_TO , KCRQ_COLON },
332 { "Delivery-Date" , RFC_DELIVERY_DATE , KCRQ_COLON },
333 { "Distribution" , RFC_DISTRIBUTION , KCRQ_COLON },
334 { "Encrypted" , RFC_ENCRYPTED , KCRQ_COLON },
335 { "Errors-To" , RFC_ERRORS_TO , KCRQ_COLON },
336 { "Expires" , RFC_EXPIRES , KCRQ_COLON },
337 { "Followup-To" , RFC_FOLLOWUP_TO , KCRQ_COLON },
338 { "From" , RFC_FROM , KCRQ_COLON },
339 { "From" , RFC_FROMX , KCRQ_NONE },
340 { "In-Reply-To" , RFC_IN_REPLY_TO , KCRQ_COLON },
341 { "Keywords" , RFC_KEYWORDS , KCRQ_COLON },
342 { "Lines" , RFC_LINES , KCRQ_COLON },
343 { "Message-ID" , RFC_MESSAGE_ID , KCRQ_COLON },
344 { "Mailing-List" , RFC_MAILING_LIST , KCRQ_COLON },
345 { "MIME-Version" , RFC_MIME_VERSION , KCRQ_COLON },
346 { "Newsgroups" , RFC_NEWSGROUPS , KCRQ_COLON },
347 { "News-Software" , RFC_NEWS_SOFTWARE , KCRQ_COLON },
348 { "NNTP-Posting-Date" , RFC_NNTP_POSTING_DATE , KCRQ_COLON },
349 { "NNTP-Posting-Host" , RFC_NNTP_POSTING_HOST , KCRQ_COLON },
350 { "NNTP-Posting-User" , RFC_NNTP_POSTING_USER , KCRQ_COLON },
351 { "Old-Date" , RFC_OLD_DATE , KCRQ_COLON },
352 { "Organization" , RFC_ORGANIZATION , KCRQ_COLON },
353 { "Originator" , RFC_ORIGINATOR , KCRQ_COLON },
354 { "Path" , RFC_PATH , KCRQ_COLON },
355 { "Precedence" , RFC_PRECEDENCE , KCRQ_COLON },
356 { "Priority" , RFC_PRIORITY , KCRQ_COLON },
357 { "Received" , RFC_RECEIVED , KCRQ_COLON },
358 { "References" , RFC_REFERENCES , KCRQ_COLON },
359 { "Reply-To" , RFC_REPLY_TO , KCRQ_COLON },
360 { "Return-Path" , RFC_RETURN_PATH , KCRQ_COLON },
361 { "Return-Receipt-To" , RFC_RETURN_RECEIPT_TO , KCRQ_COLON },
362 { "See-Also" , RFC_SEE_ALSO , KCRQ_COLON },
363 { "Sender" , RFC_SENDER , KCRQ_COLON },
364 { "Status" , RFC_STATUS , KCRQ_COLON },
365 { "Subject" , RFC_SUBJECT , KCRQ_COLON },
366 { "Summary" , RFC_SUMMARY , KCRQ_COLON },
367 { "Supersedes" , RFC_SUPERSEDES , KCRQ_COLON },
368 { "To" , RFC_TO , KCRQ_COLON },
369 { "Version" , RFC_VERSION , KCRQ_COLON },
370 { "Xref" , RFC_XREF , KCRQ_COLON },
371 { "X-Charset" , RFC_X_CHARSET , KCRQ_COLON },
372 { "X-Char-Esc" , RFC_X_CHAR_ESC , KCRQ_COLON },
373 { "X-FTN-To" , RFC_X_FTN_TO , KCRQ_COLON },
374 { "X-Mailer" , RFC_X_MAILER , KCRQ_COLON },
375 { "X-Mailreader" , RFC_X_MAILER , KCRQ_COLON },
376 { "X-Newsreader" , RFC_X_NEWSREADER , KCRQ_COLON },
377 { "X-To" , RFC_X_TO , KCRQ_COLON },
378 { "#!" , RFC_RNEWS , KCRQ_NONE },
379 { "" , RFC_ZZZZ , KCRQ_NONE },
380 };
381
382
mime_header_decode(char * decoded,const char * encoded,char * charset)383 char* mime_header_decode(char* decoded, const char* encoded, char *charset) {
384
385 char dbuf[200], cbuf[100], ebuf[50], tbuf[200];
386 char* dptr = decoded;
387 const char* eptr = encoded;
388 if(charset) *charset = NUL;
389 while(*eptr) {
390 if(*eptr == '=') {
391 const char* mptr = mime_crack_encoded_word(eptr, cbuf, ebuf, tbuf);
392 if(mptr) {
393 if(charset) {
394 strxcpy(charset, cbuf, 100);
395 charset = NULL;
396 }
397 bool okay = false;
398 strchg(tbuf, '_', ' ');
399 if(strieql(ebuf, "Q")) {
400 quoted_printable_engine qb;
401 qb.decode(dbuf, tbuf);
402 dptr = stpcpy(dptr, dbuf);
403 okay = true;
404 }
405 else if(strieql(ebuf, "B")) {
406 base64_engine b64;
407 b64.decode(dbuf, tbuf);
408 dptr = stpcpy(dptr, dbuf);
409 okay = true;
410 }
411 if(okay) {
412 eptr = mptr;
413 mptr = strskip_lwsp(mptr);
414 if(mime_crack_encoded_word(mptr, cbuf, ebuf, tbuf))
415 eptr = mptr;
416 continue;
417 }
418 }
419 }
420 *dptr++ = *eptr++;
421 }
422 *dptr = NUL;
423
424 return decoded;
425 }
426
427
428 // ------------------------------------------------------------------
429
strxmimecpy(char * dest,const char * source,int level,int size,bool detect)430 char* strxmimecpy(char* dest, const char* source, int level, int size, bool detect) {
431
432 ISub buf, buf2;
433 char charset[100];
434 int table = -1;
435
436 strxcpy(buf, source, sizeof(buf));
437 mime_header_decode(buf2, buf, charset);
438
439 if(charset[0] == NUL)
440 detect = false;
441
442 if(detect) {
443 table = LoadCharset(NULL, NULL, 1);
444 level = LoadCharset(charset, CFG->xlatlocalset);
445 if(not level) {
446 level = LoadCharset(AA->Xlatimport(), CFG->xlatlocalset);
447 }
448 }
449
450 XlatStr(buf, buf2, level, CharTable);
451
452 if(detect) {
453 if(table == -1)
454 LoadCharset("N/A", "N/A");
455 else
456 LoadCharset(CFG->xlatcharset[table].imp, CFG->xlatcharset[table].exp);
457 }
458
459 strxcpy(dest, buf, size);
460
461 return dest;
462 }
463
464
465 // ------------------------------------------------------------------
466
KludgeAREA(GMsg * msg,const char * echoid)467 static void KludgeAREA(GMsg* msg, const char* echoid) {
468
469 if(AA->Usearea()) {
470 Area* ap = AL.AreaEchoToPtr(echoid);
471 if(ap)
472 msg->areakludgeid = ap->echoid();
473 }
474 }
475
476
477 // ------------------------------------------------------------------
478
KludgeINTL(GMsg * msg,const char * ptr)479 static void KludgeINTL(GMsg* msg, const char* ptr) {
480
481 char buf1[201], buf2[201];
482 word fmpt = msg->orig.point;
483 word topt = msg->dest.point;
484 sscanf(ptr, "%s %s", buf1, buf2);
485 msg->dest.set(buf1);
486 msg->orig.set(buf2);
487 msg->orig.point = fmpt;
488 msg->dest.point = topt;
489 }
490
491
492 // ------------------------------------------------------------------
493
KludgeFMPT(GMsg * msg,const char * ptr)494 static void KludgeFMPT(GMsg* msg, const char* ptr) {
495
496 msg->orig.point = atow(ptr);
497 }
498
499
500 // ------------------------------------------------------------------
501
KludgeTOPT(GMsg * msg,const char * ptr)502 static void KludgeTOPT(GMsg* msg, const char* ptr) {
503
504 msg->dest.point = atow(ptr);
505 }
506
507
508 // ------------------------------------------------------------------
509
KludgeMSGID(GMsg * msg,const char * ptr)510 static void KludgeMSGID(GMsg* msg, const char* ptr) {
511
512 strxcpy(msg->msgids, ptr, sizeof(msg->msgids));
513 msg->msgid.reset(msg->msgids, msg->odom);
514 }
515
516
517 // ------------------------------------------------------------------
518
KludgeREPLY(GMsg * msg,const char * ptr)519 static void KludgeREPLY(GMsg* msg, const char* ptr) {
520
521 strxcpy(msg->replys, ptr, sizeof(msg->replys));
522 }
523
524
525 // ------------------------------------------------------------------
526
KludgeDOMAIN(GMsg * msg,const char * ptr)527 static void KludgeDOMAIN(GMsg* msg, const char* ptr) {
528
529 char buf1[201], buf2[201];
530 sscanf(ptr, "%s %s %s %s", msg->ddom, buf1, msg->odom, buf2);
531 msg->dest.reset(buf1);
532 msg->orig.reset(buf2);
533 }
534
535
536 // ------------------------------------------------------------------
537
KludgeFLAGS(GMsg * msg,const char * ptr)538 static void KludgeFLAGS(GMsg* msg, const char* ptr) {
539
540 GetAttribstr(&msg->attr, ptr);
541 }
542
543
544 // ------------------------------------------------------------------
545
KludgeMSGTO(GMsg * msg,const char * ptr)546 static void KludgeMSGTO(GMsg* msg, const char* ptr) {
547
548 msg->dest.reset(ptr, msg->ddom);
549 }
550
551
552 // ------------------------------------------------------------------
553
KludgePID(GMsg * msg,const char * ptr)554 static void KludgePID(GMsg* msg, const char* ptr) {
555
556 strxcpy(msg->pid, ptr, sizeof(msg->pid));
557
558 if(CFG->gedhandshake) {
559 // Recognize another GoldED msg
560 if(striinc(__gver_name__, ptr) or striinc(__gver_shortname__, ptr))
561 goldmark = GOLDMARK;
562 }
563 }
564
565
566 // ------------------------------------------------------------------
567
KludgeREPLYADDR(GMsg * msg,const char * ptr)568 static void KludgeREPLYADDR(GMsg* msg, const char* ptr) {
569
570 INam name;
571 char *buf=throw_strdup(ptr);
572 *name = NUL;
573 ParseInternetAddr(buf, *msg->realby ? name : msg->realby, msg->iaddr);
574 if(*name)
575 strxcpy(msg->realby, name, sizeof(INam));
576 throw_free(buf);
577 }
578
579
580 // ------------------------------------------------------------------
581
KludgeREPLYTO(GMsg * msg,const char * ptr)582 static void KludgeREPLYTO(GMsg* msg, const char* ptr) {
583
584 strcpy(msg->igate, ptr);
585 }
586
587
588 // ------------------------------------------------------------------
589
KludgeFROM(GMsg * msg,const char * ptr)590 static void KludgeFROM(GMsg* msg, const char* ptr) {
591
592 INam _fromname;
593 IAdr _fromaddr;
594 char* buf = throw_strdup(ptr);
595 strxmimecpy(msg->ifrom, buf, 0, sizeof(msg->ifrom), true);
596 ParseInternetAddr(buf, _fromname, _fromaddr);
597 throw_free(buf);
598 if(*_fromaddr)
599 strcpy(msg->iorig, _fromaddr);
600 if(*_fromname)
601 strxcpy(msg->realby, _fromname, sizeof(msg->realby));
602 }
603
604
605 // ------------------------------------------------------------------
606
KludgeTO(GMsg * msg,const char * ptr)607 static void KludgeTO(GMsg* msg, const char* ptr) {
608
609 INam _toname;
610 IAdr _toaddr;
611 char* buf = throw_strdup(ptr);
612 strxmimecpy(msg->ito, buf, 0, sizeof(msg->ito), true);
613 ParseInternetAddr(buf, _toname, _toaddr);
614 throw_free(buf);
615 if(*_toaddr)
616 strcpy(msg->idest, _toaddr);
617 if(*_toname)
618 strxcpy(msg->realto, _toname, sizeof(msg->realto));
619 }
620
621
622 // ------------------------------------------------------------------
623
KludgeBCC(GMsg * msg,const char * ptr)624 static void KludgeBCC(GMsg* msg, const char* ptr) {
625
626 INam _toname;
627 IAdr _toaddr, buf;
628
629 gstrarray bccs;
630 tokenize(bccs, ptr, ",");
631 for(int i=0; i < bccs.size(); i++) {
632 strxcpy(buf, strskip_wht(bccs[i].c_str()), sizeof(IAdr));
633 ParseInternetAddr(buf, _toname, _toaddr);
634 if(*_toaddr and not striinc(_toaddr, msg->ibcc)) {
635 if(*msg->ibcc)
636 strxcat(msg->ibcc, ", ", sizeof(msg->ibcc));
637 if(_toname[0] != NUL) {
638 IAdr buf2;
639 mime_header_encode(buf2, _toname, msg);
640 char quot[2] = "\"";
641 if ((buf2[0] == '\"') or (strpbrk(buf2, " \t") == NULL))
642 quot[0] = NUL;
643 gsprintf(PRINTF_DECLARE_BUFFER(buf), "%s%s%s <%s>", quot, buf2, quot, _toaddr);
644 }
645 else
646 gsprintf(PRINTF_DECLARE_BUFFER(buf), "%s", _toaddr);
647
648 strxcat(msg->ibcc, buf, sizeof(msg->ibcc));
649 }
650 }
651 }
652
653
654 // ------------------------------------------------------------------
655
KludgeCC(GMsg * msg,const char * ptr)656 static void KludgeCC(GMsg* msg, const char* ptr) {
657
658 INam _toname;
659 IAdr _toaddr, buf;
660
661 gstrarray ccs;
662 tokenize(ccs, ptr, ",");
663 for(int i=0; i < ccs.size(); i++) {
664 strxcpy(buf, strskip_wht(ccs[i].c_str()), sizeof(IAdr));
665 ParseInternetAddr(buf, _toname, _toaddr);
666 if(*_toaddr and not striinc(_toaddr, msg->icc)) {
667 if(*msg->icc)
668 strxcat(msg->icc, ", ", sizeof(msg->icc));
669 if(_toname[0] != NUL) {
670 IAdr buf2;
671 mime_header_encode(buf2, _toname, msg);
672 char quot[2] = "\"";
673 if ((buf[0] == '\"') or (strpbrk(buf2, " \t") == NULL))
674 quot[0] = NUL;
675 gsprintf(PRINTF_DECLARE_BUFFER(buf), "%s%s%s <%s>", quot, buf2, quot, _toaddr);
676 }
677 else
678 gsprintf(PRINTF_DECLARE_BUFFER(buf), "%s", _toaddr);
679
680 strxcat(msg->icc, buf, sizeof(msg->icc));
681 }
682 }
683 }
684
685
686 // ------------------------------------------------------------------
687
KludgeREPLY_TO(GMsg * msg,const char * ptr)688 static void KludgeREPLY_TO(GMsg* msg, const char* ptr) {
689
690 INam _rtname;
691 IAdr _rtaddr;
692 char *buf=throw_strdup(ptr);
693 ParseInternetAddr(buf, _rtname, _rtaddr);
694 throw_free(buf);
695 if(*_rtaddr)
696 strcpy(msg->ireplyto, _rtaddr);
697 }
698
699
700 // ------------------------------------------------------------------
701
KludgeSUBJECT(GMsg * msg,const char * ptr)702 static void KludgeSUBJECT(GMsg* msg, const char* ptr) {
703
704 if(not (msg->attr.frq() or msg->attr.att() or msg->attr.urq()))
705 strxmimecpy(msg->re, ptr, 0, sizeof(msg->re), true);
706 }
707
708
709 // ------------------------------------------------------------------
710
KludgeTZUTC(GMsg * msg,const char * ptr)711 static void KludgeTZUTC(GMsg* msg, const char* ptr) {
712
713 msg->tzutc = atoi(ptr);
714 }
715
716
717 // ------------------------------------------------------------------
718
KludgeDATE(GMsg * msg,const char * ptr)719 void KludgeDATE(GMsg* msg, const char* ptr) {
720
721 // RFC822 Date: BNF
722 //
723 // date-time = [ day "," ] date time ; dd mm yy
724 // ; hh:mm:ss zzz
725 //
726 // day = "Mon" / "Tue" / "Wed" / "Thu"
727 // / "Fri" / "Sat" / "Sun"
728 //
729 // date = 1*2DIGIT month 2DIGIT ; day month year
730 // ; e.g. 20 Jun 82
731 //
732 // month = "Jan" / "Feb" / "Mar" / "Apr"
733 // / "May" / "Jun" / "Jul" / "Aug"
734 // / "Sep" / "Oct" / "Nov" / "Dec"
735 //
736 // time = hour zone ; ANSI and Military
737 //
738 // hour = 2DIGIT ":" 2DIGIT [":" 2DIGIT]
739 // ; 00:00:00 - 23:59:59
740 //
741 // zone = "UT" / "GMT" ; Universal Time
742 // ; North American : UT
743 // / "EST" / "EDT" ; Eastern: - 5/ - 4
744 // / "CST" / "CDT" ; Central: - 6/ - 5
745 // / "MST" / "MDT" ; Mountain: - 7/ - 6
746 // / "PST" / "PDT" ; Pacific: - 8/ - 7
747 // / 1ALPHA ; Military: Z = UT;
748 // ; A:-1; (J not used)
749 // ; M:-12; N:+1; Y:+12
750 // / ( ("+" / "-") 4DIGIT ) ; Local differential
751 // ; hours+min. (HHMM)
752
753 bool date_ok = false;
754 int year=0, month=0, day=0;
755 int hour=0, minute=0, second=0;
756
757 ptr = strskip_wht(ptr);
758 if(not isdigit(*ptr)) {
759 // Skip past weekday string
760 ptr = strskip_wht(strskip_txt(ptr));
761 }
762 if(*ptr) {
763 if(isdigit(*ptr)) {
764 day = atoi(ptr);
765 ptr = strskip_wht(strskip_txt(ptr));
766 if(g_isalpha(*ptr)) {
767 month = str2mon(ptr);
768 if(month) {
769 ptr = strskip_wht(strskip_txt(ptr));
770 if(isdigit(*ptr)) {
771 year = atoi(ptr);
772 ptr = strskip_wht(strskip_txt(ptr));
773 if(isdigit(*ptr)) {
774 hour = atoi(ptr);
775 ptr = strskip_digits(ptr);
776 if(*ptr and isdigit(ptr[1])) {
777 minute = atoi(++ptr);
778 date_ok = true;
779 // The seconds part is optional
780 ptr = strskip_digits(ptr);
781 if(*ptr and isdigit(ptr[1])) {
782 second = atoi(++ptr);
783 // Setting timezone
784 ptr = strskip_wht(strskip_digits(ptr));
785 if(*ptr) {
786 if(*ptr == '(' /*)*/ ) ++ptr;
787 msg->tzutc = atoi(ptr);
788 }
789 }
790 }
791 }
792 }
793 }
794 }
795 }
796 }
797
798 if (date_ok)
799 {
800 struct tm t;
801 t.tm_year = (year < 80) ? (year+100) : (year > 1900) ? (year-1900) : year;
802 t.tm_mon = month - 1;
803 t.tm_mday = day;
804 t.tm_hour = hour;
805 t.tm_min = minute;
806 t.tm_sec = second;
807 t.tm_isdst = -1;
808 time32_t a = gmktime(&t);
809 struct tm tp; ggmtime(&tp, &a);
810 tp.tm_isdst = -1;
811 time32_t b = gmktime(&tp);
812 msg->written = a + a - b;
813 }
814 }
815
816
817 // ------------------------------------------------------------------
818
KludgeMESSAGE_ID(GMsg * msg,const char * ptr)819 static void KludgeMESSAGE_ID(GMsg* msg, const char* ptr) {
820
821 char buf[201];
822 throw_free(msg->messageid);
823 msg->messageid = throw_strdup(ptr);
824 CvtMessageIDtoMSGID(ptr, buf, AA->echoid(), "MSGID");
825 strcpy(msg->msgids, buf+8);
826 }
827
828
829 // ------------------------------------------------------------------
830
KludgeREFERENCES(GMsg * msg,const char * ptr)831 static void KludgeREFERENCES(GMsg* msg, const char* ptr) {
832
833 throw_free(msg->references);
834 msg->references = throw_strdup(ptr);
835 }
836
837
838 // ------------------------------------------------------------------
839
KludgeIN_REPLY_TO(GMsg * msg,const char * ptr)840 static void KludgeIN_REPLY_TO(GMsg* msg, const char* ptr) {
841
842 throw_free(msg->inreplyto);
843 msg->inreplyto = throw_strdup(ptr);
844 }
845
846
847 // ------------------------------------------------------------------
848
KludgeORGANIZATION(GMsg * msg,const char * ptr)849 static void KludgeORGANIZATION(GMsg* msg, const char* ptr) {
850
851 strxcpy(msg->organization, ptr, sizeof(msg->organization));
852 }
853
854
855 // ------------------------------------------------------------------
856
KludgeX_FTN_TO(GMsg * msg,const char * ptr)857 static void KludgeX_FTN_TO(GMsg* msg, const char* ptr) {
858
859 strxmimecpy(msg->realto, ptr, 0, sizeof(msg->realto), true);
860 }
861
862
863 // ------------------------------------------------------------------
864
KludgeFWDFROM(GMsg * msg,const char * ptr)865 static void KludgeFWDFROM(GMsg* msg, const char* ptr) {
866
867 if(AA->Usefwd())
868 strxcpy(msg->fwdfrom, ptr, sizeof(msg->fwdfrom));
869 }
870
871
872 // ------------------------------------------------------------------
873
KludgeFWDORIG(GMsg * msg,const char * ptr)874 static void KludgeFWDORIG(GMsg* msg, const char* ptr) {
875
876 if(AA->Usefwd())
877 msg->fwdorig.reset(ptr);
878 }
879
880
881 // ------------------------------------------------------------------
882
KludgeFWDTO(GMsg * msg,const char * ptr)883 static void KludgeFWDTO(GMsg* msg, const char* ptr) {
884
885 if(AA->Usefwd())
886 strxcpy(msg->fwdto, ptr, sizeof(msg->fwdto));
887 }
888
889
890 // ------------------------------------------------------------------
891
KludgeFWDDEST(GMsg * msg,const char * ptr)892 static void KludgeFWDDEST(GMsg* msg, const char* ptr) {
893
894 if(AA->Usefwd())
895 msg->fwddest.reset(ptr);
896 }
897
898
899 // ------------------------------------------------------------------
900
KludgeFWDSUBJ(GMsg * msg,const char * ptr)901 static void KludgeFWDSUBJ(GMsg* msg, const char* ptr) {
902
903 if(AA->Usefwd())
904 strxcpy(msg->fwdsubj, ptr, sizeof(msg->fwdsubj));
905 }
906
907
908 // ------------------------------------------------------------------
909
KludgeFWDAREA(GMsg * msg,const char * ptr)910 static void KludgeFWDAREA(GMsg* msg, const char* ptr) {
911
912 if(AA->Usefwd())
913 strxcpy(msg->fwdarea, ptr, sizeof(msg->fwdarea));
914 }
915
916
917 // ------------------------------------------------------------------
918
KludgeFWDMSGID(GMsg * msg,const char * ptr)919 static void KludgeFWDMSGID(GMsg* msg, const char* ptr) {
920
921 if(AA->Usefwd())
922 strxcpy(msg->fwdmsgid, ptr, sizeof(msg->fwdmsgid));
923 }
924
925
926 // ------------------------------------------------------------------
927
UnwrapLine(Line * line,const char * ptr,int addspace=false)928 char* UnwrapLine(Line* line, const char* ptr, int addspace = false) {
929
930 if(line->type & GLINE_WRAP) {
931 uint len = strlen(ptr);
932 char* uptr = throw_strdup(ptr);
933 while(line and (line->type & GLINE_WRAP)) {
934 if(line->next) {
935 uint nextlen = line->next->txt.length();
936 uptr = (char*)throw_realloc(uptr, len+nextlen+2);
937 if(addspace and len and (uptr[len-1] != ' ')) {
938 strcat(uptr, " ");
939 len++;
940 }
941 strcpy(uptr+len, line->next->txt.c_str());
942 len += nextlen;
943 }
944 line = line->next;
945 }
946 return uptr;
947 }
948
949 return NULL;
950 }
951
952
953 // ------------------------------------------------------------------
954
HandleKludges(GMsg * msg,Line * line,int kludgenum,const char * ptr,int getvalue)955 static int HandleKludges(GMsg* msg, Line* line, int kludgenum, const char* ptr, int getvalue) {
956
957 switch(kludgenum) {
958
959 case FTS_AREA:
960 line->kludge = GKLUD_AREA;
961 if(getvalue)
962 KludgeAREA(msg, ptr);
963 return true;
964
965 case FTS_INTL:
966 line->kludge = GKLUD_INTL;
967 if(getvalue)
968 KludgeINTL(msg, ptr);
969 return true;
970
971 case FTS_FMPT:
972 line->kludge = GKLUD_FMPT;
973 if(getvalue)
974 KludgeFMPT(msg, ptr);
975 return true;
976
977 case FTS_TOPT:
978 line->kludge = GKLUD_TOPT;
979 if(getvalue)
980 KludgeTOPT(msg, ptr);
981 return true;
982
983 case FTS_MSGID:
984 line->kludge = GKLUD_MSGID;
985 if(getvalue) {
986 char* tmp = UnwrapLine(line, ptr);
987 KludgeMSGID(msg, tmp ? tmp : ptr);
988 if(tmp)
989 throw_free(tmp);
990 }
991 return true;
992
993 case FTS_REPLY:
994 line->kludge = GKLUD_REPLY;
995 if(getvalue) {
996 char* tmp = UnwrapLine(line, ptr);
997 KludgeREPLY(msg, tmp ? tmp : ptr);
998 if(tmp)
999 throw_free(tmp);
1000 }
1001 return true;
1002
1003 case FTS_SEENBY:
1004 line->kludge = GKLUD_SEENBY;
1005 return true;
1006
1007 case FTS_PATH:
1008 line->kludge = GKLUD_PATH;
1009 return true;
1010
1011 ////////////////////////////////////////////////////////////
1012
1013 case FSC_CHARSET:
1014 line->kludge = GKLUD_CHARSET;
1015 return true;
1016
1017 case FSC_CHRS:
1018 line->kludge = GKLUD_CHARSET;
1019 return true;
1020
1021 case FSC_CODEPAGE:
1022 line->kludge = GKLUD_CHARSET;
1023 return true;
1024
1025 case FSC_DOMAIN:
1026 //line->kludge = GKLUD_DOMAIN;
1027 if(getvalue)
1028 KludgeDOMAIN(msg, ptr);
1029 return true;
1030
1031 case FSC_ENCLFILE:
1032 if(getvalue)
1033 strxcpy(msg->re, ptr, sizeof(msg->re));
1034 return true;
1035
1036 case FSC_FLAGS:
1037 line->kludge = GKLUD_FLAGS;
1038 if(getvalue)
1039 KludgeFLAGS(msg, ptr);
1040 return true;
1041
1042 case FSC_I51:
1043 line->kludge = GKLUD_CHARSET;
1044 msg->i51 = true;
1045 return true;
1046
1047 case FSC_MSGTO:
1048 //line->kludge = GKLUD_MSGTO;
1049 if(getvalue)
1050 KludgeMSGTO(msg, ptr);
1051 return true;
1052
1053 case FSC_PID:
1054 line->kludge = GKLUD_PID;
1055 if(getvalue)
1056 KludgePID(msg, ptr);
1057 return true;
1058
1059 case FSC_REPLYADDR:
1060 line->kludge = GKLUD_REPLYADDR;
1061 if(getvalue)
1062 KludgeREPLYADDR(msg, ptr);
1063 return true;
1064
1065 case FSC_REPLYTO:
1066 line->kludge = GKLUD_REPLYTO;
1067 if(getvalue)
1068 KludgeREPLYTO(msg, ptr);
1069 return true;
1070
1071 case FSC_FWDFROM:
1072 line->kludge = GKLUD_FWD;
1073 if(getvalue)
1074 KludgeFWDFROM(msg, ptr);
1075 return true;
1076
1077 case FSC_FWDORIG:
1078 line->kludge = GKLUD_FWD;
1079 if(getvalue)
1080 KludgeFWDORIG(msg, ptr);
1081 return true;
1082
1083 case FSC_FWDTO:
1084 line->kludge = GKLUD_FWD;
1085 if(getvalue)
1086 KludgeFWDTO(msg, ptr);
1087 return true;
1088
1089 case FSC_FWDDEST:
1090 line->kludge = GKLUD_FWD;
1091 if(getvalue)
1092 KludgeFWDDEST(msg, ptr);
1093 return true;
1094
1095 case FSC_FWDSUBJ:
1096 line->kludge = GKLUD_FWD;
1097 if(getvalue)
1098 KludgeFWDSUBJ(msg, ptr);
1099 return true;
1100
1101 case FSC_FWDAREA:
1102 line->kludge = GKLUD_FWD;
1103 if(getvalue)
1104 KludgeFWDAREA(msg, ptr);
1105 return true;
1106
1107 case FSC_FWDMSGID:
1108 line->kludge = GKLUD_FWD;
1109 if(getvalue)
1110 KludgeFWDMSGID(msg, ptr);
1111 return true;
1112
1113 case FSC_CHRC:
1114 case FSC_EID:
1115 case FSC_ENC:
1116 case FSC_PTH:
1117 case FSC_SPLIT:
1118 case FSC_SPTH:
1119 case FSC_TID:
1120 // Recognized but not processed
1121 return true;
1122
1123 ////////////////////////////////////////////////////////////
1124
1125 case XXX_DESTADDR:
1126 //line->kludge = GKLUD_DESTADDR;
1127 if(getvalue)
1128 KludgeMSGTO(msg, ptr);
1129 return true;
1130
1131 case XXX_TZUTCINFO:
1132 case XXX_TZUTC:
1133 line->kludge = GKLUD_KNOWN;
1134 if(getvalue)
1135 KludgeTZUTC(msg, ptr);
1136 return true;
1137
1138 case XXX_ACUPDATE:
1139 case XXX_ENCRYPTION:
1140 case XXX_EOT:
1141 case XXX_GATECHK:
1142 case XXX_GID:
1143 case XXX_GIF:
1144 case XXX_GMD:
1145 case XXX_GROUP:
1146 case XXX_MOOD:
1147 case XXX_MSGSEQ:
1148 case XXX_NOTE:
1149 case XXX_ORIGID:
1150 case XXX_ORIGINAL:
1151 case XXX_ORIGREF:
1152 case XXX_RECD:
1153 case XXX_RFC:
1154 case XXX_RFD:
1155 case XXX_RID:
1156 case XXX_ROUTE:
1157 case XXX_SN:
1158 case XXX_SOT:
1159 case XXX_TCL1:
1160 case XXX_TCL2:
1161 case XXX_TZ:
1162 case XXX_VIA:
1163 case XXX_XID:
1164 // Recognized but not processed
1165 return true;
1166 }
1167
1168 return false;
1169 }
1170
1171
1172 // ------------------------------------------------------------------
1173
HandleRFCs(GMsg * msg,Line * line,int kludgenum,const char * ptr,int getvalue)1174 int HandleRFCs(GMsg* msg, Line* line, int kludgenum, const char* ptr, int getvalue) {
1175
1176 switch(kludgenum) {
1177
1178 case RFC_FROM:
1179 line->kludge = GKLUD_RFC;
1180 if(getvalue) {
1181 char* tmp = UnwrapLine(line, ptr);
1182 KludgeFROM(msg, tmp ? tmp : ptr);
1183 if(tmp)
1184 throw_free(tmp);
1185 }
1186 return true;
1187
1188 case RFC_TO:
1189 case RFC_X_TO:
1190 line->kludge = GKLUD_RFC;
1191 if(getvalue) {
1192 char* tmp = UnwrapLine(line, ptr);
1193 KludgeTO(msg, tmp ? tmp : ptr);
1194 if(tmp)
1195 throw_free(tmp);
1196 }
1197 return true;
1198
1199 case RFC_BCC:
1200 line->kludge = GKLUD_RFC;
1201 if(true /* getvalue */) {
1202 char* tmp = UnwrapLine(line, ptr);
1203 KludgeBCC(msg, tmp ? tmp : ptr);
1204 if(tmp)
1205 throw_free(tmp);
1206 }
1207 return true;
1208
1209 case RFC_CC:
1210 line->kludge = GKLUD_RFC;
1211 if(true /* getvalue */) {
1212 char* tmp = UnwrapLine(line, ptr);
1213 KludgeCC(msg, tmp ? tmp : ptr);
1214 if(tmp)
1215 throw_free(tmp);
1216 }
1217 return true;
1218
1219 case RFC_DATE:
1220 line->kludge = GKLUD_RFC;
1221 if(getvalue)
1222 KludgeDATE(msg, ptr);
1223 return true;
1224
1225 case RFC_SUBJECT:
1226 line->kludge = GKLUD_RFC;
1227 if(getvalue) {
1228 char* tmp = UnwrapLine(line, ptr);
1229 KludgeSUBJECT(msg, tmp ? tmp : ptr);
1230 if(tmp)
1231 throw_free(tmp);
1232 }
1233 return true;
1234
1235 case RFC_REPLY_TO:
1236 line->kludge = GKLUD_RFC;
1237 if(getvalue) {
1238 char* tmp = UnwrapLine(line, ptr);
1239 KludgeREPLY_TO(msg, tmp ? tmp : ptr);
1240 if(tmp)
1241 throw_free(tmp);
1242 }
1243 return true;
1244
1245 case RFC_MESSAGE_ID:
1246 line->kludge = GKLUD_RFC;
1247 if(getvalue) {
1248 char* tmp = UnwrapLine(line, ptr);
1249 KludgeMESSAGE_ID(msg, tmp ? tmp : ptr);
1250 if(tmp)
1251 throw_free(tmp);
1252 }
1253 return true;
1254
1255 case RFC_REFERENCES:
1256 line->kludge = GKLUD_RFC;
1257 if(getvalue) {
1258 char* tmp = UnwrapLine(line, ptr);
1259 KludgeREFERENCES(msg, tmp ? tmp : ptr);
1260 if(tmp)
1261 throw_free(tmp);
1262 }
1263 return true;
1264
1265 case RFC_IN_REPLY_TO:
1266 line->kludge = GKLUD_RFC;
1267 if(getvalue) {
1268 char* tmp = UnwrapLine(line, ptr);
1269 KludgeIN_REPLY_TO(msg, tmp ? tmp : ptr);
1270 if(tmp)
1271 throw_free(tmp);
1272 }
1273 return true;
1274
1275 case RFC_ORGANIZATION:
1276 line->kludge = GKLUD_RFC;
1277 if(getvalue)
1278 KludgeORGANIZATION(msg, ptr);
1279 return true;
1280
1281 case RFC_X_FTN_TO:
1282 line->kludge = GKLUD_RFC;
1283 if(getvalue)
1284 KludgeX_FTN_TO(msg, ptr);
1285 return true;
1286
1287 case RFC_X_MAILER:
1288 line->kludge = GKLUD_RFC;
1289 if(getvalue)
1290 KludgePID(msg, ptr);
1291 return true;
1292
1293 case RFC_X_NEWSREADER:
1294 line->kludge = GKLUD_RFC;
1295 if(getvalue)
1296 KludgePID(msg, ptr);
1297 return true;
1298
1299 case RFC_NEWSGROUPS:
1300 case RFC_SENDER:
1301 case RFC_CONTENT_TRANSFER_ENCODING:
1302 case RFC_CONTENT_TYPE:
1303 case RFC_MIME_VERSION:
1304 case RFC_X_CHARSET:
1305 case RFC_X_CHAR_ESC:
1306 // Mark RFC's that we add ourselves
1307 line->kludge = GKLUD_RFC;
1308 return true;
1309
1310 case RFC_ALSO_CONTROL:
1311 case RFC_APPARENTLY_TO:
1312 case RFC_APPROVED:
1313 case RFC_ARTICLE_NAMES:
1314 case RFC_ARTICLE_UPDATES:
1315 case RFC_COMMENT:
1316 case RFC_COMMENTS:
1317 case RFC_CONTENT_DESCRIPTION:
1318 case RFC_CONTENT_DISPOSITION:
1319 case RFC_CONTENT_ID:
1320 case RFC_CONTENT_LENGTH:
1321 case RFC_CONTROL:
1322 case RFC_DELIVERED_TO:
1323 case RFC_DELIVERY_DATE:
1324 case RFC_DISTRIBUTION:
1325 case RFC_ENCRYPTED:
1326 case RFC_ERRORS_TO:
1327 case RFC_EXPIRES:
1328 case RFC_FOLLOWUP_TO:
1329 case RFC_FROMX:
1330 case RFC_KEYWORDS:
1331 case RFC_LINES:
1332 case RFC_MAILING_LIST:
1333 case RFC_NEWS_SOFTWARE:
1334 case RFC_NNTP_POSTING_DATE:
1335 case RFC_NNTP_POSTING_HOST:
1336 case RFC_NNTP_POSTING_USER:
1337 case RFC_OLD_DATE:
1338 case RFC_ORIGINATOR:
1339 case RFC_PATH:
1340 case RFC_PRECEDENCE:
1341 case RFC_PRIORITY:
1342 case RFC_RECEIVED:
1343 case RFC_RETURN_PATH:
1344 case RFC_RETURN_RECEIPT_TO:
1345 case RFC_SEE_ALSO:
1346 case RFC_STATUS:
1347 case RFC_SUMMARY:
1348 case RFC_SUPERSEDES:
1349 case RFC_VERSION:
1350 case RFC_XREF:
1351 case RFC_RNEWS:
1352 // Recognized but not processed
1353 return true;
1354 }
1355
1356 return false;
1357 }
1358
1359
1360 // ------------------------------------------------------------------
1361
ScanCtrlList(const Kludges * k,const char * kludge,char endchar)1362 int ScanCtrlList(const Kludges *k, const char *kludge, char endchar) {
1363
1364 while(*k->key) {
1365 if((k->req & KCRQ_CASE) ? streql(kludge, k->key) : strieql(kludge, k->key)) {
1366 if(k->req & KCRQ_COLON) {
1367 if(endchar == ':')
1368 return k->num;
1369 }
1370 else {
1371 return k->num;
1372 }
1373 }
1374 k++;
1375 }
1376
1377 return 0;
1378 }
1379
1380
1381 // ------------------------------------------------------------------
1382
ScanLine(GMsg * msg,Line * line,const char * ptr,int getvalue,int mask)1383 int ScanLine(GMsg* msg, Line* line, const char* ptr, int getvalue, int mask) {
1384
1385 // Kludge number
1386 int kludgenum = 0;
1387
1388 // Pointer to kludge id
1389 const char* kludge1 = ptr;
1390
1391 // Skip past "RFC" string, if any
1392 if(strnieql(kludge1, "RFC", 3) and (kludge1[3] != ':')) {
1393 kludge1 += 3;
1394 if(not g_isalpha(*kludge1))
1395 kludge1++;
1396 }
1397
1398 // Keep copy of id terminating char
1399 while((*ptr != ' ') and (*ptr != ':') and *ptr)
1400 ptr++;
1401 char endchar = *ptr;
1402
1403 #if defined(__USE_ALLOCA__)
1404 char *kludge = (char*)alloca(ptr-kludge1+1);
1405 #else
1406 __extension__ char kludge[ptr-kludge1+1];
1407 #endif
1408 strxcpy(kludge, kludge1, ptr-kludge1+1);
1409
1410 // Search for it in the known kludges list
1411 if(*kludge) {
1412 while(1) {
1413 if(mask & MASK_FTS) {
1414 kludgenum = ScanCtrlList(fts_list, kludge, endchar);
1415 if(kludgenum)
1416 break;
1417 }
1418 if(mask & MASK_FSC) {
1419 kludgenum = ScanCtrlList(fsc_list, kludge, endchar);
1420 if(kludgenum)
1421 break;
1422 }
1423 if(mask & MASK_RFC) {
1424 kludgenum = ScanCtrlList(rfc_list, kludge, endchar);
1425 if(kludgenum)
1426 break;
1427 }
1428 if(mask & MASK_XXX) {
1429 kludgenum = ScanCtrlList(xxx_list, kludge, endchar);
1430 if(kludgenum)
1431 break;
1432 }
1433 break;
1434 }
1435 }
1436
1437 // Restore terminating char
1438 if(*ptr != ' ')
1439 ptr++;
1440
1441 if(kludgenum) {
1442 ptr = strskip_wht(ptr);
1443 line->type |= GLINE_KLUD;
1444 if(kludgenum & (MASK_FTS|MASK_FSC|MASK_XXX))
1445 HandleKludges(msg, line, kludgenum, ptr, getvalue);
1446 else if(kludgenum & MASK_RFC)
1447 HandleRFCs(msg, line, kludgenum, ptr, getvalue);
1448 }
1449 else {
1450 gstrarray::iterator k;
1451 for(k = CFG->kludge.begin(); k != CFG->kludge.end(); k++) {
1452 if(strnieql(kludge, k->c_str(), k->length())) {
1453 line->type |= GLINE_KLUD;
1454 kludgenum = USERDEFINED;
1455 break;
1456 }
1457 }
1458 if(not (line->type & GLINE_KLUD))
1459 if((strnieql(kludge, "X-", 2) or strnieql(kludge, "Resent-", 7)) and (endchar == ':') and (mask & MASK_RFC)) {
1460 line->type |= GLINE_KLUD;
1461 kludgenum = RFC_X;
1462 }
1463 if(not (line->type & GLINE_KLUD))
1464 kludgenum = (endchar == ':') ? HEADERLINE : BODYLINE;
1465 }
1466
1467 return kludgenum;
1468 }
1469
1470
1471 // ------------------------------------------------------------------
1472
next_non_empty(Line * line)1473 Line* next_non_empty(Line *line) {
1474 Line* nl = line;
1475
1476 while(nl) {
1477 if(nl->txt.empty())
1478 nl = nl->next;
1479 else
1480 break;
1481 }
1482 return nl;
1483 }
1484
1485 // ------------------------------------------------------------------
1486
ScanKludges(GMsg * msg,int getvalue)1487 void ScanKludges(GMsg* msg, int getvalue) {
1488
1489 const char* ptr;
1490 int tearlineno = INT_MAX;
1491 int originlineno = INT_MAX;
1492 int gotorig=NO, gottear=NO, gottag=NO;
1493
1494 // Scan for kludge-, tear- and originlines
1495
1496 msg->tzutc = -32767; // Default value, means TZUTC kludge was not found
1497
1498 if(getvalue)
1499 goldmark = ' '; // Reset the "recognizer" code
1500
1501 int lineno = 0;
1502 Line* line = LastLine(msg->lin);
1503
1504 do {
1505 ptr = line->txt.c_str();
1506 if(*ptr == CTRL_A) {
1507
1508 // Set kludge/hidden color
1509 line->color = C_READK;
1510
1511 int kludgenum = ScanLine(msg, line, ptr+1, getvalue, MASK_ALL);
1512 if((kludgenum == BODYLINE) or (kludgenum == HEADERLINE)) {
1513 line->type |= GLINE_HIDD;
1514 line->color = C_READKH;
1515 }
1516 }
1517 else {
1518
1519 if(strneql(ptr, "AREA:", 5) and (line->prev == NULL or *line->prev->txt.c_str() == CTRL_A)) {
1520 line->color = C_READK;
1521 line->kludge = GKLUD_AREA;
1522 line->type |= GLINE_KLUD;
1523 const char* areakludgeptr = ptr+5; // Extract echoid from kludge
1524 areakludgeptr = strskip_wht(areakludgeptr);
1525 KludgeAREA(msg, areakludgeptr);
1526 }
1527
1528 if(not (line->type & GLINE_KLUD)) {
1529
1530 // Check if it is a tagline
1531 if(not gottag and (strneql("...", ptr, 3) or strneql("___", ptr, 3))) {
1532
1533 // It's only a tagline if it's just above the tearline or origin.
1534 // Or if it's the last line in the message.
1535 if(not lineno or ((lineno-1) == tearlineno) or ((lineno-1) == originlineno)) {
1536 gottag = YES;
1537 line->type |= GLINE_TAGL;
1538 line->color = C_READG;
1539 if(AA->Taglinesupport())
1540 strbtrim(strxcpy(msg->tagline, ptr+3, sizeof(msg->tagline)));
1541 }
1542 }
1543
1544 // Check if it's a tearline
1545 else if(not (gottear or gottag) and strneql("---", ptr, 3) and (ptr[3] == ' ' or ptr[3] == NUL)) {
1546
1547 Line* tearln = line;
1548 int tearlnno = lineno;
1549 while (tearln->type & GLINE_WRAP) {
1550 tearln = tearln->next;
1551 tearlnno--;
1552 }
1553 Line* nnel = next_non_empty(tearln->next);
1554 if(not tearlnno or ((tearlnno-1) == originlineno) or not nnel or nnel->type & GLINE_KLUDGE) {
1555 // Found Tearline
1556 gottear = YES;
1557 tearlineno = lineno;
1558 for (tearln = line; tearln->type & GLINE_WRAP; tearln = tearln->next) {
1559 tearln->type |= GLINE_TEAR;
1560 tearln->color = C_READT;
1561 }
1562 tearln->type |= GLINE_TEAR;
1563 tearln->color = C_READT;
1564 strbtrim(strxcpy(msg->tearline, ptr+3, sizeof(msg->tearline)));
1565
1566 if(getvalue and CFG->gedhandshake) {
1567 char* tearid[] = {
1568 "GoldED",
1569 " GED ",
1570 " GED2 ",
1571 " GED3 ",
1572 " GED386 ",
1573 " GED/2 ",
1574 " GED/386 ",
1575 " GEDP16 ",
1576 " GEDP32 ",
1577 " GEDW32 ",
1578 " GEDLNX ",
1579 " GED/W32 ",
1580 NULL
1581 };
1582 int n = 0;
1583 while(tearid[n]) {
1584 if(striinc(tearid[n], ptr)) {
1585 goldmark = GOLDMARK; // Recognize another GoldED msg
1586 break;
1587 }
1588 n++;
1589 }
1590 }
1591 }
1592 }
1593
1594 // Check if it's an originline
1595 else if(not (gotorig or gottear or gottag) and strneql(" * Origin: ", ptr, 11)) {
1596
1597 // Found Origin line
1598 bool cnd = line->next != NULL;
1599 Line* nnel = next_non_empty(line->next);
1600 bool nextkl = cnd ? not nnel or nnel->type & GLINE_KLUDGE : false;
1601 nnel = cnd ? next_non_empty(line->next->next) : NULL;
1602 bool nextor = cnd ? (not nnel or nnel->type & GLINE_KLUDGE) and (line->next->txt.find(/*(*/')') != line->next->txt.npos) : false;
1603 if(not line->next or nextkl or nextor) {
1604
1605 gotorig = YES;
1606 originlineno = lineno;
1607 line->type |= GLINE_ORIG;
1608 line->color = C_READO;
1609 strxcpy(msg->origin, line->txt.c_str()+11, sizeof(msg->origin));
1610 if(nextor) { // Get the next line too
1611 strcat(msg->origin, line->next->txt.c_str());
1612 line->next->color = C_READO;
1613 line->next->type |= GLINE_ORIG; // Mark next line as Origin too
1614 }
1615 }
1616 }
1617
1618 else if(strneql(ptr, "SEEN-BY:", 8)) {
1619 line->kludge = GKLUD_SEENBY;
1620 line->color = C_READK;
1621 line->type |= GLINE_KLUD;
1622 }
1623
1624 // Check if it's a signature indicator
1625 else if(AA->isinternet() or *msg->ito or *msg->ifrom) {
1626 if(streql(ptr, "-- ")) {
1627 for(Line* q = line; q; q = q->next) {
1628 if((q->type & (GLINE_KLUDGE|GLINE_ORIG|GLINE_TEAR)) == 0) {
1629 q->color = C_READS;
1630 q->type |= GLINE_SIGN;
1631 if(q != line)
1632 q->type |= GLINE_HARD;
1633 if(strneql("----", q->txt.c_str(), 4))
1634 break;
1635 }
1636 }
1637 }
1638 }
1639 }
1640 }
1641 if(line->type & GLINE_WRAP) {
1642 Line* linep = line;
1643 while(linep and (linep->type & GLINE_WRAP)) {
1644 if(linep->next) {
1645 linep->next->type |= linep->type & GLINE_KLUDGE;
1646 linep->next->kludge = linep->kludge;
1647 linep->next->color = linep->color;
1648 }
1649 linep = linep->next;
1650 }
1651 }
1652
1653 lineno++;
1654
1655 } while((line = line->prev) != NULL);
1656
1657 if(not gottag)
1658 *msg->tagline = NUL;
1659 if(not gottear)
1660 *msg->tearline = NUL;
1661 if(not gotorig)
1662 *msg->origin = NUL;
1663
1664 if(getvalue) {
1665 // This is the new code (experimental)
1666 // It looks for an Origin before taking MSGID
1667 // Trust msg->orig if valid and we're in netmail area.
1668 // (msg->orig is already merged with INTL/FMPT/TOPT)
1669
1670 if(not (AA->isnet() and msg->orig.valid())) {
1671 if(CFG->addresslookupfirst and msg->msgid.valid())
1672 msg->orig = msg->msgid;
1673 else if((ptr = strrchr(msg->origin, '(' /*)*/ )) != NULL) {
1674 while(not isdigit(*ptr) and *ptr)
1675 ptr++;
1676 msg->orig.reset(ptr);
1677 }
1678 if(msg->msgid.valid())
1679 msg->orig = msg->msgid;
1680 }
1681
1682 if(msg->orig.zone == 0)
1683 msg->orig.zone = msg->msgid.zone ? msg->msgid.zone : AA->Aka().addr.zone;
1684
1685 if(msg->dest.zone == 0)
1686 msg->dest.zone = msg->orig.zone;
1687 }
1688 }
1689
1690
1691 // ------------------------------------------------------------------
1692
Latin2Local(char * str)1693 void Latin2Local(char *str)
1694 {
1695 if (!CFG->latin2local || !str) return;
1696
1697 for (size_t i = 0; str[i]; i++)
1698 {
1699 byte chr = str[i];
1700 byte xch = CFG->latintolocal[chr];
1701
1702 if (xch && (xch != chr))
1703 {
1704 byte left = i ? str[i-1] : 0;
1705 byte right = str[i+1];
1706
1707 if (((left >= 0x80) && g_isalpha(left )) ||
1708 ((right >= 0x80) && g_isalpha(right)))
1709 {
1710 str[i] = xch;
1711
1712 for (size_t j = i-1; j < i; j--)
1713 {
1714 chr = str[j];
1715 xch = CFG->latintolocal[chr];
1716
1717 if (xch && (xch != chr))
1718 str[j] = xch;
1719 else
1720 break;
1721 }
1722 }
1723 }
1724 }
1725 }
1726
1727
1728 // ------------------------------------------------------------------
1729
Latin2Local(std::string & str)1730 void Latin2Local(std::string &str)
1731 {
1732 #if defined(__USE_ALLOCA__)
1733 char *temp = (char *)alloca(str.length()+1);
1734 #else
1735 __extension__ char temp[str.length()+1];
1736 #endif
1737 strcpy(temp, str.c_str());
1738 Latin2Local(temp);
1739 str = temp;
1740 }
1741
1742 // ------------------------------------------------------------------
1743
1744 #ifdef HAS_ICONV
IconvClear(void)1745 void IconvClear(void){
1746 if( iconv_cd!=(iconv_t)(-1) ){
1747 iconv_close(iconv_cd);
1748 iconv_cd = (iconv_t)(-1);
1749 }
1750 }
1751 #endif
1752
1753 // ------------------------------------------------------------------
1754
XlatStr(char * dest,const char * src,int level,Chs * chrtbl,int qpencoded,bool i51)1755 char* XlatStr(char* dest, const char* src, int level, Chs* chrtbl, int qpencoded, bool i51) {
1756
1757 if( src==NULL )
1758 return dest;
1759
1760 if( not chrtbl
1761 #ifdef HAS_ICONV
1762 && iconv_cd==(iconv_t)(-1)
1763 #endif
1764 )
1765 return stpcpy(dest, src);
1766
1767 uint n;
1768 int clen;
1769 int translated;
1770 char* tptr;
1771 char* escp;
1772 const char* sptr = src;
1773 char* dptr = dest;
1774 char dochar;
1775 ChsTab* chrs = chrtbl ? chrtbl->t : (ChsTab*)NULL;
1776
1777 #ifdef HAS_ICONV
1778 size_t iconvrc=(size_t)(-1);
1779 if( iconv_cd!=(iconv_t)(-1) ){
1780 iconvrc=iconv( iconv_cd, NULL, NULL, NULL, NULL ); // init iconv
1781 }
1782 #endif
1783 while(*sptr) {
1784 switch(*sptr) {
1785 case 0x02:
1786 if(i51 and I51Table) {
1787 for(n=0; n<I51Table->size; n++) {
1788 tptr = (char*)I51TP[n];
1789 if(*(sptr+1) == tptr[0]) {
1790 if(*(sptr+2) == tptr[1]) {
1791 escp = &tptr[2];
1792 if(*escp) {
1793 *dptr++ = *escp++;
1794 if(*escp) {
1795 *dptr++ = *escp++;
1796 if(*escp) {
1797 *dptr++ = *escp;
1798 }
1799 }
1800 }
1801 sptr += 2;
1802 n = (uint)-1;
1803 break;
1804 }
1805 }
1806 }
1807 if(n != (uint)-1) // I51 char not found, use fallback method
1808 sptr++;
1809 }
1810 sptr++;
1811 break;
1812
1813 case 29:
1814 if(MNETable) {
1815 for(n=0; n<MNETable->size; n++) {
1816 tptr = (char*)MNETP[n];
1817 if(*(sptr+1) == tptr[0]) {
1818 if(*(sptr+2) == tptr[1]) {
1819 escp = &tptr[2];
1820 if(*escp) {
1821 *dptr++ = *escp++;
1822 if(*escp) {
1823 *dptr++ = *escp++;
1824 if(*escp) {
1825 *dptr++ = *escp;
1826 }
1827 }
1828 }
1829 sptr += 2;
1830 n = (uint)-1;
1831 break;
1832 }
1833 }
1834 }
1835 if(n != (uint)-1) // MNEMONIC char not found, use fallback method
1836 sptr++;
1837 }
1838 sptr++;
1839 break;
1840
1841 case SOFTCR:
1842 translated = false;
1843 if (WideDispsoftcr)
1844 goto defaultchardo;
1845 else if (CompTable)
1846 {
1847 if(sptr > src) {
1848 if(not (isspace(*(sptr-1)) or isspace(*(sptr+1)))) {
1849 for(n=0; n<CompTable->size; n++) {
1850 tptr = (char*)CompTP[n];
1851 if(*(sptr-1) == tptr[0]) {
1852 if(*(sptr+1) == tptr[1]) {
1853 escp = &tptr[2];
1854 if(*escp) {
1855 dptr--;
1856 *dptr++ = *escp++;
1857 if(*escp) {
1858 *dptr++ = *escp++;
1859 if(*escp) {
1860 *dptr++ = *escp;
1861 translated = true;
1862 }
1863 }
1864 }
1865 sptr += 2;
1866 break;
1867 }
1868 }
1869 }
1870 }
1871 }
1872 }
1873 if(not translated)
1874 *dptr++ = *sptr++;
1875 break;
1876
1877 case '=':
1878 if(qpencoded) {
1879 if(isxdigit(sptr[1]) and isxdigit(sptr[2])) {
1880 dochar = (char)((xtoi(sptr[1]) << 4) | xtoi(sptr[2]));
1881 sptr += 3;
1882 goto chardo;
1883 }
1884 }
1885 goto defaultchardo;
1886
1887 default:
1888 defaultchardo:
1889 dochar = *sptr++;
1890 chardo:
1891 #ifdef HAS_ICONV
1892 if( iconv_cd!=(iconv_t)(-1) ){
1893 unsigned srcleft=1;
1894 unsigned dstleft=3;
1895 char* tsptr = &dochar;
1896
1897 iconvrc=iconv( iconv_cd, &tsptr, &srcleft, &dptr, &dstleft );
1898 if( iconvrc==((size_t)-1) ){
1899 switch( errno ){
1900 case EINVAL:
1901 LOG.printf("An incomplete multibyte sequence has been encountered before:");
1902 LOG.printf("%s",sptr);
1903 case EILSEQ:
1904 LOG.printf("An invalid multibyte sequence has been encountered in the input before:");
1905 LOG.printf("%s",sptr);
1906 case E2BIG:
1907 LOG.printf("There is not sufficient destination size before '%s'", sptr);
1908 default:
1909 LOG.printf("Unknown error %u in iconv() before %s", errno, sptr);
1910 }
1911 }
1912 }
1913 else
1914 #endif
1915
1916 if ((level > 0) && chrs)
1917 {
1918 tptr = (char*)chrs[(byte)dochar];
1919 clen = *tptr++;
1920 while(clen--)
1921 *dptr++ = *tptr++;
1922 }
1923 else {
1924 *dptr++ = dochar;
1925 }
1926 }
1927 }
1928 *dptr = NUL;
1929 return dptr;
1930 }
1931
1932
1933 // ------------------------------------------------------------------
1934
cmp_quotes(char * q1,char * q2)1935 int cmp_quotes(char* q1, char* q2) {
1936
1937 q1--;
1938 q2--;
1939
1940 do {
1941 q1 = spanspaces(++q1);
1942 q2 = spanspaces(++q2);
1943 if(*q1 != *q2)
1944 return NO;
1945 } while(*q1 and *q2);
1946
1947 return *q1 == *q2;
1948 }
1949
1950
1951 // ------------------------------------------------------------------
1952
TextToLines(int __line_width,bool getvalue,bool header_recode)1953 void GMsg::TextToLines(int __line_width, bool getvalue, bool header_recode) {
1954
1955 MakeLineIndex(this, __line_width, getvalue, header_recode);
1956 }
1957
1958
1959 // ------------------------------------------------------------------
1960
check_multipart(const char * ptr,char * boundary)1961 static bool check_multipart(const char* ptr, char* boundary) {
1962
1963 if(striinc("multipart", ptr)) {
1964 const char* boundptr = striinc("boundary=", ptr);
1965 if(boundptr) {
1966 boundptr += 9;
1967 const char* boundend;
1968 if(*boundptr == '\"') {
1969 boundptr++;
1970 boundend = strchr(boundptr, '\"');
1971 }
1972 else {
1973 boundend = strpbrk(boundptr, " \r\n");
1974 }
1975 if(boundend) {
1976 strxcpy(boundary, boundptr, 1+boundend-boundptr);
1977 return true;
1978 }
1979 }
1980 }
1981 return false;
1982 }
1983
1984
1985 // ------------------------------------------------------------------
1986
put_on_new_line(const char * ptr,const char * prev_ptr)1987 inline bool put_on_new_line(const char *ptr, const char *prev_ptr) {
1988
1989 if((*ptr == CR) or
1990 (*ptr == CTRL_A) or
1991 is_quote(ptr) or
1992 ((ptr[0] == ptr[1]) and (ptr[0] == ptr[2])) or
1993 (strneql(ptr, "-- ", 3) and (ptr[3] == CR)) or
1994 strneql(ptr, " * Origin: ", 11) /*or
1995 (ptr[0] == prev_ptr[0]) and (ptr[1] == prev_ptr[1])*/)
1996 return true;
1997 // Put RFC kludges and SEEN-BY on new line
1998 while(*ptr and (isxalnum(*ptr) or (*ptr == '-')))
1999 ptr++;
2000 if(*ptr == ':')
2001 return true;
2002 return false;
2003 }
2004
2005
2006 // ------------------------------------------------------------------
2007
MakeLineIndex(GMsg * msg,int margin,bool getvalue,bool header_recode)2008 void MakeLineIndex(GMsg* msg, int margin, bool getvalue, bool header_recode) {
2009
2010 uint idx=0, idxadjust=0;
2011 uint len;
2012 int level=0;
2013 uint n;
2014 char ch, chln = 0, dochar;
2015 Line* line;
2016 Line* nextline=NULL;
2017 char* bp;
2018 char* btmp=NULL;
2019 char* tptr;
2020 char* escp;
2021 char* bptr;
2022 ISub buf;
2023 char qbuf[MAXQUOTELEN], qbuf2[MAXQUOTELEN], chsbuf[100];
2024 char* ptr;
2025 char* qptr;
2026 char* tmp=NULL;
2027 char* linetmp=NULL;
2028 uint qlen=0, qlen2=0;
2029 int wraps=0, para=0, chslev;
2030 bool reflow = false, quoteflag = false;
2031 bool quotewraphard = AA->Quotewraphard();
2032 bool qpencoded = getvalue and (IsQuotedPrintable(AA->Xlatimport()) or AA->StripHTML());
2033 bool gotmime = false;
2034 bool gotmultipart = false;
2035 bool inheader = false;
2036 gstrarray boundary_set;
2037 char boundary[100];
2038
2039 *buf = *qbuf = *qbuf2 = NUL;
2040
2041 if(margin < 0) {
2042 margin = -margin;
2043 quoteflag = true;
2044 }
2045
2046 // Free all previously allocated lines
2047 line = msg->lin;
2048 while(line) {
2049 nextline = line->next;
2050 throw_xdelete(line);
2051 line = nextline;
2052 }
2053
2054 msg->icc[0] = NUL;
2055 msg->ibcc[0] = NUL;
2056
2057 msg->lines = 0;
2058 msg->lin = NULL;
2059
2060 if(AA->attr().hex()) {
2061
2062 // Make a complete hexdump as a list of message lines
2063 w_info(LNG->GenHexdump);
2064 throw_release(msg->txt);
2065 line = AA->MakeDumpMsg(msg, LNG->Hexdumphead);
2066 if(line and msg->txt) {
2067 line = AddLine(line, "");
2068 line = AddLine(line, LNG->Hexdumptext);
2069 line = AddLine(line, "");
2070 ptr = msg->txt;
2071 uint _size = strlen(msg->txt);
2072 if ((AA->basetype() == "OPUS") || (AA->basetype() == "FTS1"))
2073 idxadjust = 190;
2074 for (idx=0; idx < _size; ptr+=16,idx+=16)
2075 {
2076 gsprintf(PRINTF_DECLARE_BUFFER(buf), "%04X ", idx+idxadjust);
2077 HexDump16(buf+7, ptr, MinV((int)(_size-idx), 16), HEX_DUMP2);
2078 line = AddLine(line, buf);
2079 }
2080 }
2081
2082 w_info(NULL);
2083 }
2084 else { // Convert the message text to a list of separately allocated lines
2085
2086 char prev_ptr[3] = {"\xFF\xFF"};
2087
2088 if(AA->StripHTML())
2089 RemoveHTML(msg->txt);
2090 ptr = spanfeeds(msg->txt);
2091
2092 // Set default conversion table for area
2093 if(getvalue) {
2094 if(not strieql(AA->Xlatimport(), CFG->xlatlocalset)) {
2095 strxcpy(msg->charset, AA->Xlatimport(), sizeof(msg->charset));
2096 level = msg->charsetlevel = LoadCharset(msg->charset, CFG->xlatlocalset);
2097 }
2098 }
2099
2100 if(*ptr != NUL) {
2101 line = msg->lin = new Line();
2102 throw_xnew(line);
2103
2104 // Alloc space for one line
2105 linetmp = (char*)throw_calloc(1, margin+512);
2106 while(*ptr) {
2107
2108 bptr = linetmp;
2109 bp = bptr;
2110 len = 0;
2111
2112 // Link previous line to this one
2113
2114 if(line->prev) {
2115 line->prev->next = line;
2116 if((line->prev->type & (GLINE_HARD|GLINE_WRAP|GLINE_QUOT)) == (GLINE_HARD|GLINE_WRAP)) {
2117 line->prev->type &= ~GLINE_HARD;
2118 line->type |= GLINE_HARD;
2119 }
2120 }
2121
2122 // Reflow quotes
2123
2124 if(reflow) {
2125 len = qlen;
2126 qptr = qbuf;
2127 reflow = false;
2128 // Insert previous quotestring
2129 for(n=0; n<qlen; n++)
2130 {
2131 if ((level > 0) && ChsTP)
2132 {
2133 tptr = (char*)ChsTP[(byte)(*qptr++)];
2134 chln = *tptr++;
2135 while(chln--) {
2136 *(++bp) = *tptr++;
2137 }
2138 }
2139 else {
2140 *(++bp) = *qptr++;
2141 }
2142 }
2143 if(quotewraphard) {
2144 *qbuf = NUL;
2145 qlen = 0;
2146 }
2147 ptr = spanfeeds(ptr);
2148 line->type |= GLINE_QUOT|GLINE_HARD;
2149 }
2150
2151 // Get type of line
2152 int isq_flag1 = 0;
2153 bool isq_flag2 = false;
2154
2155 if(wraps == 0) {
2156
2157 if(gotmultipart) {
2158 if(*ptr == '-' and ptr[1] == '-') {
2159 gstrarray::iterator ib;
2160 for(ib = boundary_set.begin(); ib != boundary_set.end(); ib++)
2161 if(strneql(ptr+2, (*ib).c_str(), (*ib).length())) {
2162 inheader = true;
2163 break;
2164 }
2165 }
2166 else if(*ptr == '\n' or *ptr == '\r')
2167 inheader = false;
2168 }
2169
2170 if(inheader and (*ptr != '-'))
2171 line->type |= GLINE_HIDD;
2172
2173 para = 0;
2174 if(*ptr == CTRL_A or inheader) { // Found kludge/hidden line
2175 para = GLINE_KLUD;
2176 line->type |= GLINE_HARD;
2177 if(getvalue and not CFG->ignorecharset) {
2178 tptr = ptr;
2179 char* kludge = ptr + (*ptr == CTRL_A ? 1 : 0);
2180 if(strnieql(kludge, "RFC", 3)) {
2181 kludge += 3;
2182 if(not g_isalpha(*kludge))
2183 kludge++;
2184 }
2185 while((*ptr != ' ') and (*ptr != ':') and *ptr)
2186 ptr++;
2187 char endchar = *ptr;
2188 *ptr = NUL;
2189 int kludgetype = -1;
2190 if(strieql(kludge, "I51"))
2191 kludgetype = FSC_I51;
2192 else if(strieql(kludge, "CHRS") or strieql(kludge, "CHARSET"))
2193 kludgetype = FSC_CHARSET;
2194 else if(strieql(kludge, "CODEPAGE"))
2195 kludgetype = FSC_CODEPAGE;
2196 else if(strieql(kludge, "Content-Type"))
2197 kludgetype = RFC_CONTENT_TYPE;
2198 else if(strieql(kludge, "Content-Transfer-Encoding"))
2199 kludgetype = RFC_CONTENT_TRANSFER_ENCODING;
2200 else if(strieql(kludge, "X-Charset"))
2201 kludgetype = RFC_X_CHARSET;
2202 else if(strieql(kludge, "X-Char-Esc"))
2203 kludgetype = RFC_X_CHAR_ESC;
2204 *ptr = endchar;
2205 if(*ptr != ' ')
2206 ptr++;
2207 ptr = strskip_wht(ptr);
2208 char* keptr = strpbrk(ptr, "\r\n");
2209 if(keptr) {
2210 endchar = *keptr;
2211 *keptr = NUL;
2212 }
2213 if(kludgetype == FSC_I51) {
2214 msg->i51 = true;
2215 // Convert FSC-0051.003 to FSC-0054.003
2216 strxcpy(chsbuf, "LATIN-1", sizeof(chsbuf));
2217 chslev = LoadCharset(chsbuf, CFG->xlatlocalset);
2218 if(not chslev) {
2219 strxcpy(chsbuf, AA->Xlatimport(), sizeof(chsbuf));
2220 chslev = LoadCharset(chsbuf, CFG->xlatlocalset);
2221 }
2222 if(chslev) {
2223 level = msg->charsetlevel = chslev;
2224 strcpy(msg->charset, chsbuf);
2225 }
2226 }
2227 else if((kludgetype == FSC_CHARSET) or (kludgetype == FSC_CODEPAGE)) {
2228 *chsbuf = NUL;
2229 qpencoded = IsQuotedPrintable(ptr);
2230 if(kludgetype == FSC_CODEPAGE)
2231 strxmerge(chsbuf, sizeof(chsbuf), "CP", ptr, NULL);
2232 else
2233 strxcpy(chsbuf, qpencoded ? ExtractPlainCharset(ptr) : ptr, sizeof(chsbuf));
2234 // Workaround for buggy mailreaders which stores '_' in charset name
2235 strchg(chsbuf,'_',' ');
2236 chslev = LoadCharset(chsbuf, CFG->xlatlocalset);
2237 if(not chslev) {
2238 strxcpy(chsbuf, AA->Xlatimport(), sizeof(chsbuf));
2239 chslev = LoadCharset(chsbuf, CFG->xlatlocalset);
2240 }
2241 if(chslev) {
2242 level = msg->charsetlevel = chslev;
2243 strcpy(msg->charset, chsbuf);
2244 }
2245 if(*msg->charset == NUL)
2246 strcpy(msg->charset, chsbuf);
2247 }
2248 else if(kludgetype == RFC_CONTENT_TYPE) {
2249 // Content-Type: text/plain; charset="us-ascii"
2250 while(keptr and ((keptr[1] == ' ') or (keptr[1] == '\t'))) {
2251 *keptr = endchar;
2252 keptr = strpbrk(keptr+1, "\r\n");
2253 if(keptr) {
2254 endchar = *keptr;
2255 *keptr = NUL;
2256 }
2257 }
2258 const char *mime_charset = striinc("charset=", ptr);
2259 if(mime_charset != NULL) {
2260 if(mime_charset[8] == '\"') {
2261 strxcpy(chsbuf, mime_charset+9, sizeof(chsbuf));
2262 char *quote = strchr(chsbuf, '\"');
2263 if(quote != NULL) *quote = NUL;
2264 }
2265 else
2266 strxcpy(chsbuf, strrword(mime_charset+8), sizeof(chsbuf));
2267 if(striinc("8859", chsbuf))
2268 ISO2Latin(chsbuf, chsbuf);
2269 chslev = LoadCharset(chsbuf, CFG->xlatlocalset);
2270 if(not chslev) {
2271 strxcpy(chsbuf, AA->Xlatimport(), sizeof(chsbuf));
2272 chslev = LoadCharset(chsbuf, CFG->xlatlocalset);
2273 }
2274 if(chslev) {
2275 level = msg->charsetlevel = chslev;
2276 strcpy(msg->charset, chsbuf);
2277 }
2278 if(*msg->charset == NUL)
2279 strcpy(msg->charset, chsbuf);
2280 gotmime = true;
2281 }
2282 else if(check_multipart(ptr, boundary)) {
2283 boundary_set.push_back(boundary);
2284 gotmultipart = true;
2285 gotmime = true;
2286 }
2287 }
2288 else if(kludgetype == RFC_CONTENT_TRANSFER_ENCODING) {
2289 if(striinc("quoted-printable", ptr)) {
2290 qpencoded = true;
2291 msg->charsetencoding |= GCHENC_QP;
2292 strcpy(chsbuf, MakeQuotedPrintable(msg->charset));
2293 chslev = LoadCharset(msg->charset, CFG->xlatlocalset);
2294 if(not chslev) {
2295 strxcpy(chsbuf, AA->Xlatimport(), sizeof(chsbuf));
2296 chslev = LoadCharset(chsbuf, CFG->xlatlocalset);
2297 }
2298 if(chslev) {
2299 level = msg->charsetlevel = chslev;
2300 strcpy(msg->charset, chsbuf);
2301 }
2302 }
2303 }
2304 else if(kludgetype == RFC_X_CHARSET) {
2305 if(not gotmime) {
2306 if(striinc("8859", ptr))
2307 ISO2Latin(chsbuf, ptr);
2308 else
2309 strxcpy(chsbuf, ptr, sizeof(chsbuf));
2310 chslev = LoadCharset(chsbuf, CFG->xlatlocalset);
2311 if(not chslev) {
2312 strxcpy(chsbuf, AA->Xlatimport(), sizeof(chsbuf));
2313 chslev = LoadCharset(chsbuf, CFG->xlatlocalset);
2314 }
2315 if(chslev) {
2316 level = msg->charsetlevel = chslev;
2317 strcpy(msg->charset, chsbuf);
2318 }
2319 }
2320 }
2321 else if(kludgetype == RFC_X_CHAR_ESC) {
2322 if(not gotmime)
2323 msg->charsetencoding |= GCHENC_MNE;
2324 }
2325 if(keptr)
2326 *keptr = endchar;
2327 ptr = tptr;
2328 }
2329 }
2330 else if ((isq_flag1 = is_quote(ptr)) &&
2331 (isq_flag2 = is_quote2(line, ptr)))
2332 {
2333 para = GLINE_QUOT;
2334 line->type |= GLINE_QUOT|GLINE_HARD;
2335 GetQuotestr(ptr, qbuf, &qlen);
2336 }
2337 }
2338
2339 if (CFG->quoteusenewai && isq_flag1 && !isq_flag2)
2340 {
2341 uint bad_qlen;
2342 char bad_qbuf[MAXQUOTELEN];
2343 char *bad_ptr;
2344
2345 GetQuotestr(bad_ptr = ptr, bad_qbuf, &bad_qlen);
2346
2347 while (true)
2348 {
2349 for (; *bad_ptr && (*bad_ptr != CR); bad_ptr++);
2350 if (!*bad_ptr) break;
2351
2352 char *bad_head = bad_ptr;
2353
2354 bad_ptr++;
2355 if (*bad_ptr == LF) bad_ptr++;
2356
2357 if (strneql(bad_qbuf, bad_ptr, bad_qlen))
2358 {
2359 *bad_head = ' ';
2360
2361 memmove(bad_head+1, bad_ptr+bad_qlen, strlen(bad_ptr));
2362 bad_ptr = bad_head;
2363 }
2364 else
2365 break;
2366 }
2367 }
2368
2369 // Get one line
2370
2371 ch = '\0';
2372 tmp = NULL;
2373 while(*ptr and (len < (uint)margin)) {
2374 switch(*ptr) {
2375 case CR:
2376 do_cr:
2377 ch = CR;
2378 ptr = spanfeeds(ptr+1);
2379 if(wraps and not ((line->type & GLINE_HARD) and not (line->type & GLINE_QUOT))) {
2380 if(para != GLINE_QUOT) {
2381 if(quoteflag) {
2382 if(para == GLINE_KLUD) {
2383 wraps = 0;
2384 break;
2385 }
2386 if(put_on_new_line(ptr, prev_ptr)) {
2387 wraps = 0;
2388 break;
2389 }
2390 char* lp = ptr;
2391 while((*lp == ' ') or (*lp == '\t'))
2392 lp++;
2393 if(*lp == CR) {
2394 wraps = 0;
2395 break;
2396 }
2397 else {
2398 ptr = lp;
2399 if(*bp != ' ') {
2400 *(++bp) = ' ';
2401 len++;
2402 }
2403 }
2404 ch = '\0';
2405 continue;
2406 }
2407 else {
2408 wraps=0;
2409 break;
2410 }
2411 }
2412 else {
2413 GetQuotestr(ptr, qbuf2, &qlen2);
2414 if((*ptr != CR) and cmp_quotes(qbuf2, qbuf)) {
2415 char* lp = ptr + qlen2;
2416 if(is_quote(lp)) {
2417 wraps = 0;
2418 para = 0;
2419 break;
2420 }
2421 else {
2422 ptr = lp;
2423 para = GLINE_QUOT;
2424 if((*ptr != ' ') and (*bp != ' ')) {
2425 if(put_on_new_line(ptr, prev_ptr)) {
2426 ptr -= qlen2;
2427 wraps = 0;
2428 break;
2429 }
2430 tmp = ptr-1;
2431 btmp = bp;
2432 *(++bp) = ' ';
2433 len++;
2434 }
2435 else if(*ptr == ' ') {
2436 ptr -= qlen2;
2437 wraps = 0;
2438 break;
2439 }
2440 ch = 0;
2441 continue;
2442 }
2443 }
2444 else {
2445 wraps = 0;
2446 para = 0;
2447 break;
2448 }
2449 }
2450 }
2451 break;
2452 case 0x02: // The I51 escape character
2453 if(msg->i51 and I51Table) {
2454 for(n=0; n<I51Table->size; n++) {
2455 tptr = (char*)I51TP[n];
2456 if(*(ptr+1) == tptr[0]) {
2457 if(*(ptr+2) == tptr[1]) {
2458 escp = &tptr[2];
2459 if(*escp) {
2460 *(++bp) = *escp++;
2461 if(*escp) {
2462 *(++bp) = *escp++;
2463 len++;
2464 if(*escp) {
2465 *(++bp) = *escp;
2466 len++;
2467 }
2468 }
2469 }
2470 ptr += 2;
2471 n = (uint)-1;
2472 break;
2473 }
2474 }
2475 }
2476 if(n != (uint)-1) // I51 char not found, use fallback method
2477 ptr++;
2478 }
2479 ptr++;
2480 break;
2481 case 29: // The MNE escape character
2482 if(MNETable) {
2483 for(n=0; n<MNETable->size; n++) {
2484 tptr = (char*)MNETP[n];
2485 if(*(ptr+1) == tptr[0]) {
2486 if(*(ptr+2) == tptr[1]) {
2487 escp = &tptr[2];
2488 if(*escp) {
2489 *(++bp) = *escp++;
2490 if(*escp) {
2491 *(++bp) = *escp++;
2492 len++;
2493 if(*escp) {
2494 *(++bp) = *escp;
2495 len++;
2496 }
2497 }
2498 }
2499 ptr += 2;
2500 n = (uint)-1;
2501 break;
2502 }
2503 }
2504 }
2505 if(n != (uint)-1) // MNE char not found, use fallback method
2506 ptr++;
2507 }
2508 ptr++;
2509 break;
2510 case SOFTCR:
2511 if (WideDispsoftcr)
2512 goto defaultchardo;
2513 else {
2514 if(CompTable) {
2515 if(not (isspace(*(ptr-1)) or isspace(*(ptr+1)))) {
2516 for(n=0; n<CompTable->size; n++) {
2517 tptr = (char*)CompTP[n];
2518 if(*(ptr-1) == tptr[0]) {
2519 if(*(ptr+1) == tptr[1]) {
2520 escp = &tptr[2];
2521 if(*escp) {
2522 *(bp) = *escp++;
2523 if(*escp) {
2524 *(++bp) = *escp++;
2525 len++;
2526 if(*escp) {
2527 *(++bp) = *escp;
2528 len++;
2529 }
2530 }
2531 }
2532 ptr++;
2533 break;
2534 }
2535 }
2536 }
2537 }
2538 else if(para == GLINE_QUOT) {
2539 *ptr-- = CR; // Fake a CR
2540 }
2541 }
2542 else if(para == GLINE_QUOT) {
2543 *ptr-- = CR; // Fake a CR
2544 }
2545 ptr++;
2546 }
2547 break;
2548 case LF:
2549 ptr++;
2550 break;
2551 case CTRL_A:
2552 *(++bp) = *ptr++;
2553 ++len;
2554 break;
2555 case '=':
2556 if(qpencoded) {
2557 if(isxdigit(ptr[1]) and isxdigit(ptr[2])) {
2558 // Decode the character
2559 dochar = (char)((xtoi(ptr[1]) << 4) | xtoi(ptr[2]));
2560 ptr += 3;
2561 if(dochar == '\t') {
2562 if(len >= qlen) {
2563 tmp = ptr-3;
2564 btmp = bp;
2565 }
2566 goto do_ht;
2567 }
2568 else if(dochar == CR)
2569 goto do_cr;
2570 goto chardo;
2571 }
2572 else if((ptr[1] == CR) or (ptr[1] == LF)) {
2573 // Skip soft line break
2574 ptr = spanfeeds(ptr+2);
2575 break;
2576 }
2577 }
2578 goto defaultchardo;
2579 case '\t':
2580 if(len >= qlen) {
2581 tmp = ptr;
2582 btmp = bp;
2583 }
2584 ptr++;
2585 do_ht:
2586 if(CFG->disptabsize) {
2587 int llen = (int)(bp-linetmp);
2588 for(n=0; n<(CFG->disptabsize-(llen%CFG->disptabsize)); n++) {
2589 *(++bp) = ' ';
2590 len++;
2591 }
2592 }
2593 else {
2594 *(++bp) = ' ';
2595 len++;
2596 }
2597 break;
2598 case ' ':
2599 if(len >= qlen) {
2600 tmp = ptr;
2601 btmp = bp;
2602 }
2603 default:
2604 defaultchardo:
2605 dochar = *ptr++;
2606 chardo:
2607 if ((level > 0) && ChsTP)
2608 {
2609 tptr = (char*)ChsTP[(byte)dochar];
2610 chln = *tptr++;
2611 while(chln--) {
2612 *(++bp) = *tptr++;
2613 ++len;
2614 }
2615 }
2616 else {
2617 *(++bp) = dochar;
2618 ++len;
2619 }
2620 break;
2621 }
2622 if(ch == CR)
2623 break;
2624 }
2625
2626 if(len == (uint)margin) {
2627 if(*ptr == CR) {
2628 line->type |= GLINE_HARD;
2629 wraps = 0;
2630 ptr++;
2631 }
2632 else {
2633 wraps++;
2634 if(para == GLINE_QUOT)
2635 reflow = true;
2636 line->type |= GLINE_WRAP;
2637 ptr = spanfeeds(ptr);
2638 if((*bp == ' ') or (isspace(*ptr) and (*ptr != LF)))
2639 ptr = spanspaces(ptr);
2640 else {
2641 if(tmp) {
2642 bp = btmp+1;
2643 ptr = tmp+1;
2644 }
2645 }
2646 }
2647 }
2648 else
2649 line->type |= GLINE_HARD;
2650
2651 *(++bp) = NUL;
2652
2653 // Get line length
2654 uint tmplinelength = (uint)(bp-bptr);
2655 if(tmplinelength > (uint)(margin + 512)) {
2656 LOG.ErrPointer();
2657 LOG.printf("! A message line length (%u bytes) exceeded an internal buffer limit of %u bytes", tmplinelength, margin+512);
2658 LOG.printf(": Message line text: %s", bptr+1);
2659 PointerErrorExit();
2660 }
2661
2662 // Store line
2663 line->txt = linetmp+1;
2664 prev_ptr[0] = line->txt.empty() ? 0xFF : line->txt[0];
2665 prev_ptr[1] = line->txt.length() < 2 ? 0xFF : line->txt[1];
2666
2667 // Set line color and type
2668 if((line->type & GLINE_QUOT) and not is_quote(line->txt.c_str()))
2669 line->type ^= GLINE_QUOT;
2670 if(line->type & GLINE_QUOT)
2671 line->color = quotecolor(line->txt.c_str());
2672 else if(inheader)
2673 line->color = C_READT;
2674 else
2675 line->color = C_READW;
2676
2677 Line* prevline = line;
2678 line = new Line();
2679 throw_xnew(line);
2680 line->prev = prevline;
2681
2682 ptr = spanfeeds(ptr);
2683 }
2684
2685 throw_release(linetmp);
2686 throw_xdelete(line);
2687
2688 // Charset translate header fields
2689 if(header_recode) {
2690 strxmimecpy(msg->by, msg->by, level, sizeof(INam), true);
2691 strxmimecpy(msg->to, msg->to, level, sizeof(INam), true);
2692 if(not (msg->attr.frq() or msg->attr.att() or msg->attr.urq()))
2693 strxmimecpy(msg->re, msg->re, level, sizeof(ISub), true);
2694 }
2695
2696 // Scan msg body top for RFC headerlines
2697 int irfcbody = AA->Internetrfcbody();
2698 if(irfcbody != 0) {
2699 if(msg->lin) {
2700 Line* linep = msg->lin;
2701 int headerlines = 0;
2702 while(linep) {
2703 if(not linep->txt.empty()) {
2704 const char* tptr = linep->txt.c_str();
2705 if(*tptr != CTRL_A) {
2706 int kludgetype = ScanLine(msg, linep, tptr, getvalue, MASK_RFC);
2707 if(kludgetype) {
2708 if(kludgetype == HEADERLINE) {
2709 linep->type |= GLINE_HIDD;
2710 }
2711 headerlines++;
2712 if(linep->type & GLINE_HIDD)
2713 linep->color = C_READKH;
2714 else
2715 linep->color = C_READK;
2716 if(linep->next) {
2717 char lwsp = *linep->next->txt.c_str();
2718 while((lwsp == ' ') or (lwsp == '\t') or (linep->type & GLINE_WRAP)) {
2719 linep = linep->next;
2720 linep->type |= linep->prev->type & (GLINE_KLUD|GLINE_HIDD);
2721 linep->color = linep->prev->color;
2722 if(linep->next)
2723 lwsp = *linep->next->txt.c_str();
2724 else
2725 break;
2726 }
2727 }
2728 }
2729 else
2730 break;
2731 }
2732 }
2733 else {
2734 if(headerlines) {
2735 linep->type |= GLINE_KLUD;
2736 linep->kludge = GKLUD_RFC;
2737 linep->color = C_READK;
2738 }
2739 if(--irfcbody == 0)
2740 break;
2741 }
2742 if(linep->type & GLINE_WRAP) {
2743 while(linep and (linep->type & GLINE_WRAP)) {
2744 linep = linep->next;
2745 if(linep) {
2746 linep->type |= linep->prev->type & (GLINE_KLUD|GLINE_HIDD);
2747 linep->color = linep->prev->color;
2748 }
2749 }
2750 }
2751 if(linep)
2752 linep = linep->next;
2753 }
2754 }
2755 }
2756
2757 // Scan for kludge-, tear- and originlines
2758 ScanKludges(msg, getvalue);
2759
2760 // Try to fix the following situation:
2761 // Messagebase From field: fido7@da.ru
2762 // @REPLYADDR: fido7@da.ru
2763 // @REPLYTO: 2:5020/52 Sergey Kitsya
2764 // From: fido7@da.ru
2765 if(getvalue and streql(msg->by, msg->iaddr) and not *msg->realby and *msg->igate) {
2766 ptr = strchr(msg->igate, ' ');
2767 if(ptr) {
2768 ptr = strskip_wht(ptr);
2769 if(not isuucp(ptr))
2770 strcpy(msg->realby, ptr);
2771 }
2772 }
2773 }
2774 }
2775
2776 // Make the index to the line index as allowed by config
2777 MsgLineReIndex(msg);
2778 }
2779
2780
2781 // ------------------------------------------------------------------
2782
MsgLineReIndex(GMsg * msg,int viewhidden,int viewkludge,int viewquote)2783 void MsgLineReIndex(GMsg* msg, int viewhidden, int viewkludge, int viewquote) {
2784
2785 if(viewhidden == -1)
2786 viewhidden = AA->Viewhidden();
2787 if(viewkludge == -1)
2788 viewkludge = AA->Viewkludge();
2789 if(viewquote == -1)
2790 viewquote = AA->Viewquote();
2791
2792 int x;
2793 Line* line;
2794
2795 throw_xrelease(msg->line);
2796 line = msg->lin;
2797 msg->lines = 0;
2798 while(line) {
2799 msg->lines++;
2800 if(line->next) {
2801 if(line->type & GLINE_QUOT) {
2802 if(not (line->next->type & GLINE_QUOT) and not strblank(line->next->txt.c_str())) {
2803 if(CFG->switches.get(quotespacing)) {
2804 line = AddLine(line, "");
2805 msg->lines++;
2806 }
2807 }
2808 }
2809 else {
2810 const char *posn, *posn2 = line->txt.c_str();
2811 if(msg->attr.pos() and ((posn = striinc("@position", posn2)) != NULL)) {
2812 line->txt.erase(posn - posn2, 9);
2813 line->type |= GLINE_POSI;
2814 }
2815 if((line->next->type & GLINE_QUOT) and not strblank(line->txt.c_str())) {
2816 if(CFG->switches.get(quotespacing)) {
2817 line = AddLine(line, "");
2818 msg->lines++;
2819 }
2820 }
2821 }
2822 }
2823 line = line->next;
2824 }
2825
2826 msg->line = (Line**)throw_xcalloc(msg->lines+2, sizeof(Line*)); // FIXME: Memory Leak
2827
2828 x = 0;
2829 msg->lines = 0;
2830
2831 char qbuf[MAXQUOTELEN];
2832 char qbuf0[MAXQUOTELEN];
2833 uint qlen = 0;
2834 int qmatches = 0;
2835
2836 *qbuf0 = NUL;
2837 for(line = msg->lin; line != NULL; line = line->next) {
2838 if(line->type & GLINE_KLUD) {
2839 *qbuf0 = NUL;
2840 qmatches = 0;
2841 if(not viewkludge) {
2842 continue;
2843 }
2844 }
2845 else if(line->type & GLINE_HIDD) {
2846 *qbuf0 = NUL;
2847 qmatches = 0;
2848 if(not viewhidden) {
2849 continue;
2850 }
2851 }
2852 else if (line->type & GLINE_TXTH)
2853 {
2854 *qbuf0 = NUL;
2855 qmatches = 0;
2856 continue;
2857 }
2858 else if(line->type & GLINE_QUOT) {
2859 if(not viewquote) {
2860 GetQuotestr(line->txt.c_str(), qbuf, &qlen);
2861 if(not cmp_quotes(qbuf0, qbuf)) {
2862 strcpy(qbuf0, qbuf);
2863 qmatches = 0;
2864 }
2865 const char *p = line->txt.c_str()+qlen;
2866 while(*p != NUL) {
2867 if(isxalnum(*p)) {
2868 qmatches++;
2869 break;
2870 }
2871 ++p;
2872 }
2873 if(qmatches != 1) {
2874 continue;
2875 }
2876 }
2877 }
2878 else {
2879 *qbuf0 = NUL;
2880 qmatches = 0;
2881 }
2882 msg->line[x++] = line;
2883 msg->lines++;
2884 }
2885
2886 msg->line[x] = NULL; // Mark end of index
2887
2888 // Calculate quote percent
2889 int quotes = 0, nonquotes = 0;
2890
2891 line = msg->lin;
2892 while(line) {
2893 if(not (line->type & (GLINE_KLUDGE|GLINE_TEAR|GLINE_ORIG))) {
2894 if(line->txt.c_str()) {
2895 int n = line->txt.length();
2896 nonquotes += n;
2897 if(line->type & GLINE_QUOT)
2898 quotes += n;
2899 }
2900 }
2901 line = line->next;
2902 }
2903 msg->quotepct = 100-Pct(nonquotes, quotes);
2904 }
2905
2906
2907 // ------------------------------------------------------------------
2908
IsQuotedPrintable(const char * encoding)2909 bool IsQuotedPrintable(const char *encoding) {
2910
2911 if(striinc("LATIN1QP", encoding))
2912 return true;
2913 else {
2914 const char *lencoding = strlword(encoding);
2915 int len = strlen(lencoding);
2916 if((len > 2) and strnieql("QP", lencoding+len-2, 2))
2917 return true;
2918 }
2919 return false;
2920 }
2921
2922
2923 // ------------------------------------------------------------------
2924
2925 static char qpencodingbuf[100];
2926
MakeQuotedPrintable(const char * encoding)2927 char *MakeQuotedPrintable(const char *encoding) {
2928
2929 strxmerge(qpencodingbuf, sizeof(qpencodingbuf), strlword(encoding), "QP", NULL);
2930 return qpencodingbuf;
2931 }
2932
2933 // ------------------------------------------------------------------
2934
ExtractPlainCharset(const char * encoding)2935 char *ExtractPlainCharset(const char *encoding) {
2936
2937 strxcpy(qpencodingbuf, strlword(encoding), sizeof(qpencodingbuf));
2938 int len = strlen(qpencodingbuf);
2939 if(len > 2)
2940 qpencodingbuf[len-2] = NUL;
2941 return qpencodingbuf;
2942 }
2943
2944
2945 // ------------------------------------------------------------------
2946
Latin2ISO(char * iso_encoding,const char * latin_encoding)2947 char *Latin2ISO(char *iso_encoding, const char *latin_encoding) {
2948
2949 static const char *isono[] = { "15", "1", "2", "3", "4", "9", "10", "13", "14", "15" };
2950 int chsno = atoi(latin_encoding+5);
2951 if(chsno < 0) chsno = -chsno; // support for both latin-1 and latin1
2952 chsno = chsno > sizeof(isono)/sizeof(const char *) ? 0 : chsno;
2953 return strxmerge(iso_encoding, 12, "iso-8859-", isono[chsno], NULL);
2954 }
2955
2956
2957 // ------------------------------------------------------------------
2958
ISO2Latin(char * latin_encoding,const char * iso_encoding)2959 char *ISO2Latin(char *latin_encoding, const char *iso_encoding) {
2960
2961 static const char *latinno[] = { NULL, "1", "2", "3", "4", NULL, NULL, NULL, NULL, "5", "6", NULL, NULL, "7", "8", "9" };
2962 int chsno = atoi(strstr(iso_encoding, "8859")+5);
2963 chsno = chsno > sizeof(latinno)/sizeof(const char *) ? 0 : chsno;
2964 if(latinno[chsno] == NULL)
2965 return strxmerge(latin_encoding, 12, iso_encoding, NULL);
2966 else
2967 return strxmerge(latin_encoding, 8, "latin-", latinno[chsno], NULL);
2968 }
2969
2970
2971 // ------------------------------------------------------------------
2972
CheckLevel(const char * imp,const char * imp2,int n,int & current_table)2973 static bool CheckLevel(const char* imp, const char* imp2, int n, int ¤t_table)
2974 {
2975 const char *ptr = striinc(imp2, imp);
2976 ptr += strlen(imp2);
2977 strskip_wht(ptr);
2978
2979 int level = atoi(ptr);
2980
2981 if (CharTable && (n == current_table) && (level <= CharTable->level))
2982 return true;
2983
2984 gfile fp(AddPath(CFG->goldpath, CFG->xlatged), "rb", CFG->sharemode);
2985 if (fp.isopen())
2986 {
2987 if (!CharTable) CharTable = (Chs*)throw_calloc(1, sizeof(Chs));
2988 fp.FseekSet(n, sizeof(Chs));
2989 fp.Fread(CharTable, sizeof(Chs));
2990
2991 ChsTP = CharTable->t;
2992 current_table = n;
2993
2994 // Disable softcr translation unless DISPSOFTCR is enabled
2995 if (not WideDispsoftcr)
2996 {
2997 char* tptr = (char*)ChsTP[SOFTCR];
2998 *tptr++ = 1;
2999 *tptr = SOFTCR;
3000 }
3001
3002 if (level <= CharTable->level) return true;
3003 }
3004
3005 return false;
3006 }
3007
3008
3009 // ------------------------------------------------------------------
3010
LoadCharset(const char * imp,const char * exp,int query)3011 int LoadCharset(const char* imp, const char* exp, int query) {
3012
3013 static int current_table = -1;
3014 int n;
3015
3016 switch(query) {
3017 case 1:
3018 return current_table;
3019 default:
3020 break;
3021 }
3022
3023 #ifdef HAS_ICONV
3024 if( iconv_cd != (iconv_t)(-1) )
3025 iconv_close(iconv_cd);
3026 iconv_cd = iconv_open(exp, imp);
3027 if(iconv_cd != (iconv_t)(-1) )
3028 LOG.printf("iconv is initialised to convert from %s to %s", imp, exp);
3029 else
3030 LOG.printf("Can't initialise iconv to convert from %s to %s", imp, exp);
3031 #endif
3032
3033 // Find and load charset table
3034 std::vector<Map>::iterator xlt;
3035 for(n = 0, xlt = CFG->xlatcharset.begin(); xlt != CFG->xlatcharset.end(); xlt++, n++)
3036 {
3037 if (!striinc(xlt->exp, exp)) continue;
3038
3039 bool imp_found = make_bool(strnieql(xlt->imp, imp, strlen(xlt->imp)));
3040 if (imp_found) imp_found = CheckLevel(imp, xlt->imp, n, current_table);
3041
3042 std::vector< std::pair<std::string, gstrarray> >::iterator als;
3043 for (als = CFG->xlatcharsetalias.begin();
3044 !imp_found && (als != CFG->xlatcharsetalias.end()); als++)
3045 {
3046 if (strieql(xlt->imp, als->first.c_str()))
3047 {
3048 for (gstrarray::iterator it = als->second.begin(); !imp_found && (it != als->second.end()); it++)
3049 if (striinc(it->c_str(), imp))
3050 imp_found = CheckLevel(imp, it->c_str(), n, current_table);
3051 }
3052 }
3053
3054 if (imp_found) return CharTable->level;
3055 }
3056
3057 // No matching table found
3058 throw_release(CharTable);
3059 ChsTP = NULL;
3060 current_table = -1;
3061 return 0;
3062 }
3063
3064
3065 // ------------------------------------------------------------------
3066
DeleteLine(Line * line)3067 Line* DeleteLine(Line* line) {
3068
3069 Line* nextline = NULL;
3070
3071 // Link next and previous lines and release this line
3072
3073 if(line) {
3074 if(line->prev) {
3075 line->prev->next = line->next;
3076 nextline = line->prev;
3077 }
3078 if(line->next) {
3079 line->next->prev = line->prev;
3080 nextline = line->next;
3081 }
3082 throw_xdelete(line);
3083 }
3084
3085 return nextline;
3086 }
3087
3088
3089 // ------------------------------------------------------------------
3090
InsertLine(Line * newline,Line * oldline,int pos)3091 Line* InsertLine(Line* newline, Line* oldline, int pos) {
3092
3093 if(oldline) {
3094 if(pos >= DIR_BELOW) {
3095 newline->prev = oldline;
3096 newline->next = oldline->next;
3097 if(oldline->next)
3098 oldline->next->prev = newline;
3099 oldline->next = newline;
3100 }
3101 else {
3102 newline->prev = oldline->prev;
3103 newline->next = oldline;
3104 if(oldline->prev)
3105 oldline->prev->next = newline;
3106 oldline->prev = newline;
3107 }
3108 }
3109 return newline;
3110 }
3111
3112
3113 // ------------------------------------------------------------------
3114
FirstLine(Line * line)3115 Line* FirstLine(Line* line) {
3116
3117 if(line)
3118 while(line->prev)
3119 line = line->prev;
3120 return line;
3121 }
3122
3123
3124 // ------------------------------------------------------------------
3125
LastLine(Line * line)3126 Line* LastLine(Line* line) {
3127
3128 if(line)
3129 while(line->next)
3130 line = line->next;
3131 return line;
3132 }
3133
3134
3135 // ------------------------------------------------------------------
3136
AddLine(Line * line,const char * buf,int where)3137 Line* AddLine(Line* line, const char* buf, int where) {
3138
3139 Line* newline = new Line(buf);
3140 throw_xnew(newline);
3141 newline->type = GLINE_HARD;
3142 newline->color = C_READW;
3143
3144 return InsertLine(newline, line, where);
3145 }
3146
3147
3148 // ------------------------------------------------------------------
3149
AddLine(Line * line,const char * buf)3150 Line* AddLine(Line* line, const char* buf) {
3151
3152 return AddLine(line, buf, DIR_BELOW);
3153 }
3154
3155
3156 // ------------------------------------------------------------------
3157
AddLineFast(Line * oldline,char * text)3158 Line* AddLineFast(Line* oldline, char* text) {
3159
3160 Line* newline = new Line(text);
3161 throw_xnew(newline);
3162 newline->type = GLINE_HARD;
3163 newline->color = C_READW;
3164 newline->prev = oldline;
3165 newline->next = oldline->next;
3166 if(oldline->next)
3167 oldline->next->prev = newline;
3168 oldline->next = newline;
3169 return newline;
3170 }
3171
3172
3173 // ------------------------------------------------------------------
3174
AddKludge(Line * line,char * buf,int where)3175 Line* AddKludge(Line* line, char* buf, int where) {
3176
3177 Line* newline = new Line(buf);
3178 throw_xnew(newline);
3179 newline->type = GLINE_HARD|GLINE_KLUD;
3180 newline->color = C_READK;
3181 return InsertLine(newline, line, where);
3182 }
3183
3184
3185 // ------------------------------------------------------------------
3186
AddLineF(Line * & line,const char * format,...)3187 Line* AddLineF(Line*& line, const char* format, ...) {
3188
3189 char buf[256];
3190 va_list argptr;
3191 va_start(argptr, format);
3192 vsprintf(buf, format, argptr);
3193 va_end(argptr);
3194 line = AddLine(line, buf);
3195 return line;
3196 }
3197
3198
3199 // ------------------------------------------------------------------
3200
AddHexdump(Line * & line,void * data,size_t datalen)3201 Line* AddHexdump(Line*& line, void* data, size_t datalen) {
3202
3203 char buf[256];
3204 uint pos = 0;
3205 char* ptr = (char*)data;
3206
3207 while (pos < datalen)
3208 {
3209 uint dataleft = datalen - pos;
3210 gsprintf(PRINTF_DECLARE_BUFFER(buf), "%04X ", pos);
3211 HexDump16(buf+7, ptr, (dataleft < 16) ? dataleft : 16, HEX_DUMP2);
3212 line = AddLine(line, buf);
3213 ptr += 16;
3214 pos += 16;
3215 }
3216
3217 return line;
3218 }
3219
3220
3221 // ------------------------------------------------------------------
3222
ParseInternetAddr(char * __string,char * __name,char * __addr,bool detect_charset)3223 char* ParseInternetAddr(char* __string, char* __name, char* __addr, bool detect_charset) {
3224
3225 *__name = *__addr = NUL;
3226 char* commaptr = NULL;
3227
3228 if(strchr(__string, ',')) {
3229 bool inquotes = false;
3230 commaptr = __string;
3231 while(commaptr) {
3232 if(*commaptr == '\"')
3233 inquotes = not inquotes;
3234 else if((*commaptr == ',') and not inquotes) {
3235 *commaptr = NUL;
3236 break;
3237 }
3238 if(not *commaptr)
3239 commaptr = NULL;
3240 else
3241 commaptr++;
3242 }
3243 }
3244
3245 char* p;
3246 if((p = strrchr(__string, '>')) != NULL)
3247 *(++p) = NUL;
3248
3249 char* endchar = __string + strlen(__string) - 1;
3250 if(*endchar == /*(*/ ')') {
3251 char* begchar = endchar;
3252 int pcnt = 0;
3253 while(begchar > __string) {
3254 if(*begchar == /*(*/ ')')
3255 pcnt++;
3256 else if(*begchar == '(' /*)*/)
3257 pcnt--;
3258 if(pcnt == 0)
3259 break;
3260 begchar--;
3261 }
3262 if(*begchar == '(' /*)*/)
3263 begchar++;
3264 strbtrim(strxcpy(__name, begchar, MinV((size_t)(endchar-begchar)+1, (size_t)sizeof(INam))));
3265 strbtrim(strxcpy(__addr, __string, MinV((size_t)(begchar-__string), (size_t)sizeof(IAdr))));
3266 }
3267 else if(*endchar == '>') {
3268 char* endaddr = endchar;
3269 while(*endchar != '<' and endchar > __string)
3270 endchar--;
3271 char* begaddr = endchar;
3272 if(*endchar == '<') {
3273 begaddr++;
3274 if (endchar > __string) endchar--;
3275 }
3276 __string = strskip_wht(__string);
3277 strbtrim(strxcpy(__name, __string, MinV((size_t)(endchar-__string)+1, (size_t)sizeof(INam))));
3278 strbtrim(strxcpy(__addr, begaddr, MinV((size_t)(endaddr-begaddr)+1, (size_t)sizeof(IAdr))));
3279 }
3280 else {
3281 strxcpy(__addr, __string, sizeof(IAdr));
3282 }
3283
3284 if(*__addr == '@') {
3285 char* ptr = strchr(__addr, ':');
3286 if(ptr)
3287 memmove(__addr, ptr+1, strlen(ptr));
3288 }
3289
3290 if(commaptr)
3291 *commaptr = ',';
3292
3293 StripQuotes(__name);
3294
3295 if(not strchr(__addr, '@'))
3296 *__addr = NUL;
3297
3298 strxmimecpy(__name, __name, 0, strlen(__name)+1, detect_charset);
3299
3300 return __name;
3301 }
3302
3303
3304 // ------------------------------------------------------------------
3305
InvalidateControlInfo(GMsg * msg)3306 void InvalidateControlInfo(GMsg* msg) {
3307
3308 Line* line = msg->lin;
3309 char buf[256];
3310
3311 while(line) {
3312
3313 if(not (line->type & (GLINE_TEAR | GLINE_ORIG))) {
3314
3315 strcpy(buf, line->txt.c_str());
3316
3317 // Invalidate tearline
3318 if(not CFG->invalidate.tearline.first.empty())
3319 doinvalidate(buf, CFG->invalidate.tearline.first.c_str(), CFG->invalidate.tearline.second.c_str(), true);
3320 else
3321 doinvalidate(buf, "---", "-+-", true);
3322
3323 // Invalidate originline
3324 if(not CFG->invalidate.origin.first.empty())
3325 doinvalidate(buf, CFG->invalidate.origin.first.c_str(), CFG->invalidate.origin.second.c_str());
3326 else
3327 doinvalidate(buf, " * Origin: ", " + Origin: ");
3328
3329 // Invalidate SEEN-BY's
3330 if(not CFG->invalidate.seenby.first.empty())
3331 doinvalidate(buf, CFG->invalidate.seenby.first.c_str(), CFG->invalidate.seenby.second.c_str());
3332 else
3333 doinvalidate(buf, "SEEN-BY: ", "SEEN+BY: ");
3334
3335 if(stricmp(buf, line->txt.c_str())) {
3336 line->type &= ~GLINE_KLUDGE;
3337 line->kludge = 0;
3338 line->color = C_READW;
3339 line->txt = buf;
3340 }
3341
3342 }
3343 line = line->next;
3344 }
3345 }
3346
3347
3348 // ------------------------------------------------------------------
3349