1 /*
2 * MultiMail offline mail reader
3 * message editing (continuation of the LetterWindow class)
4
5 Copyright 1996 Kolossvary Tamas <thomas@tvnet.hu>
6 Copyright 1997 John Zero <john@graphisoft.hu>
7 Copyright 1997-2019 William McBrine <wmcbrine@gmail.com>
8 Distributed under the GNU General Public License, version 3 or later. */
9
10 #include "interfac.h"
11
set_Letter_Params(net_address & nm,const char * to)12 void LetterWindow::set_Letter_Params(net_address &nm, const char *to)
13 {
14 NM = nm;
15 delete[] To;
16 To = strdupplus(to);
17 }
18
QuoteText(FILE * reply)19 void LetterWindow::QuoteText(FILE *reply)
20 {
21 char TMP[81];
22 int i;
23 bool inet = !(!(mm.areaList->getType() & INTERNET));
24 const char *From = mm.letterList->getFrom();
25
26 int width = mm.resourceObject->getInt(QuoteWrapCols);
27 if ((width < 20) || (width > 80))
28 width = 78;
29 width -= inet ? 2 : 6;
30
31 char c;
32 const char *s, *quotestr = mm.resourceObject->get(inet ? InetQuote :
33 QuoteHead);
34
35 // Format header:
36
37 while ((c = *quotestr++) != 0) {
38 if (c != '%')
39 fputc(c, reply);
40 else {
41 s = 0;
42 switch (tolower(*quotestr)) {
43 case 'f':
44 s = From;
45 break;
46 case 't':
47 s = mm.letterList->getTo();
48 break;
49 case 'd':
50 s = mm.letterList->getDate();
51 break;
52 case 's':
53 s = mm.letterList->getSubject();
54 break;
55 case 'a':
56 s = mm.areaList->getDescription();
57 break;
58 case 'n':
59 s = "\n";
60 break;
61 case '%':
62 s = "%";
63 }
64 if (s) {
65 sprintf(TMP, "%.80s", s);
66 letterconv_in(TMP);
67 fputs(TMP, reply);
68 quotestr++;
69 }
70 }
71 }
72 fputs("\n\n", reply);
73
74 // Set quote initials if necessary:
75
76 if (!inet) {
77 char initials[4];
78
79 // Start off with the first two letters of the name
80 strncpy(initials, From, 2);
81 initials[2] = '\0';
82 initials[3] = '\0';
83
84 // Find the first letters of each of the second and last
85 // words in the name, if available
86 i = 1;
87 for (int j = 1; j < 3; j++) {
88 bool end = false;
89 while (From[i] && !end) {
90 if ((From[i - 1] == ' ') && (From[i] != ' ')) {
91 initials[j] = From[i];
92 if (j == 1)
93 end = true;
94 }
95 i++;
96 }
97 }
98
99 letterconv_in(initials);
100 sprintf(TMP, " %s> ", initials);
101 } else
102 strcpy(TMP, "> ");
103
104 // Output quoted text:
105
106 MakeChain(width, true);
107
108 for (i = 0; i < NumOfLines; i++) {
109 Line *curr = linelist[i];
110
111 if (!((Sigline == curr->attr) ||
112 (!curr->length && (i < (NumOfLines - 1)) &&
113 (Sigline == linelist[i + 1]->attr) ))) {
114
115 fputs(curr->length ? ((Quoted == curr->attr) ?
116 (inet ? ">" : ((curr->text[0] == ' ') ? "" : " ")) :
117 TMP) : (inet ? ">" : ""), reply);
118
119 curr->out(reply);
120 }
121 }
122
123 MakeChain(COLS);
124 }
125
HeaderLine(ShadowedWin & win,char * buf,int limit,int pos,coltype color)126 int LetterWindow::HeaderLine(ShadowedWin &win, char *buf, int limit,
127 int pos, coltype color)
128 {
129 areaconv_in(buf);
130 int getit = win.getstring(pos, 8, buf, limit, color, color);
131 areaconv_out(buf);
132 return getit;
133 }
134
EnterHeader(char * FROM,char * TO,char * SUBJ,bool & privat)135 int LetterWindow::EnterHeader(char *FROM, char *TO, char *SUBJ, bool &privat)
136 {
137 static const char *noyes[] = { "No", "Yes" };
138
139 char NETADD[100];
140 int result, current, maxitems = 2;
141 bool end = false;
142 bool hasNet = mm.areaList->isEmail();
143 bool hasNews = mm.areaList->isUsenet();
144 bool hasTo = hasNews || mm.areaList->hasTo();
145
146 if (hasNet) {
147 sprintf(NETADD, "%.99s", (const char *) NM);
148 maxitems++;
149 } else
150 NM.isSet = false;
151
152 if (hasTo)
153 maxitems++;
154
155 ShadowedWin rep_header(maxitems + 2, COLS - 4, (LINES / 2) - 3, C_LETEXT);
156
157 rep_header.put(1, 2, "From:");
158 if (hasTo)
159 rep_header.put(2, 2, " To:");
160 if (hasNet)
161 rep_header.put(3, 2, "Addr:");
162 rep_header.put(maxitems, 2, "Subj:");
163
164 rep_header.attrib(C_LEGET2);
165 areaconv_in(FROM);
166 rep_header.put(1, 8, FROM, 69);
167 areaconv_out(FROM);
168
169 if (hasNet && !NM.isSet) {
170 //NM.isInternet = mm.areaList->isInternet();
171 TO[0] = '\0';
172 current = 1;
173 } else {
174 if (hasTo) {
175 rep_header.attrib(C_LEGET1);
176 areaconv_in(TO);
177 rep_header.put(2, 8, TO, 69);
178 areaconv_out(TO);
179 }
180 if (hasNet) {
181 rep_header.attrib(C_LEGET2);
182 areaconv_in(NETADD);
183 rep_header.put(3, 8, NETADD, 69);
184 areaconv_out(NETADD);
185 }
186 current = maxitems - 1;
187 }
188
189 rep_header.update();
190
191 do {
192 result = HeaderLine(rep_header, (current == (maxitems - 1)) ?
193 SUBJ : (((current == 2) && hasNet) ? NETADD : ((current &&
194 hasTo) ? TO : FROM)), ((current == 1) && hasNews) ? 512 :
195 ((current == (maxitems - 1)) ? mm.areaList->maxSubLen() :
196 (((current == 2) && NM.isInternet) ? 72 :
197 mm.areaList->maxToLen())), current + 1, (current & 1) ?
198 C_LEGET1 : C_LEGET2);
199
200 switch (result) {
201 case 0:
202 end = true;
203 break;
204 case 1:
205 current++;
206 if (current == maxitems)
207 end = true;
208 break;
209 case 2:
210 if (current > 0)
211 current--;
212 break;
213 case 3:
214 if (current < maxitems - 1)
215 current++;
216 }
217 } while (!end);
218
219 if (result) {
220 int pmode = (!hasNet ? mm.areaList->hasPublic() : 0) +
221 ((mm.areaList->hasPrivate() &&
222 !mm.areaList->isUsenet()) ? 2 : 0);
223
224 if (hasNet)
225 NM = NETADD;
226
227 switch (pmode) {
228 case 1:
229 privat = false;
230 break;
231 case 2:
232 privat = true;
233 break;
234 case 3:
235 if (!ui->WarningWindow("Make letter private?", privat ? 0 : noyes))
236 privat = !privat;
237 }
238 }
239 return result;
240 }
241
reconvert(const char * reply_filename)242 long LetterWindow::reconvert(const char *reply_filename)
243 {
244 FILE *src, *dest;
245
246 char *outname = mytmpnam();
247 src = fopen(reply_filename, "rt");
248 dest = fopen(outname, "wt");
249
250 fseek(src, 0, SEEK_END);
251 long replen = ftell(src);
252 rewind(src);
253
254 char *body = new char[((replen > MAXBLOCK) ? MAXBLOCK : replen) + 1];
255
256 long totlen = replen;
257 replen = 0;
258 while (totlen > MAXBLOCK) {
259 long blklen = (long) fread(body, 1, MAXBLOCK, src);
260 body[blklen] = '\0';
261 areaconv_out(body);
262 replen += (long) fwrite(body, 1, blklen, dest);
263 totlen -= blklen;
264 }
265 totlen = (long) fread(body, 1, totlen, src);
266 fclose(src);
267
268 body[totlen] = '\0';
269 areaconv_out(body);
270 while (body[totlen - 1] == '\n')
271 totlen--;
272
273 replen += (long) fwrite(body, 1, totlen, dest);
274 fclose(dest);
275
276 delete[] body;
277
278 remove(reply_filename);
279 rename(outname, reply_filename);
280
281 delete[] outname;
282
283 return replen;
284 }
285
setToFrom(char key,char * TO,char * FROM)286 void LetterWindow::setToFrom(char key, char *TO, char *FROM)
287 {
288 char format[7];
289 sprintf(format, "%%.%ds", mm.areaList->maxToLen());
290
291 bool usealias = mm.areaList->getUseAlias();
292 if (usealias) {
293 const char *name = mm.packet->getAliasName();
294 sprintf(FROM, format, name ? name : "");
295 if (!FROM[0])
296 usealias = false;
297 }
298 if (!usealias) {
299 const char *name = mm.packet->getLoginName();
300 sprintf(FROM, format, name ? name : "");
301 }
302
303 if (mm.areaList->isUsenet()) {
304 const char *newsgrps = 0;
305
306 if (key != 'E') {
307 newsgrps = mm.letterList->getFollow();
308 if (!newsgrps)
309 newsgrps = mm.letterList->getNewsgrps();
310 }
311 if (!newsgrps)
312 newsgrps = mm.areaList->getDescription();
313
314 sprintf(TO, "%.512s", newsgrps);
315 } else
316 if (key == 'E')
317 strcpy(TO, (To ? To : "All"));
318 else
319 if (mm.areaList->isInternet()) {
320 if (key == 'O') {
321 sprintf(TO, format, fromName(mm.letterList->getTo()));
322 NM = fromAddr(mm.letterList->getTo());
323 } else {
324 const char *rep = mm.letterList->getReply();
325
326 sprintf(TO, format, mm.letterList->getFrom());
327 if (rep)
328 NM = fromAddr(rep);
329 }
330 } else
331 sprintf(TO, format, (key == 'O') ? mm.letterList->getTo() :
332 mm.letterList->getFrom());
333 }
334
EnterLetter(int replyto_area,char key)335 void LetterWindow::EnterLetter(int replyto_area, char key)
336 {
337 FILE *reply;
338 char FROM[74], TO[514], SUBJ[514];
339 const char *orig_id;
340
341 mystat fileStat;
342 time_t oldtime;
343
344 long replen, replyto_num;
345 bool privat;
346
347 mm.areaList->gotoArea(replyto_area);
348
349 bool news = mm.areaList->isUsenet();
350 bool inet = news || mm.areaList->isInternet();
351
352 // HEADER
353
354 setToFrom(key, TO, FROM);
355
356 if (key == 'E')
357 SUBJ[0] = '\0'; //we don't have subject yet
358 else {
359 const char *s = stripre(mm.letterList->getSubject());
360 int len = strlen(s);
361
362 bool useRe = (inet || mm.resourceObject->getInt(ReOnReplies))
363 && ((len + 4) <= mm.areaList->maxSubLen());
364 sprintf(SUBJ, useRe ? "Re: %.509s" : "%.512s", s);
365 }
366
367 privat = (key == 'E') ? false : mm.letterList->getPrivate();
368
369 if (!EnterHeader(FROM, TO, SUBJ, privat)) {
370 NM.isSet = false;
371 delete[] To;
372 To = 0;
373 ui->areas.Select();
374 ui->redraw();
375 return;
376 }
377
378 // Don't use refnum if posting in different area:
379
380 replyto_num = ((key == 'E') || (key == 'N') || (replyto_area !=
381 mm.letterList->getAreaID())) ? 0 : mm.letterList->getMsgNum();
382
383 orig_id = replyto_num ? mm.letterList->getMsgID() : 0;
384
385 // BODY
386
387 char *reply_filename = mytmpnam();
388
389 // Quote the old text
390
391 if (key != 'E') {
392 reply = fopen(reply_filename, "wt");
393 QuoteText(reply);
394 fclose(reply);
395 }
396 fileStat.init(reply_filename);
397 oldtime = fileStat.fdate();
398
399 // Edit the reply
400
401 edit(reply_filename);
402 ui->areas.Select();
403 ui->redraw();
404
405 // Check if modified
406
407 fileStat.init(reply_filename);
408 if (fileStat.fdate() == oldtime)
409 if (ui->WarningWindow("Cancel this letter?")) {
410 remove(reply_filename);
411 ui->redraw();
412 return;
413 }
414
415 // Mark original as replied
416
417 if (key != 'E') {
418 int origatt = mm.letterList->getStatus();
419 mm.letterList->setStatus(origatt | MS_REPLIED);
420 if (!(origatt & MS_REPLIED))
421 ui->setAnyRead();
422 }
423
424 reply = fopen(reply_filename, "at");
425
426 // Signature
427
428 bool sigset = false;
429
430 const char *sg = mm.resourceObject->get(sigFile);
431 if (sg && *sg) {
432 FILE *s = fopen(sg, "rt");
433 if (s) {
434 int c;
435
436 fputs(inet ? "\n-- \n" : "\n", reply);
437 while ((c = fgetc(s)) != EOF)
438 if (c != '\r')
439 fputc(c, reply);
440 fclose(s);
441
442 sigset = true;
443 }
444 }
445
446 // Tagline
447
448 bool useTag = mm.resourceObject->getInt(UseTaglines) &&
449 ui->taglines.NumOfItems() && ui->Tagwin();
450 if (useTag)
451 fprintf(reply, inet ? (sigset ? "\n%s\n" : "\n-- \n%s\n") :
452 "\n... %s\n", ui->taglines.getCurrent());
453 else
454 if (!inet)
455 fprintf(reply, " \n");
456
457 // Tearline (not for Blue Wave -- it does its own)
458
459 if (!inet) {
460 const char *tear = mm.areaList->getTear();
461
462 if (tear)
463 fprintf(reply, "%s\n", tear);
464 }
465
466 fclose(reply);
467
468 // Reconvert the text
469
470 mm.areaList->gotoArea(replyto_area);
471 replen = reconvert(reply_filename);
472
473 mm.areaList->enterLetter(replyto_area, FROM, news ? "All" : TO,
474 SUBJ, orig_id, news ? TO : 0, replyto_num, privat, NM,
475 reply_filename, replen);
476
477 delete[] reply_filename;
478
479 NM.isSet = false;
480 delete[] To;
481 To = 0;
482
483 ui->areas.Select();
484 ui->setUnsaved();
485 ui->redraw();
486 }
487
forward_header(FILE * fd,const char * FROM,const char * TO,const char * SUBJ,int replyto_area,bool is_reply)488 void LetterWindow::forward_header(FILE *fd, const char *FROM,
489 const char *TO, const char *SUBJ, int replyto_area, bool is_reply)
490 {
491 enum {area, date, from, to, subj, items};
492 static const char *names[items] = {"ly in", "ly on", "ly by",
493 "ly to", " subj"};
494 char Header[512], *p;
495 int j;
496
497 int oldarea = mm.letterList->getAreaID();
498 mm.areaList->gotoArea(mm.letterList->getAreaID());
499
500 const char *head[items] = {
501 mm.areaList->getDescription(), mm.letterList->getDate(),
502 mm.letterList->getFrom(), mm.letterList->getTo(),
503 mm.letterList->getSubject()
504 };
505
506 const char *org[items] = {
507 0, 0, FROM, TO, SUBJ
508 };
509
510 bool use[items];
511
512 use[area] = (oldarea != replyto_area);
513 use[date] = !is_reply;
514 for (j = from; j < items; j++)
515 use[j] = !(!strcasecmp(org[j], head[j]));
516
517 ui->areas.Select();
518
519 bool anyused = false;
520
521 for (j = 0; j < items; j++)
522 if (use[j]) {
523 p = Header + sprintf(Header, "%.511s", head[j]);
524 if (((j == from) && mm.areaList->isEmail())
525 || ((j == to) && mm.areaList->isReplyArea()))
526
527 netAdd(p);
528 letterconv_in(Header);
529 fprintf(fd, " * Original%s: %s\n", names[j], Header);
530 anyused = true;
531 }
532
533 if (anyused)
534 fprintf(fd, "\n");
535 }
536
EditLetter(bool forwarding)537 void LetterWindow::EditLetter(bool forwarding)
538 {
539 FILE *reply;
540 char FROM[74], TO[514], SUBJ[514];
541 long siz;
542 int replyto_num, replyto_area;
543 bool privat, newsflag = false;
544
545 bool is_reply_area = (mm.areaList->getAreaNo() == REPLY_AREA);
546
547 NM = mm.letterList->getNetAddr();
548
549 replyto_area = ui->areaMenu();
550 if (replyto_area == -1)
551 return;
552
553 // The refnum is only good for the original area:
554
555 replyto_num = (replyto_area != mm.letterList->getAreaID()) ?
556 0 : mm.letterList->getReplyTo();
557
558 char *msgid = strdupplus(mm.letterList->getMsgID());
559
560 mm.areaList->gotoArea(replyto_area);
561
562 if (forwarding) {
563 if (mm.areaList->isEmail()) {
564 ui->areas.Select();
565 ui->addressbook();
566 mm.areaList->gotoArea(replyto_area);
567 } else {
568 NM.isSet = false;
569 newsflag = mm.areaList->isUsenet();
570 }
571 setToFrom('E', TO, FROM);
572 sprintf(SUBJ, "%.513s", mm.letterList->getSubject());
573 privat = false;
574 } else {
575 const char *newsgrps = mm.letterList->getNewsgrps();
576 newsflag = !(!newsgrps);
577
578 strcpy(FROM, mm.letterList->getFrom());
579 sprintf(TO, "%.512s", newsflag ? newsgrps : mm.letterList->getTo());
580 sprintf(SUBJ, "%.512s", mm.letterList->getSubject());
581 privat = mm.letterList->getPrivate();
582 }
583
584 if (!EnterHeader(FROM, TO, SUBJ, privat)) {
585 NM.isSet = false;
586 ui->areas.Select();
587 ui->redraw();
588 return;
589 }
590
591 DestroyChain(); // current letter's chain reset
592
593 char *reply_filename = mytmpnam();
594
595 reply = fopen(reply_filename, "wt");
596 if (forwarding)
597 forward_header(reply, FROM, TO, SUBJ, replyto_area, is_reply_area);
598
599 letter_body *msgBody = mm.letterList->getBody();
600
601 while (msgBody) {
602 char *body = msgBody->getText();
603 int offset = 0;
604
605 letterconv_in(body);
606
607 // Can't use MakeChain here, or it will wrap the text; so:
608 if (!hidden) // skip hidden lines at start
609 while (*body == 1) {
610 do {
611 body++;
612 offset++;
613 } while (*body && (*body != '\n'));
614 while (*body == '\n') {
615 body++;
616 offset++;
617 }
618 }
619
620 fwrite(body, msgBody->getLength() - offset, 1, reply);
621
622 msgBody = msgBody->next;
623 }
624 fclose(reply);
625
626 edit(reply_filename);
627 siz = reconvert(reply_filename);
628
629 if (!forwarding)
630 mm.areaList->killLetter(mm.letterList->getAreaID(),
631 mm.letterList->getMsgNum());
632
633 mm.areaList->enterLetter(replyto_area, FROM, newsflag ? "All" :
634 TO, SUBJ, msgid, newsflag ? TO : 0, replyto_num, privat,
635 NM, reply_filename, siz);
636
637 delete[] reply_filename;
638 delete[] msgid;
639
640 if (is_reply_area) {
641 mm.letterList->rrefresh();
642 ui->letters.ResetActive();
643 }
644 ui->areas.Select();
645
646 NM.isSet = false;
647
648 ui->redraw();
649 ui->setUnsaved();
650 }
651
SplitLetter(int lines)652 bool LetterWindow::SplitLetter(int lines)
653 {
654 static int eachmax = mm.resourceObject->getInt(MaxLines);
655
656 if (!lines) {
657 char maxlinesA[55];
658
659 sprintf(maxlinesA, "%d", eachmax);
660 if (!ui->savePrompt(
661 "Max lines per part? (WARNING: Split is not reversible!)",
662 maxlinesA) || !sscanf(maxlinesA, "%d", &eachmax))
663
664 return false;
665 }
666 unsigned int maxlines = lines ? lines : eachmax;
667
668 if (maxlines < 20) {
669 ui->nonFatalError("Split at less than 20 lines not allowed");
670 return false;
671 }
672
673 MakeChain(80);
674 unsigned int orglines = NumOfLines;
675 unsigned int parts = (orglines - 1) / maxlines + 1;
676
677 if (parts == 1)
678 return false;
679
680 NM = mm.letterList->getNetAddr();
681
682 int replyto_area = mm.letterList->getAreaID();
683 int replyto_num = mm.letterList->getReplyTo();
684
685 char ORGSUBJ[514], *from, *to, *msgid, *newsgrps;
686
687 from = strdupplus(mm.letterList->getFrom());
688 to = strdupplus(mm.letterList->getTo());
689 msgid = replyto_num ? strdupplus(mm.letterList->getMsgID()) : 0;
690 newsgrps = strdupplus(mm.letterList->getNewsgrps());
691
692 sprintf(ORGSUBJ, "%.510s", mm.letterList->getSubject());
693
694 unsigned int x = parts;
695 unsigned int padsize = 1;
696 while (x /= 10)
697 padsize++;
698
699 bool privat = mm.letterList->getPrivate();
700
701 unsigned int clines = 0;
702
703 mm.areaList->killLetter(replyto_area, mm.letterList->getMsgNum());
704
705 for (unsigned int partno = 1; partno <= parts; partno++) {
706 FILE *reply;
707 char SUBJ[514];
708
709 char *reply_filename = mytmpnam();
710
711 unsigned int endline = (orglines > maxlines) ? maxlines: orglines;
712
713 unsigned long replen = 0;
714 reply = fopen(reply_filename, "wt");
715 for (unsigned int i = clines; i < (clines + endline); i++) {
716 linelist[i]->out(reply);
717 replen += linelist[i]->length + 1;
718 }
719 fclose(reply);
720
721 sprintf(SUBJ, "%.499s (%0*d/%d)", ORGSUBJ, padsize, partno, parts);
722
723 mm.areaList->enterLetter(replyto_area, from, to, SUBJ, msgid,
724 newsgrps, replyto_num, privat, NM, reply_filename, (long) replen);
725
726 delete[] reply_filename;
727
728 clines += endline;
729 orglines -= endline;
730 }
731 delete[] newsgrps;
732 delete[] msgid;
733 delete[] to;
734 delete[] from;
735
736 NM.isSet = false;
737
738 mm.letterList->rrefresh();
739
740 if (!lines) {
741 ui->letters.ResetActive();
742 ui->areas.Select();
743 ui->setUnsaved();
744 }
745 return true;
746 }
747
GetTagline()748 void LetterWindow::GetTagline()
749 {
750 ui->taglines.EnterTagline(tagline1);
751 ReDraw();
752 }
753
EditOriginal()754 bool LetterWindow::EditOriginal()
755 {
756 int old_area = mm.letterList->getAreaID();
757 long old_mnum = mm.letterList->getMsgNum();
758 int orig_area = mm.areaList->getAreaNo();
759 int orig_mnum = mm.letterList->getCurrent();
760 int oldPos = position;
761 position = 0;
762
763 letter_list *old_list = mm.letterList;
764 mm.areaList->gotoArea(REPLY_AREA);
765 mm.areaList->getLetterList();
766 ui->areas.ResetActive();
767
768 bool found = mm.letterList->findReply(old_area, old_mnum);
769
770 if (found && ui->WarningWindow("A reply exists. Re-edit it?"))
771 EditLetter(false);
772 else
773 found = false;
774
775 position = oldPos;
776 delete mm.letterList;
777 mm.letterList = old_list;
778 mm.areaList->gotoArea(orig_area);
779 ui->areas.ResetActive();
780 mm.letterList->gotoLetter(orig_mnum);
781 ui->letters.ResetActive();
782
783 return found;
784 }
785
SplitAll(int lines)786 void LetterWindow::SplitAll(int lines)
787 {
788 letter_list *old_list = 0;
789 statetype state = ui->active();
790 bool list_is_active = (state == letter) || (state == letterlist);
791
792 ui->areas.Select();
793 int orig_area = mm.areaList->getAreaNo();
794
795 bool is_reply_area = (orig_area == REPLY_AREA) && list_is_active;
796
797 if (!is_reply_area) {
798 if (list_is_active)
799 old_list = mm.letterList;
800
801 mm.areaList->gotoArea(REPLY_AREA);
802 mm.areaList->getLetterList();
803 ui->areas.ResetActive();
804 }
805
806 bool anysplit = false;
807 int last = mm.letterList->noOfActive();
808 for (int i = 0; i < last; i++) {
809 mm.letterList->gotoActive(i);
810 if (SplitLetter(lines)) {
811 i--;
812 last--;
813 anysplit = true;
814 }
815 }
816
817 if (is_reply_area)
818 ui->letters.ResetActive();
819 else {
820 delete mm.letterList;
821 if (list_is_active)
822 mm.letterList = old_list;
823 }
824 mm.areaList->gotoArea(orig_area);
825 ui->areas.ResetActive();
826
827 if ((state == letter) && !is_reply_area)
828 MakeChain(COLS);
829
830 if (anysplit)
831 ui->nonFatalError("Some replies were split");
832 }
833