// ------------------------------------------------------------------ // GoldED+ // Copyright (C) 1990-1999 Odinn Sorensen // Copyright (C) 1999-2000 Alexander S. Aganichev // ------------------------------------------------------------------ // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License as // published by the Free Software Foundation; either version 2 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, // MA 02111-1307 USA // ------------------------------------------------------------------ // $Id$ // ------------------------------------------------------------------ // Mega-functions to handle creation of msgs :-( // ------------------------------------------------------------------ #include // ------------------------------------------------------------------ static std::vector post_xparea; bool akamatchreply = false; // ------------------------------------------------------------------ std::string &strtrimline(std::string &p) { if(not p.empty()) { std::string::iterator trail = p.end(); while(trail != p.begin()) { --trail; if(not strchr(" \t\r\n", *trail) and not issoftcr(*trail)) { ++trail; break; } } p.erase(trail, p.end()); } return p; } // ------------------------------------------------------------------ const char* get_subject_re_info(const char* s, uint32_t& n) { if(g_toupper(*s) == 'R' and g_tolower(s[1]) == 'e') { if(s[2] == ':') { n = 1; return s + 3; } else if(s[2] == '^' and isdigit(s[3])) { const char* d = s + 4; while(isdigit(*d)) d++; if(*d == ':') { n = (uint32_t)atol(s + 3); return d + 1; } } } n = 0; return NULL; } // ------------------------------------------------------------------ void CheckSubject(GMsg* msg, char* subj) { for(int n=0; nisnet()) { if(EDIT->AutoAttach()) { // If the subject was changed if(not strieql(subj, msg->re)) { // Check if the subj begins with drive spec if(not (msg->attr.frq() or msg->attr.att() or msg->attr.urq())) { char* ptr = subj; if(*ptr == '^') ptr++; #ifdef __UNIX__ if((*ptr == '/') and not strchr(ptr, ':')) { /* } */ #else if((in_range((char)g_tolower(*ptr), (char)'c', (char)'z') and (ptr[1] == ':')) or ((*ptr == '\\') and (ptr[1] == '\\'))) { #endif // Autoattach msg->attr.att1(); AttrAdd(&msg->attr, &CFG->attribsattach); DispHeadAttrs(msg); } } } } if(msg->attr.frq()) { // Handle File Requests if(*subj) { ISub buf; strcpy(buf, subj); char* ptr = strtok(buf, " "); while(ptr) { if(*ptr == '!') { // Store password if(fspecs) strcpy(fspec[fspecs-1].password, ptr); } else { fspec = (FileSpec*)throw_realloc(fspec, (fspecs+1)*sizeof(FileSpec)); memset(fspec+fspecs, 0, sizeof(FileSpec)); fspec[fspecs].files = 1; strxcpy(fspec[fspecs].path, ptr, sizeof(Path)); specfiles++; fspecs++; } ptr = strtok(NULL, " "); } } } else if(msg->attr.att()) { // Handle File Attaching ISub buf; if(strblank(subj)) { if(*CFG->attachpath) strxcpy(subj, CFG->attachpath, sizeof(ISub)); else strxcpy(subj, CFG->goldpath, sizeof(ISub)); } strcpy(buf, subj); char* ptr = strtok(buf, " "); while(ptr) { fspec = (FileSpec*)throw_realloc(fspec, (fspecs+1)*sizeof(FileSpec)); memset(fspec+fspecs, 0, sizeof(FileSpec)); if(*ptr == '^') { fspec[fspecs].delsent = YES; ptr++; } if((ptr == CleanFilename(ptr)) and *CFG->attachpath) strxmerge(fspec[fspecs].path, sizeof(Path), CFG->attachpath, ptr, NULL); else strxcpy(fspec[fspecs].path, ptr, sizeof(Path)); FileSelect(msg, LNG->AttachFiles, &fspec[fspecs]); specfiles += fspec[fspecs].files; if(fspec[fspecs].files) fspecs++; ptr = strtok(NULL, " "); } } else if(msg->attr.urq()) { // Handle Update Requests ISub buf; if(not *subj) strcpy(subj, "."); strcpy(buf, subj); char* ptr = strtok(buf, " "); while(ptr) { if(*ptr == '!') { // Store password if(fspecs) strcpy(fspec[fspecs-1].password, ptr); } else { fspec = (FileSpec*)throw_realloc(fspec, (fspecs+1)*sizeof(FileSpec)); memset(fspec+fspecs, 0, sizeof(FileSpec)); strxcpy(fspec[fspecs].path, ptr, sizeof(Path)); FileSelect(msg, LNG->UpdreqFiles, &fspec[fspecs]); specfiles += fspec[fspecs].files; if(fspec[fspecs].files) fspecs++; } ptr = strtok(NULL, " "); } } // Generate the (first) processed subject line if(specfiles) { ISub buf; *buf = NUL; for(int x=0,n=0; x 71) { n++; break; } else strcat(buf, subject); } if(n) break; } strtrim(strcpy(subj, buf)); } } } // ------------------------------------------------------------------ static bool have_origin(GMsg *msg) { Line* line = msg->lin; while(line) if(line->type & GLINE_ORIG) return true; else line = line->next; return false; } // ------------------------------------------------------------------ static void MakeMsg3(int& mode, GMsg* msg) { int n; std::vector::iterator u; msg->charsetlevel = 0; if(*AA->Xlatexport()) { msg->charsetlevel = LoadCharset(CFG->xlatlocalset, AA->Xlatexport()); if(msg->charsetlevel) sprintf(msg->charset, "%s %d", AA->Xlatexport(), msg->charsetlevel); else sprintf(msg->charset, "%s 2", CFG->xlatlocalset); } // Do Timefields if(msg->attr.fmu()) { time32_t a = gtime(NULL); struct tm *tp = ggmtime(&a); tp->tm_isdst = -1; time32_t b = gmktime(tp); a += a - b; if(AA->havereceivedstamp()) msg->received = a; if(AA->havearrivedstamp()) msg->arrived = a; } GMsg* carbon=NULL; int cc = DoCarboncopy(msg, &carbon); if(AA->isecho() or have_origin(msg)) DoTearorig(mode, msg); // Do FakeNets msg->oorig = msg->orig; if(AA->isnet() and msg->orig.point) { for(u = CFG->aka.begin(); u != CFG->aka.end(); u++) { if(not memcmp(&(*u), &msg->orig, sizeof(Addr))) { // Use fakenet to everybody if(u->pointnet) { msg->oorig.net = u->pointnet; // Create fake address msg->oorig.node = msg->orig.point; msg->oorig.point = 0; } break; } } } DoKludges(mode, msg); if(cc) { std::string temp; update_statuslinef(LNG->StatusCC, "ST_STATUSCC", msg->to, msg->dest.make_string(temp).c_str()); } msg->LinesToText(); if(AA->isnet() and (msg->attr.frq() or msg->attr.att() or msg->attr.urq()) and specfiles >= 1) CreateFileMsgs(mode, msg); else { HeaderView->Use(AA, msg); HeaderView->Paint(); // Do zoneGating if(AA->isnet() and CFG->zonegating and (msg->dest.zone != msg->orig.zone)) { if(not (msg->attr.dir() or msg->attr.cra() or msg->attr.hld())) { GMenuZonegate MenuZonegate; if(CFG->zonegating == YES or MenuZonegate.Run()) ZonegateIt(msg->odest, msg->orig, msg->dest); } } if(msg->odest.net == 0) msg->odest = msg->dest; HeaderView->Use(AA, msg); HeaderView->Paint(); w_info(LNG->Wait); AA->SaveMsg((mode == MODE_CHANGE) ? GMSG_UPDATE : GMSG_NEW, msg); if(not (AA->isecho() and mode == MODE_REPLYCOMMENT)) update_addressbook(msg); w_info(NULL); } if(AL.AreaEchoToNo(AA->Areayouwroteto())>=0) { Area* A = AL.AreaEchoToPtr(AA->Areayouwroteto()); if(AA != A) { char* back = NULL; uint mlen = 0; msg->link.reset(); char* ptr = msg->txt + (*msg->txt == CTRL_A); if(not strnieql(ptr, "AREA:", 5)) { uint elen = 6 + strlen(AA->echoid()) + 1; mlen = strlen(msg->txt)+1; msg->txt = (char*)throw_realloc(msg->txt, elen+mlen); back = msg->txt+elen; memmove(back, msg->txt, mlen); strcpy(msg->txt, "\001AREA:"); strcpy(msg->txt+6, AA->echoid()); msg->txt[elen-1] = CR; } AA->Close(); A->Open(); uint32_t oldmsgno = msg->msgno; A->NewMsgno(msg); A->SaveMsg(GMSG_NEW|GMSG_NOLSTUPD, msg); A->Close(); AA->Open(); if(back) memmove(msg->txt, back, mlen); msg->msgno = oldmsgno; } } if(cc) { Area* A = AA; if(AA->isecho()) { AA = AL.AreaEchoToPtr(AA->Areareplyto()); if(AA and (AA != A)) { AA->Open(); AA->RandomizeData(mode); } else AA = A; } for(n=0; ntxt = msg->txt; cmsg->lin = msg->lin; cmsg->line = msg->line; cmsg->lines = msg->lines; cmsg->messageid = msg->messageid; cmsg->inreplyto = msg->inreplyto; cmsg->references = msg->references; AA->NewMsgno(cmsg); { std::string temp; update_statuslinef(LNG->StatusCC, "ST_STATUSCC", cmsg->to, cmsg->dest.make_string(temp).c_str()); } // Do aka matching if(AA->Akamatching()) { int newaka = AkaMatch(&cmsg->orig, &cmsg->dest); cmsg->orig = CFG->aka[newaka].addr; } // Do FakeNets cmsg->oorig = cmsg->orig; if(AA->isnet() and cmsg->orig.point) { for(u = CFG->aka.begin(); u != CFG->aka.end(); u++) { if(not memcmp(&(*u), &cmsg->orig, sizeof(Addr))) { // Use fakenet to everybody if(u->pointnet) { cmsg->oorig.net = u->pointnet; // Create fake address cmsg->oorig.node = cmsg->orig.point; cmsg->oorig.point = 0; } break; } } } // remove unnessesary To: line from message if present for(Line* line = cmsg->lin; line; line = line->next) if(strnieql(line->txt.c_str(), "To:", 3)) line = DeleteLine(line); else if(line->type & GLINE_KLUDGE) continue; else break; DoKludges(mode, cmsg); if(have_origin(cmsg)) DoTearorig(mode, cmsg); cmsg->LinesToText(); msg->txt = cmsg->txt; msg->lin = cmsg->lin; msg->line = cmsg->line; msg->lines = cmsg->lines; msg->messageid = cmsg->messageid; msg->inreplyto = cmsg->inreplyto; msg->references = cmsg->references; if(AA->isnet() and (cmsg->attr.frq() or cmsg->attr.att() or cmsg->attr.urq())) { CreateFileMsgs(MODE_NEW, cmsg); msg->txt = cmsg->txt; msg->lin = cmsg->lin; msg->line = cmsg->line; msg->lines = cmsg->lines; msg->messageid = cmsg->messageid; msg->inreplyto = cmsg->inreplyto; msg->references = cmsg->references; } else { HeaderView->Use(AA, cmsg); HeaderView->Paint(); // Do zoneGating if(AA->isnet() and CFG->zonegating and (cmsg->dest.zone != cmsg->orig.zone)) { if(not cmsg->attr.dir()) { GMenuZonegate MenuZonegate; if(CFG->zonegating == YES or MenuZonegate.Run()) ZonegateIt(cmsg->odest, cmsg->orig, cmsg->dest); } } if(cmsg->odest.net == 0) cmsg->odest = cmsg->dest; HeaderView->Use(AA, cmsg); HeaderView->Paint(); w_info(LNG->Wait); AA->SaveMsg(GMSG_NEW, cmsg); w_info(NULL); update_addressbook(cmsg); msg->txt = cmsg->txt; msg->lin = cmsg->lin; msg->line = cmsg->line; msg->lines = cmsg->lines; msg->messageid = cmsg->messageid; msg->inreplyto = cmsg->inreplyto; msg->references = cmsg->references; } } throw_release(carbon); if(A != AA) { AA->Close(); AA = A; AA->RandomizeData(); } AA->UpdateAreadata(); } } // ------------------------------------------------------------------ static void MakeMsg2(int& mode, int& status, int& forwstat, int& topline, GMsg* msg, GMsg* oldmsg, GMsg* cmpmsg) { uint n; char buf[256], buf2[256]; Line* line; Line* newline; if(status == MODE_CHANGE or (mode == MODE_FORWARD and status == MODE_SAVE)) { if(mode == MODE_CHANGE) { if(stricmp(msg->By(), AA->Username().name)) { std::vector::iterator x; for(n = 0, x = CFG->username.begin(); x != CFG->username.end(); n++, x++) { if(strieql(x->name, msg->By())) { n = 0; break; } } if(n) status = MODE_SAVE; } } w_info(LNG->Wait); if(mode != MODE_CHANGE) { if(not CFG->switches.get(emptytearline)) strcpy(msg->tearline, AA->Tearline()); if(AA->Taglinesupport()) strcpy(msg->tagline, AA->Tagline()); DoTearorig(mode, msg); strcpy(msg->organization, AA->Organization()); } if(mode != MODE_CHANGE or status == MODE_SAVE) { if(TemplateToText(mode, msg, oldmsg, AA->Tpl(), OrigArea)) { HeaderView->Use(AA, msg); HeaderView->Paint(); } msg->attr.pos1(); msg->TextToLines(CFG->dispmargin-1, false); // Ignore any kludge address found msg->attr.pos0(); } uint lineno, position = reader_topline+1; for(lineno = 0; lineno < msg->lines; lineno++) { if(not (msg->line[lineno]->type & GLINE_QUOT)) if(msg->line[lineno]->type & GLINE_POSI) position = lineno+reader_topline+1; } if(*EDIT->External() and not EDIT->Internal()) { SaveLines(MODE_NEW, AddPath(CFG->goldpath, EDIT->File()), msg, 79); } int loop = 0; w_info(NULL); do { if(loop) { status = MODE_SAVE; forwstat = NO; } if(mode == MODE_FORWARD) status = MODE_SAVE; if(*EDIT->External() and forwstat == NO and not EDIT->Internal()) { strcpy(buf, EDIT->External()); sprintf(buf2, "%u", position); strischg(buf, "@line", buf2); strcpy(buf2, AddPath(CFG->goldpath, EDIT->File())); strchg(buf2, GOLD_WRONG_SLASH_CHR, GOLD_SLASH_CHR); strischg(buf, "@file", buf2); long ftbefore = GetFiletime(AddPath(CFG->goldpath, EDIT->File())); sprintf(buf2, LNG->EditCmd, buf); ShellToDos(buf, buf2, LGREY|_BLACK, YES); long ftafter = GetFiletime(AddPath(CFG->goldpath, EDIT->File())); if(status != MODE_SAVE) { status = MODE_SAVE; if(ftbefore == ftafter) { if(streql(msg->by, cmpmsg->by)) if(streql(msg->to, cmpmsg->to)) if(streql(msg->re, cmpmsg->re)) if(not memcmp(&msg->attr, &cmpmsg->attr, sizeof(Attr))) status = MODE_QUIT; } } if(status != MODE_QUIT) { LoadCharset("N/A", "N/A"); strcpy(stpcpy(msg->charset, CFG->xlatlocalset), " 2"); msg->charsetlevel = 2; } } else if(forwstat == NO and (EDIT->Internal() or not *EDIT->External())) { w_info(LNG->Wait); status = MODE_SAVE; newline = line = msg->lin; while(line) { newline = line; if((line->type & GLINE_KLUD) and not AA->Viewkludge() and not (line->kludge & GKLUD_RFC)) newline = line = DeleteLine(line); else { strtrimline(line->txt); if(line->type & GLINE_HARD) line->txt += "\n"; else line->txt += " "; line = line->next; } } msg->lin = FirstLine(newline); w_info(NULL); if(position) position--; if(not savedirect) status = EditMsg(mode, &position, msg); _in_editor = NO; w_info(LNG->Wait); if(status != MODE_QUIT) { line = msg->lin; while(line) { if(line->txt.find('\n') != line->txt.npos) line->type = GLINE_HARD; else if(line->next and (line->next->type & GLINE_QUOT)) line->type = GLINE_HARD; else line->type = 0; strtrimline(line->txt); if(AA->isinternet() or *msg->ito or *msg->ifrom) { // Check for signature indicator if(streql(line->txt.c_str(), "--")) { line->txt = "-- "; line->type = GLINE_HARD; } } line = line->next; } LoadCharset("N/A", "N/A"); strcpy(stpcpy(msg->charset, CFG->xlatlocalset), " 2"); msg->charsetlevel = 2; msg->LinesToText(); } w_info(NULL); } if(status == MODE_SAVE) { if(*EDIT->External() and not EDIT->Internal()) LoadText(msg, AddPath(CFG->goldpath, EDIT->File())); if(mode == MODE_FORWARD) msg->attr.pos1(); bool adat_viewhidden = AA->Viewhidden(); bool adat_viewkludge = AA->Viewkludge(); bool adat_viewquote = AA->Viewquote(); bool adat_striphtml = AA->StripHTML(); AA->adat->viewhidden = true; AA->adat->viewkludge = true; AA->adat->viewquote = true; AA->adat->striphtml = false; msg->TextToLines(CFG->dispmargin-1, false); // Ignore any kludge address found AA->adat->viewhidden = adat_viewhidden; AA->adat->viewkludge = adat_viewkludge; AA->adat->viewquote = adat_viewquote; AA->adat->striphtml = adat_striphtml; msg->attr.pos0(); InvalidateControlInfo(msg); if(not savedirect) { HeaderView->Use(AA, msg); HeaderView->Paint(); BodyView->Use(AA, msg, topline); BodyView->Paint(); do { if(gkbd.quitall) status = MODE_SAVE; else { GMenuEditfile MenuEditfile; status = MenuEditfile.Run(msg); } if(status == MODE_VIEW) { BodyView->Use(AA, msg, topline); BodyView->Paint(); ViewMessage(); } } while(status == MODE_VIEW); } if(status == MODE_SAVE) DoCrosspost(msg, post_xparea); } loop++; if(status == MODE_CHANGE) { _in_editor = YES; HeaderView->Use(AA, msg); HeaderView->Paint(); } } while(status == MODE_CHANGE); } } // ------------------------------------------------------------------ static void GetLastLink(GMsg* msg, uint32_t& msgno) { GMsg* uplink = (GMsg*)throw_calloc(1, sizeof(GMsg)); uplink->msgno = msg->msgno; uplink->link.first_set(msg->link.first()); if(uplink->link.first()) { while(AA->Msgn.ToReln(uplink->link.first())) { if(not AA->LoadHdr(uplink, uplink->link.first(), false)) uplink->msgno = 0; } } // Return msgno of the last link msgno = uplink->msgno; ResetMsg(uplink); throw_free(uplink); } // ------------------------------------------------------------------ void MakeMsg(int mode, GMsg* omsg, bool ignore_replyto) { GFTRK("MakeMsg"); // Tell GMsgHeaderView not to show msg size _in_editor = YES; // Allocate some msgs GMsg* msg = (GMsg*)throw_calloc(1, sizeof(GMsg)); GMsg* reply = (GMsg*)throw_calloc(1, sizeof(GMsg)); GMsg* cmpmsg = (GMsg*)throw_calloc(1, sizeof(GMsg)); uint32_t reply_msgno = 0; // Keep copy of original aka for later restoration Addr origaka = AL.AreaIdToPtr(OrigArea)->aka(); // Force template choice if necessary if(AA->Forcetemplate() and (mode != MODE_CHANGE)) ChangeTemplate(); // Random System AA->RandomizeData(); // Prepare confirmation receipts int confirm = NO; if(mode == MODE_CONFIRM) { confirm = YES; mode = MODE_REPLY; } // Prepare crossposting int crosspost = NO; post_xparea.clear(); do { if(post_xparea.size()) { mode = MODE_COPY; AL.SetActiveAreaNo(post_xparea.back()); if(CurrArea != OrigArea) { AA->Open(); AA->RandomizeData(mode); } msg->TextToLines(CFG->dispmargin-1); msg->orig = AA->Aka().addr; msg->charsetlevel = LoadCharset(CFG->xlatlocalset, AA->Xlatexport()); if(msg->charsetlevel) sprintf(msg->charset, "%s %d", AA->Xlatexport(), msg->charsetlevel); else sprintf(msg->charset, "%s 2", CFG->xlatlocalset); strcpy(msg->odom, CFG->aka[AkaMatch(&msg->orig, &AA->Aka().addr)].domain); if(AA->isecho() or have_origin(msg)) DoTearorig(mode, msg); DoKludges(mode, msg); msg->LinesToText(); post_xparea.pop_back(); } int status = MODE_SAVE; bool hardlines = EDIT->HardLines(); int topline = 0; fspecs = specfiles = 0; fspec = (FileSpec*)throw_realloc(fspec, sizeof(FileSpec)); memset(fspec, 0, sizeof(FileSpec)); // Get msg number and reset/copy msg data if(mode != MODE_COPY) ResetMsg(msg); switch(mode) { case MODE_FORWARD: memcpy(msg, omsg, sizeof(GMsg)); msg->txt = (char*)throw_strdup(msg->txt); msg->lin = NULL; msg->line = NULL; msg->messageid = NULL; msg->inreplyto = NULL; msg->references = NULL; if(CurrArea != OrigArea) AA->SetXlatimport(AL.AreaIdToPtr(OrigArea)->Xlatimport()); msg->TextToLines(CFG->dispmargin-1, true, false); msg->msgid.reset(); *msg->iorig = NUL; *msg->idest = NUL; *msg->ireplyto = NUL; *msg->iaddr = NUL; *msg->igate = NUL; *msg->ifrom = NUL; *msg->ito = NUL; *msg->organization = NUL; *msg->realby = NUL; *msg->realto = NUL; *msg->origin = NUL; // Drop through ... case MODE_COPY: AA->NewMsgno(msg); msg->link.reset(); break; case MODE_CHANGE: memcpy(msg, omsg, sizeof(GMsg)); msg->txt = (char*)throw_strdup(msg->txt); msg->lin = NULL; msg->line = NULL; msg->messageid = NULL; msg->inreplyto = NULL; msg->references = NULL; msg->TextToLines(CFG->dispmargin-1, true, false); break; case MODE_NEW: wfill(MINROW, 0, MAXROW-2, MAXCOL-1, ' ', C_READW); case MODE_QUOTE: case MODE_REPLY: case MODE_REPLYCOMMENT: AA->NewMsgno(msg); msg->timesread = 1; } msg->oorig = msg->orig; msg->board = AA->board(); msg->odest = msg->dest; if(mode != MODE_COPY) { // Set msg date and time bool dochgdate = true; if(mode == MODE_CHANGE) { dochgdate = make_bool(EDIT->ChangeDate()); if((EDIT->ChangeDate() == YES) and not msg->attr.fmu()) dochgdate = false; } if(dochgdate) { time32_t a = gtime(NULL); struct tm *tp = ggmtime(&a); tp->tm_isdst = -1; time32_t b = gmktime(tp); a += a - b; msg->received = msg->arrived = msg->written = a; } // Prepare msg header if(mode != MODE_CHANGE) msg->attr = AA->Attributes(); // Set default attributes switch(mode) { case MODE_QUOTE: case MODE_REPLYCOMMENT: if(CurrArea != OrigArea) AA->SetXlatimport(AL.AreaIdToPtr(OrigArea)->Xlatimport()); omsg->TextToLines(-CFG->quotemargin, true, false); if(ignore_replyto) *omsg->ireplyto = NUL; if(omsg->attr.rot()) Rot13(omsg); // Drop through case MODE_REPLY: if(confirm) msg->attr = CFG->attribscfm; if(omsg->attr.pvt() & !AA->isecho()) msg->attr.pvt1(); // Set Pvt attr in response to Pvt in orig if(omsg->attr.frq() and (mode == MODE_REPLY) and (not confirm)) { msg->attr = CFG->attribsfrq; msg->attr.frq1(); // Special case for the file request function } // Change header data if replying to a forwarded message if((mode == MODE_REPLYCOMMENT) and omsg->fwdorig.net) { strcpy(omsg->by, omsg->fwdfrom); strcpy(omsg->realby, omsg->fwdfrom); omsg->oorig = omsg->orig = omsg->fwdorig; strcpy(omsg->to, omsg->fwdto); strcpy(omsg->realto, omsg->fwdto); omsg->odest = omsg->dest = omsg->fwddest; strcpy(omsg->re, omsg->fwdsubj); *omsg->ireplyto = *omsg->iorig = NUL; } // Do aka matching if(AA->Akamatching()) { // ... but only if we did NOT change aka manually if(AA->Aka().addr.equals(AA->aka())) { Addr aka_addr = AA->Aka().addr; if (CFG->akamatchfromto) { bool useto = true; std::vector::iterator a; for (a = CFG->aka.begin(); useto && (a != CFG->aka.end()); a++) { if(omsg->orig.equals(a->addr)) useto = false; } if (useto) { for (a = CFG->aka.begin(); a != CFG->aka.end(); a++) if(omsg->dest.equals(a->addr)) { akamatchreply = true; break; } } } if (CFG->akamatchfromto && akamatchreply) aka_addr = omsg->dest; else aka_addr = AA->Aka().addr; AkaMatch(&aka_addr, &omsg->orig); AA->SetAka(aka_addr); } } if((mode == MODE_REPLYCOMMENT) and not omsg->fwdorig.net) { strcpy(msg->to, omsg->to); strcpy(msg->realto, omsg->realto); msg->dest = omsg->dest; strcpy(msg->idest, omsg->idest); } else { strcpy(msg->to, omsg->By()); strcpy(msg->realto, omsg->realby); msg->dest = omsg->orig; strcpy(msg->idest, *omsg->ireplyto ? omsg->ireplyto : *omsg->iorig ? omsg->iorig : omsg->iaddr); } if(not *msg->iaddr) strcpy(msg->iaddr, msg->idest); strcpy(msg->re, omsg->re); if(AA->Replyre() or AA->isinternet()) { uint32_t number; const char* r = get_subject_re_info(msg->re, number); if(r) { if(AA->Replyre() == REPLYRE_NUMERIC and not AA->isinternet()) { ISub subj; sprintf(subj, "Re^%u:%s", (((number+1) > number) ? (number+1) : number), r); strcpy(msg->re, subj); } } else if(not msg->attr.frq() and not msg->attr.urq()) { memmove(msg->re+4, msg->re, sizeof(ISub)-5); memmove(msg->re, "Re: ", 4); } } else { char* r; uint32_t number; char* ptr = msg->re; do { r = (char*)get_subject_re_info(ptr, number); if(r) ptr = strskip_wht(r); } while(r); strcpy(msg->re, ptr); } strcpy(msg->ddom, omsg->odom); if((mode == MODE_REPLYCOMMENT) and omsg->fwdorig.net) strcpy(msg->replys, omsg->fwdmsgid); else strcpy(msg->replys, omsg->msgids); if(AA->isnet()) { if(omsg->messageid) { throw_free(msg->inreplyto); msg->inreplyto = throw_strdup(omsg->messageid); } strcpy(msg->igate, omsg->igate); if(*msg->igate) { msg->dest.set(msg->igate); char* ptr = strchr(msg->igate, ' '); if(ptr) { if(not isuucp(msg->to)) strcpy(msg->realto, msg->to); strcpy(msg->to, strskip_wht(ptr)); } } } else { int reflen = omsg->references ? strlen(omsg->references) : 0; int midlen = omsg->messageid ? strlen(omsg->messageid) : 0; msg->references = (char*)throw_calloc(1, reflen+1+midlen+1); if(omsg->references) strcpy(msg->references, omsg->references); if(omsg->messageid) { if(reflen) strcat(msg->references, " "); strcat(msg->references, omsg->messageid); } if(*msg->references == NUL) throw_release(msg->references); } if(CurrArea == OrigArea) { if((CFG->replylink == REPLYLINK_DIRECT) or streql(AA->basetype(), "JAM")) reply_msgno = omsg->msgno; else if(CFG->replylink == REPLYLINK_CHAIN) GetLastLink(omsg, reply_msgno); msg->link.to_set(reply_msgno); if(msg->link.to() == omsg->msgno) omsg->link.first_set(msg->msgno); } /////////// /////////// Drop through /////////// case MODE_FORWARD: if(mode == MODE_FORWARD) { if(msg->fwdorig.net == 0) { strcpy(msg->fwdfrom, msg->By()); msg->fwdorig = msg->orig; strcpy(msg->fwdto, msg->To()); msg->fwddest = msg->dest; strxcpy(msg->fwdsubj, msg->re, sizeof(Subj)); Area* fwdarea = AL.AreaIdToPtr(OrigArea); strcpy(msg->fwdarea, fwdarea->isecho() ? fwdarea->echoid() : ""); strcpy(msg->fwdmsgid, msg->msgids); } } /////////// /////////// Drop through /////////// case MODE_NEW: strcpy(msg->by, AA->Username().name); msg->attr.nwm1(); if(not AA->islocal()) msg->attr.uns1(); strcpy(msg->odom, CFG->aka[AkaMatch(&msg->orig, &AA->Aka().addr)].domain); break; case MODE_CHANGE: if(not AA->islocal()) msg->attr.uns1(); msg->attr.snt0(); msg->attr.rcv0(); break; } // Get random items switch(mode) { case MODE_NEW: case MODE_FORWARD: *msg->replys = NUL; throw_release(msg->references); throw_release(msg->inreplyto); if(AA->isnet()) { strcpy(msg->to, ""); msg->dest.reset_fast(); msg->odest.reset_fast(); } if(not AA->isnet() or (AA->isemail() and strchr(AA->Whoto(), '@'))) strcpy(msg->to, AA->Whoto()); /////// /////// Drop through /////// case MODE_REPLYCOMMENT: case MODE_QUOTE: case MODE_REPLY: case MODE_CHANGE: AA->RandomizeData(mode); if(mode != MODE_CHANGE) { msg->orig = AA->Aka().addr; if(AA->isinternet()) strcpy(msg->iorig, AA->Internetaddress()); if(not strblank(AA->Username().name)) strcpy(msg->by, AA->Username().name); if(CFG->switches.get(emptytearline)) *msg->tearline = NUL; } break; } int forwstat = NO; if(msg->odest.net == 0) msg->odest = msg->dest; status = NO; if(not confirm) { strcpy(cmpmsg->by, msg->by); strcpy(cmpmsg->to, msg->to); strcpy(cmpmsg->re, msg->re); cmpmsg->attr = msg->attr; if(savedirect) { CheckSubject(msg, msg->re); } else { GMenuEditHeader MenuEditHeader; while((status = MenuEditHeader.Run(mode, msg)) == YES); } } if(status == NO) { if(mode == MODE_CHANGE or mode == MODE_FORWARD) { status = MODE_SAVE; if(mode == MODE_FORWARD) forwstat = YES; } else { if(confirm) { throw_release(msg->txt); FILE* fp = fsopen(AddPath(CFG->goldpath, CFG->confirmfile), "rt", CFG->sharemode); if(fp) { LoadText(msg, AddPath(CFG->goldpath, CFG->confirmfile)); fclose(fp); } if(msg->txt == NULL) msg->txt = throw_strdup("\r\rConfirmation Receipt\r\r"); TokenXlat(mode, msg->txt, msg, omsg, CurrArea); } else CreateFileAddr(msg); msg->TextToLines(CFG->dispmargin-1); status = MODE_SAVE; } } MakeMsg2(mode, status, forwstat, topline, msg, omsg, cmpmsg); } if(status != MODE_SAVE) { post_xparea.clear(); crosspost = NO; } if(status == MODE_SAVE) { if(*msg->iorig and (strlen(msg->iorig) < sizeof(Name))) { strcpy(msg->realby, msg->by); strcpy(msg->by, msg->iorig); } if(mode == MODE_COPY) AA->SaveMsg(GMSG_NEW, msg); else MakeMsg3(mode, msg); // If message is a reply, update the links on the original if(CurrArea == OrigArea and (mode == MODE_QUOTE or mode == MODE_REPLYCOMMENT or mode == MODE_REPLY)) { if(AA->Msgn.ToReln(reply_msgno)) { if(AA->LoadHdr(reply, reply_msgno, false)) { uint32_t replynext; bool ok2save = false; if(streql(AA->basetype(), "SQUISH")) { if(reply->link.first()) { for(int r=0; rlink.list_max()-1; r++) { if(reply->link.list(r) == 0) { reply->link.list_set(r, msg->msgno); ok2save = true; break; } } } else { reply->link.first_set(msg->msgno); ok2save = true; } } else if(streql(AA->basetype(), "JAM")) { if(reply->link.first()) { replynext = reply->link.first(); do { reply_msgno = replynext; if(not AA->LoadHdr(reply, reply_msgno, false)) break; replynext = reply->link.next(); } while(reply->link.next()); if(reply->link.next() == 0) { reply->link.next_set(msg->msgno); ok2save = true; } } else { reply->link.first_set(msg->msgno); ok2save = true; } } else { reply->link.first_set(msg->msgno); ok2save = true; } if(ok2save) { reply->pcboard.reply_written = msg->written; AA->SaveHdr(GMSG_UPDATE, reply); } } } } // Ask if the original msg should be deleted while we're at it if(CurrArea == OrigArea and CFG->switches.get(askdelorig) and not confirm) { switch(mode) { case MODE_REPLY: case MODE_QUOTE: case MODE_REPLYCOMMENT: if(not AA->isecho()) { topline = 0; omsg->TextToLines(CFG->dispmargin-1); if(omsg->attr.rot()) Rot13(omsg); HeaderView->Use(AA, omsg); HeaderView->Paint(); BodyView->Use(AA, omsg, topline); BodyView->Paint(); GMenuDelorig MenuDelorig; if(MenuDelorig.Run()) { AA->Mark.Del(omsg->msgno); AA->PMrk.Del(omsg->msgno); AA->DeleteMsg(omsg, DIR_PREV); } } break; } } } if(CurrArea != OrigArea) { AA->UpdateAreadata(); AA->Close(); AL.SetActiveAreaId(OrigArea); AA->RandomizeData(); } AA->UpdateAreadata(); EDIT->HardLines(hardlines); for(int n=0; nCrossposting, "ST_CROSSPOSTING", AL[post_xparea.back()]->echoid()); } while(post_xparea.size()); _in_editor = NO; // Restore original aka AA->SetAka(origaka); akamatchreply = false; ResetMsg(omsg); ResetMsg(cmpmsg); ResetMsg(reply); ResetMsg(msg); throw_free(cmpmsg); throw_free(reply); throw_free(msg); LoadLanguage(AA->Loadlanguage()); GFTRK(NULL); } // ------------------------------------------------------------------