1046 lines
26 KiB
C++
1046 lines
26 KiB
C++
|
|
// ------------------------------------------------------------------
|
|
// 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$
|
|
// ------------------------------------------------------------------
|
|
// Reader secondary functions
|
|
// ------------------------------------------------------------------
|
|
|
|
#include <vector>
|
|
#include <algorithm>
|
|
#include <golded.h>
|
|
#include <gwinput.h>
|
|
#include <gftnall.h>
|
|
#define PROTOTYPES
|
|
#include <uudeview.h>
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
// Global data from GEREAD
|
|
|
|
extern GMsg* reader_msg;
|
|
extern bool reader_msglistfirst;
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
void ChangeAttributes() {
|
|
|
|
if(reader_msg->msgno) {
|
|
|
|
// Reload if hexdumped
|
|
if(AA->attr().hex()) {
|
|
AA->attr().hex0();
|
|
AA->LoadMsg(reader_msg, reader_msg->msgno, CFG->dispmargin-(int)CFG->switches.get(disppagebar));
|
|
}
|
|
|
|
GMsg* msg = (GMsg*)throw_malloc(sizeof(GMsg));
|
|
memcpy(msg, reader_msg, sizeof(GMsg));
|
|
AskAttributes(reader_msg);
|
|
if(memcmp(msg, reader_msg, sizeof(GMsg))) {
|
|
msg->charsetlevel = LoadCharset(CFG->xlatlocalset, msg->charset);
|
|
DoKludges(MODE_CHANGE, reader_msg, GKLUD_FLAGS);
|
|
reader_msg->LinesToText();
|
|
AA->SaveMsg(GMSG_UPDATE, reader_msg);
|
|
}
|
|
throw_free(msg);
|
|
}
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
void DecMargin() {
|
|
|
|
if(CFG->dispmargin > (MAXCOL/3))
|
|
CFG->dispmargin--;
|
|
else {
|
|
SayBibi();
|
|
reader_keyok = YES;
|
|
}
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
void IncMargin() {
|
|
|
|
if(CFG->dispmargin < MAXCOL)
|
|
CFG->dispmargin++;
|
|
else {
|
|
SayBibi();
|
|
reader_keyok = YES;
|
|
}
|
|
}
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
void ToggleMark() {
|
|
|
|
uint tmp = AA->Mark.Find(reader_msg->msgno);
|
|
if(tmp)
|
|
AA->Mark.DelReln(tmp);
|
|
else
|
|
AA->Mark.Add(reader_msg->msgno);
|
|
HeaderView->Use(AA, reader_msg);
|
|
HeaderView->Paint();
|
|
reader_keyok = YES;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
void ToggleBookMark() {
|
|
|
|
if(AA->bookmark == reader_msg->msgno)
|
|
AA->bookmark = 0;
|
|
else
|
|
AA->bookmark = reader_msg->msgno;
|
|
HeaderView->Use(AA, reader_msg);
|
|
HeaderView->Paint();
|
|
reader_keyok = YES;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
void ToggleHiddKlud() {
|
|
|
|
AA->ToggleViewhidden();
|
|
AA->ToggleViewkludge();
|
|
MsgLineReIndex(reader_msg);
|
|
reader_topline = 0;
|
|
reader_keyok = YES;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
void ToggleKludge() {
|
|
|
|
AA->ToggleViewkludge();
|
|
MsgLineReIndex(reader_msg);
|
|
reader_topline = 0;
|
|
reader_keyok = YES;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
void ToggleHidden() {
|
|
|
|
AA->ToggleViewhidden();
|
|
MsgLineReIndex(reader_msg);
|
|
reader_topline = 0;
|
|
reader_keyok = YES;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
void ToggleStripHTML() {
|
|
|
|
AA->ToggleStripHTML();
|
|
MsgLineReIndex(reader_msg);
|
|
reader_topline = 0;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
void ToggleQuote() {
|
|
|
|
AA->ToggleViewquote();
|
|
MsgLineReIndex(reader_msg);
|
|
reader_topline = 0;
|
|
reader_keyok = YES;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
void ToggleROT13() {
|
|
|
|
if(AA->Msgn.Count()) {
|
|
reader_msg->attr.rotX();
|
|
Rot13(reader_msg);
|
|
reader_keyok = YES;
|
|
}
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
void TogglePageBar() {
|
|
|
|
CFG->switches.set(disppagebar, not CFG->switches.get(disppagebar));
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
void ToggleRealMsgno() {
|
|
|
|
CFG->switches.set(disprealmsgno, not CFG->switches.get(disprealmsgno));
|
|
HeaderView->Use(AA, reader_msg);
|
|
HeaderView->Paint();
|
|
reader_keyok = YES;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
void ToggleTwits() {
|
|
|
|
gkey k;
|
|
|
|
do {
|
|
switch(AA->Twitmode()) {
|
|
case TWIT_SHOW:
|
|
AA->SetTwitmode(TWIT_BLANK);
|
|
w_info(LNG->TwitBlanked);
|
|
break;
|
|
case TWIT_BLANK:
|
|
AA->SetTwitmode(TWIT_SKIP);
|
|
w_info(LNG->TwitSkipped);
|
|
break;
|
|
case TWIT_SKIP:
|
|
AA->SetTwitmode(TWIT_IGNORE);
|
|
w_info(LNG->TwitIgnoreSkip);
|
|
break;
|
|
case TWIT_IGNORE:
|
|
AA->SetTwitmode(TWIT_KILL);
|
|
w_info(LNG->TwitKilled);
|
|
break;
|
|
case TWIT_KILL:
|
|
AA->SetTwitmode(TWIT_SHOW);
|
|
w_info(LNG->TwitDisplayed);
|
|
break;
|
|
}
|
|
|
|
k = waitkeyt(3000);
|
|
|
|
} while(k and k != Key_Ent and k != Key_Esc);
|
|
|
|
w_info(NULL);
|
|
|
|
if(k == Key_Esc)
|
|
AA->SetTwitmode(CFG->twitmode);
|
|
else
|
|
CFG->twitmode = AA->Twitmode();
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
void ToggleStyles() {
|
|
|
|
gkey k;
|
|
int setting = AA->adat->usestylies + AA->adat->hidestylies*2;
|
|
|
|
do {
|
|
switch(setting) {
|
|
case 2:
|
|
case 0: w_info(LNG->StylecodesYes); setting = 1; break;
|
|
case 1: w_info(LNG->StylecodesHide); setting = 3; break;
|
|
case 3: w_info(LNG->StylecodesNo); setting = 0; break;
|
|
}
|
|
k = waitkeyt(3000);
|
|
} while (k and k != Key_Ent and k != Key_Esc);
|
|
w_info(NULL);
|
|
|
|
if(k != Key_Esc) {
|
|
AA->adat->usestylies = make_bool(setting & 1);
|
|
AA->adat->hidestylies = make_bool(setting & 2);
|
|
}
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
void GotoMsgno() {
|
|
|
|
if(AA->Msgn.Count()) {
|
|
|
|
// Set the active window
|
|
int lastwh = whandle();
|
|
int inhdr = AA->Msglistheader() or not _in_msglist;
|
|
|
|
if(reader_keycode < KK_Macro)
|
|
if(gkbd.kbuf == NULL)
|
|
kbput(reader_keycode); // Put back the key
|
|
|
|
char buf[150];
|
|
char* ptr = buf;
|
|
int list_max = reader_msg->link.list_max();
|
|
uint32_t* replies = (uint32_t*)throw_calloc(list_max+1, sizeof(uint32_t));
|
|
uint32_t replyto, replynext;
|
|
if(CFG->switches.get(disprealmsgno)) {
|
|
ptr += sprintf(ptr, " %-5.5s: %s %u", LNG->MsgReal, LNG->of, AA->Msgn.Count());
|
|
replyto = reader_msg->link.to();
|
|
replies[0] = reader_msg->link.first();
|
|
replynext = reader_msg->link.next();
|
|
for(int replyn=1; replyn<list_max+1; replyn++)
|
|
replies[replyn] = reader_msg->link.list(replyn-1);
|
|
}
|
|
else {
|
|
ptr += sprintf(ptr, " %-5.5s: %s %u", LNG->Msg, LNG->of, AA->Msgn.Count());
|
|
replyto = AA->Msgn.ToReln(reader_msg->link.to());
|
|
replies[0] = AA->Msgn.ToReln(reader_msg->link.first());
|
|
replynext = AA->Msgn.ToReln(reader_msg->link.next());
|
|
for(int replyn=1; replyn<list_max+1; replyn++)
|
|
replies[replyn] = AA->Msgn.ToReln(reader_msg->link.list(replyn-1));
|
|
}
|
|
if(replyto)
|
|
ptr += sprintf(ptr, " -%u", replyto);
|
|
for(int replyn=0,plus=0; replyn<list_max+1; replyn++)
|
|
if(replies[replyn])
|
|
ptr += sprintf(ptr, " %s%u", (plus++?"":"+"), replies[replyn]);
|
|
if(replynext)
|
|
sprintf(ptr, " *%u", replynext);
|
|
|
|
if(inhdr) {
|
|
HeaderView->window.activate_quick();
|
|
}
|
|
else {
|
|
wopen_(0, 0, 3, strlen(buf)+3, W_BHEAD, C_HEADB, C_HEADW);
|
|
w_shadow();
|
|
wtitle(LNG->EnterMsgno, TCENTER, C_HEADT);
|
|
}
|
|
|
|
int wrow = inhdr ? 1 : 0;
|
|
wprints(wrow, 0, C_HEADW, buf);
|
|
*buf = NUL;
|
|
|
|
gwindow iwindow(whandle());
|
|
|
|
std::string fbuf = buf;
|
|
gwinput2 iform(iwindow);
|
|
iform.setup(C_HEADW, C_HEADW, C_HEADI, _box_table(W_BHEAD, 13), true);
|
|
iform.add_field(0, wrow, 8, 5, fbuf, 20, gwinput::cvt_none, gwinput::entry_new);
|
|
vcurshow();
|
|
iform.run(H_InputMsgno);
|
|
vcurhide();
|
|
if(iform.dropped)
|
|
fbuf = "";
|
|
|
|
long active = AA->Msgn.Count();
|
|
long msgno = atol(fbuf.c_str());
|
|
|
|
if(CFG->switches.get(disprealmsgno))
|
|
if(msgno > 0)
|
|
msgno = AA->Msgn.ToReln(msgno);
|
|
|
|
if((msgno < 0) and ((active+msgno) > 0))
|
|
msgno = active + msgno;
|
|
|
|
if(RngV(msgno, 1L, active))
|
|
AA->set_lastread((uint)msgno);
|
|
|
|
if(inhdr)
|
|
wactiv_(lastwh);
|
|
else
|
|
wclose();
|
|
|
|
throw_free(replies);
|
|
}
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
void PrevArea() {
|
|
|
|
AA->attr().hex0();
|
|
AA->Close();
|
|
int currarea = AL.AreaIdToNo(CurrArea);
|
|
int testarea = currarea;
|
|
while(testarea > 0) {
|
|
testarea--;
|
|
if(not AL[testarea]->isseparator()) {
|
|
currarea = testarea;
|
|
break;
|
|
}
|
|
}
|
|
if(currarea == testarea) {
|
|
AL.SetActiveAreaNo(currarea);
|
|
OrigArea = CurrArea;
|
|
}
|
|
else
|
|
HandleGEvent(EVTT_ENDOFMSGS);
|
|
AA->Open();
|
|
AA->RandomizeData();
|
|
AA->SetBookmark(AA->lastread());
|
|
if (CFG->disppmfirst && AA->PMrk.Tags())
|
|
{
|
|
AA->isreadpm = false;
|
|
ToggleMarkRead();
|
|
}
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
void NextArea() {
|
|
|
|
AA->attr().hex0();
|
|
AA->Close();
|
|
uint currarea = AL.AreaIdToNo(CurrArea);
|
|
uint testarea = currarea;
|
|
while(testarea < (AL.size()-1)) {
|
|
testarea++;
|
|
if(not AL[testarea]->isseparator()) {
|
|
currarea = testarea;
|
|
break;
|
|
}
|
|
}
|
|
if(currarea == testarea) {
|
|
AL.SetActiveAreaNo(currarea);
|
|
OrigArea = CurrArea;
|
|
}
|
|
else
|
|
HandleGEvent(EVTT_ENDOFMSGS);
|
|
AA->Open();
|
|
AA->RandomizeData();
|
|
AA->SetBookmark(AA->lastread());
|
|
if (CFG->disppmfirst && AA->PMrk.Tags())
|
|
{
|
|
AA->isreadpm = false;
|
|
ToggleMarkRead();
|
|
}
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
void QuitNow() {
|
|
|
|
AA->attr().hex0();
|
|
reader_finished = YES;
|
|
reader_done = YES;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
void ExitAsk() {
|
|
|
|
AA->attr().hex0();
|
|
GMenuQuit MenuQuit;
|
|
reader_done = reader_finished = MenuQuit.Run();
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
void NewArea(bool jumpnext) {
|
|
|
|
AA->attr().hex0();
|
|
if(AA->isopen())
|
|
AA->Close();
|
|
|
|
int newarea = CurrArea;
|
|
|
|
if(jumpnext) {
|
|
uint idx = AL.AreaIdToNo(CurrArea);
|
|
uint oidx = idx;
|
|
|
|
do {
|
|
idx++;
|
|
|
|
// Wrap around
|
|
if(idx >= AL.size())
|
|
idx = 0;
|
|
|
|
// Exit loop if no area with new mail found
|
|
if(idx == oidx) {
|
|
newarea = AreaPick(LNG->NewArea, 0, &newarea);
|
|
if(newarea != -1)
|
|
idx = AL.AreaIdToNo(newarea);
|
|
break;
|
|
}
|
|
|
|
} while(AL.AreaNoToPtr(idx)->unread == 0);
|
|
|
|
CurrArea = AL.AreaNoToId(idx);
|
|
}
|
|
else {
|
|
newarea = AreaPick(LNG->NewArea, 0, &newarea);
|
|
if(newarea != -1)
|
|
CurrArea = newarea;
|
|
}
|
|
|
|
AL.Sort();
|
|
reader_done = YES;
|
|
|
|
if(gkbd.quitall)
|
|
QuitNow();
|
|
else {
|
|
AL.SetActiveAreaId(CurrArea);
|
|
OrigArea = CurrArea;
|
|
strcpy(stecho, AA->echoid());
|
|
AA->RandomizeData();
|
|
|
|
if (AA->Msglistfirst() && (kbput(KK_ReadMessageList) != -1))
|
|
reader_msglistfirst = true;
|
|
else
|
|
reader_msglistfirst = false;
|
|
}
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
void DosShell() {
|
|
|
|
ShellToDos(getenv(GOLD_SHELL_ENV), LNG->DOS_Shell, LGREY_|_BLACK, YES);
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
void TouchNetscan(int popup)
|
|
{
|
|
gfile fp(AddPath(CFG->areapath, CFG->semaphore.netscan), "wb", CFG->sharemode);
|
|
if (fp.isopen())
|
|
{
|
|
if (popup)
|
|
{
|
|
w_infof(" %s ", CFG->semaphore.netscan);
|
|
HandleGEvent(EVTT_JOBDONE);
|
|
waitkeyt(10000);
|
|
w_info(NULL);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
int ExternUtil(GMsg *msg, const ExtUtil &extutil)
|
|
{
|
|
Path editorfile, tmpfile, buf;
|
|
strxcpy(editorfile, AddPath(CFG->goldpath, EDIT->File()), sizeof(Path));
|
|
|
|
std::string cmdline = extutil.cmdline;
|
|
|
|
int mode = (extutil.options & EXTUTIL_KEEPCTRL) ? MODE_SAVE : MODE_SAVENOCTRL;
|
|
SaveLines(mode, editorfile, msg, 79);
|
|
strcpy(buf, editorfile);
|
|
strchg(buf, GOLD_WRONG_SLASH_CHR, GOLD_SLASH_CHR);
|
|
strischg(cmdline, "@file", buf);
|
|
if(striinc("@tmpfile", cmdline.c_str()))
|
|
{
|
|
mktemp(strcpy(tmpfile, AddPath(CFG->temppath, "GDXXXXXX")));
|
|
SaveLines(mode, tmpfile, msg, 79);
|
|
strcpy(buf, tmpfile);
|
|
strchg(buf, GOLD_WRONG_SLASH_CHR, GOLD_SLASH_CHR);
|
|
strischg(cmdline, "@tmpfile", buf);
|
|
}
|
|
else
|
|
tmpfile[0] = NUL;
|
|
strcpy(buf, CFG->goldpath);
|
|
strchg(buf, GOLD_WRONG_SLASH_CHR, GOLD_SLASH_CHR);
|
|
strischg(cmdline, "@path", buf);
|
|
TokenXlat(MODE_NEW, cmdline, msg, msg, CurrArea);
|
|
|
|
int pauseval = 0;
|
|
if(extutil.options & EXTUTIL_PAUSEONERROR)
|
|
pauseval = -1;
|
|
if(extutil.options & EXTUTIL_PAUSE)
|
|
pauseval = 1;
|
|
|
|
ShellToDos(cmdline.c_str(), "",
|
|
extutil.options & EXTUTIL_CLS ? LGREY_|_BLACK : BLACK_|_BLACK,
|
|
extutil.options & EXTUTIL_CURSOR,
|
|
pauseval
|
|
);
|
|
|
|
if(extutil.options & EXTUTIL_RELOAD) {
|
|
|
|
if(not (extutil.options & EXTUTIL_KEEPCTRL)) {
|
|
if (*msg->tearline or *msg->origin)
|
|
{
|
|
gfile fp(editorfile, "at");
|
|
if (fp.isopen())
|
|
{
|
|
if (*msg->tearline)
|
|
fp.Printf("--- %s\n", msg->tearline);
|
|
if (*msg->origin)
|
|
fp.Printf(" * Origin: %s\n", msg->origin);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool hardlines = EDIT->HardLines();
|
|
EDIT->HardLines(false);
|
|
LoadText(msg, editorfile);
|
|
EDIT->HardLines(hardlines);
|
|
|
|
if(not strstr(msg->txt, "\001CHRS:") and not strstr(msg->txt, "\001CHARSET:")) {
|
|
// Prepend "@CHRS: XLATLOCALSET 2\n" to force proper encoding
|
|
const char *charset = AA->Viewkludge() ? msg->charset : CFG->xlatlocalset;
|
|
char *msg_txt_chrs = (char *)throw_malloc(strlen(msg->txt)+strlen(charset)+sizeof("\001CHRS: 2\r")+16);
|
|
sprintf(msg_txt_chrs, "\001CHRS: %s 2\r%s", charset, msg->txt);
|
|
throw_free(msg->txt);
|
|
msg->txt = msg_txt_chrs;
|
|
}
|
|
|
|
// Ignore any kludge address found
|
|
msg->TextToLines(CFG->dispmargin-(int)CFG->switches.get(disppagebar), false);
|
|
|
|
if(AA->Viewkludge()) {
|
|
// Try to convert to the original codepage
|
|
char *inpcharset = msg->charset;
|
|
int level = LoadCharset(CFG->xlatlocalset, IsQuotedPrintable(inpcharset) ? ExtractPlainCharset(inpcharset) : inpcharset);
|
|
if(level) {
|
|
// do recode
|
|
char *msg_txt_chrs = (char *)throw_malloc(strlen(msg->txt)*3+16);
|
|
XlatStr(msg_txt_chrs, msg->txt, level, CharTable);
|
|
throw_free(msg->txt);
|
|
msg->txt = (char *)throw_realloc(msg_txt_chrs, strlen(msg_txt_chrs)+16);
|
|
}
|
|
}
|
|
msg->charsetlevel = LoadCharset(msg->charset, CFG->xlatlocalset);
|
|
}
|
|
|
|
if(extutil.options & EXTUTIL_WIPE)
|
|
WipeFile(editorfile, 0);
|
|
if(tmpfile[0] != NUL)
|
|
WipeFile(tmpfile, 0);
|
|
|
|
return YES;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
int ExternUtil(GMsg *msg, uint32_t utilno)
|
|
{
|
|
std::vector<ExtUtil>::iterator it = CFG->externutil.begin();
|
|
std::vector<ExtUtil>::iterator end = CFG->externutil.end();
|
|
|
|
for (uint32_t i = 0; it != end; i++, it++)
|
|
{
|
|
if (it->utilno != i) continue;
|
|
return ExternUtil(msg, *it);
|
|
}
|
|
|
|
SayBibi();
|
|
return YES;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
void ExternUtilMenu(GMsg* msg)
|
|
{
|
|
static int startat = 0;
|
|
static char cmdline[1024] = "";
|
|
gstrarray Listi;
|
|
|
|
Listi.push_back(LNG->EnterCmdLine);
|
|
|
|
std::vector<ExtUtil>::iterator it = CFG->externutil.begin();
|
|
std::vector<ExtUtil>::iterator end = CFG->externutil.end();
|
|
for (; it != end; it++)
|
|
{
|
|
char buf[100];
|
|
sprintf(buf, " %02d %.59s%s ", it->utilno, it->cmdline, (it->cmdline.length() > 59) ? ">" : "" );
|
|
Listi.push_back(buf);
|
|
}
|
|
|
|
size_t n = MinV(Listi.size(), (MAXROW-10));
|
|
set_title(LNG->ExternUtil, TCENTER, C_ASKT);
|
|
update_statusline(LNG->SelectExternUtil);
|
|
whelppcat(H_ReadExternUtil);
|
|
n = wpickstr(6, 0, 6+n+1, -1, W_BASK, C_ASKB, C_ASKW, C_ASKS, Listi, startat, title_shadow);
|
|
whelpop();
|
|
|
|
if (n != -1)
|
|
{
|
|
if (n == 0)
|
|
{
|
|
if (edit_string(cmdline, sizeof(cmdline), LNG->ExecCmdLine, H_ReadExternUtil))
|
|
{
|
|
ExtUtil extutil;
|
|
extutil.utilno = 0;
|
|
extutil.cmdline = cmdline;
|
|
extutil.options = CFG->externoptions;
|
|
reader_keyok = ExternUtil(msg, extutil);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
reader_keyok = ExternUtil(msg, CFG->externutil[n-1]);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
static bool PeekURLCmp(const std::string &a, const std::string b)
|
|
{
|
|
return stricmp(a.c_str(), b.c_str()) > 0;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
void ReadPeekURLs(GMsg* msg)
|
|
{
|
|
w_info(LNG->Wait);
|
|
|
|
// Scan the current msg for urls
|
|
int tline = reader_topline;
|
|
if (CFG->peekurloptions & PEEK_FROMTOP)
|
|
tline = 0;
|
|
|
|
Line **lin = msg->line;
|
|
std::vector<char *> urls;
|
|
|
|
for (int n = tline; n < msg->lines; n++)
|
|
{
|
|
const char *ptr = lin[n]->txt.c_str();
|
|
|
|
while (*ptr)
|
|
{
|
|
const char *urlBegin = url_begin(ptr);
|
|
if (urlBegin and not strneql(ptr, "mailto:", 7))
|
|
{
|
|
const char *urlEnd = urlBegin + strcspn(urlBegin, " \t\"\'<>()[]");
|
|
if (ispunct(urlEnd[-1]) and (urlEnd[-1] != '/'))
|
|
--urlEnd;
|
|
|
|
if (urlBegin < urlEnd)
|
|
{
|
|
char* bufurl=(char*)throw_malloc(urlEnd - ptr + 3);
|
|
bufurl[0] = ' ';
|
|
strxcpy(bufurl + 1, ptr, (urlEnd - ptr) + 1);
|
|
strcat(bufurl, " ");
|
|
|
|
std::vector<char *>::iterator it = urls.begin();
|
|
std::vector<char *>::iterator end = urls.end();
|
|
for (; it != end; it++)
|
|
{
|
|
if (strieql(*it, bufurl))
|
|
break;
|
|
}
|
|
|
|
if (it == end)
|
|
urls.push_back(bufurl);
|
|
else
|
|
throw_free(bufurl);
|
|
|
|
ptr = urlEnd - 1;
|
|
}
|
|
}
|
|
|
|
ptr++;
|
|
}
|
|
}
|
|
|
|
w_info(NULL);
|
|
|
|
if (not urls.empty())
|
|
{
|
|
gstrarray Listi;
|
|
|
|
std::vector<char *>::iterator it = urls.begin();
|
|
std::vector<char *>::iterator end = urls.end();
|
|
for (; it != end; it++)
|
|
{
|
|
Listi.push_back(*it);
|
|
}
|
|
|
|
// Sort list if requested
|
|
if(CFG->peekurloptions & FREQ_SORT)
|
|
sort(Listi.begin(), Listi.end(), PeekURLCmp);
|
|
|
|
// Run the picker
|
|
size_t n = MinV(urls.size(), (MAXROW-10));
|
|
set_title(LNG->PeekURLMenuTitle, TCENTER, C_ASKT);
|
|
update_statusline(LNG->PeekURLStat);
|
|
whelppcat(H_PeekURL);
|
|
n = wpickstr(6, 0, 6 + n + 1, -1, W_BASK, C_ASKB, C_ASKW, C_ASKS, Listi, 0, title_shadow);
|
|
whelpop();
|
|
|
|
if(n != -1)
|
|
{
|
|
std::vector<UrlHandler>::iterator it = CFG->urlhandler.begin();
|
|
std::vector<UrlHandler>::iterator end = CFG->urlhandler.end();
|
|
#if 0 // will be implemented later
|
|
for (; it != end; it++)
|
|
{
|
|
if (it->scheme.match(Listi[n].c_str(), gregex::extended | gregex::icase))
|
|
break;
|
|
}
|
|
#else
|
|
it = end;
|
|
#endif
|
|
|
|
if (it == end) it = CFG->urlhandler.begin();
|
|
|
|
std::string cmdline = it->handler.cmdline;
|
|
std::string buf = "\"" + strtrim(strltrim(Listi[n])) + "\"";
|
|
strischg(cmdline, "@url", buf.c_str());
|
|
|
|
buf = CFG->goldpath;
|
|
strchg(buf, GOLD_WRONG_SLASH_CHR, GOLD_SLASH_CHR);
|
|
strischg(cmdline, "@path", buf.c_str());
|
|
|
|
TokenXlat(MODE_NEW, cmdline, msg, msg, CurrArea);
|
|
|
|
int pauseval = 0;
|
|
if (it->handler.options & EXTUTIL_PAUSEONERROR)
|
|
pauseval = -1;
|
|
|
|
if (it->handler.options & EXTUTIL_PAUSE)
|
|
pauseval = 1;
|
|
|
|
ShellToDos(cmdline.c_str(), "",
|
|
it->handler.options & EXTUTIL_CLS ? LGREY_|_BLACK : BLACK_|_BLACK,
|
|
it->handler.options & EXTUTIL_CURSOR,
|
|
pauseval
|
|
);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
w_info(LNG->PeekInfoNoURLs);
|
|
waitkeyt(10000);
|
|
w_info(NULL);
|
|
}
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
void UUDecode(GMsg* msg) {
|
|
|
|
Path infile, outfile;
|
|
bool ok = false;
|
|
|
|
if((*CFG->uudecodepath == NUL) or is_dir(CFG->uudecodepath)) {
|
|
|
|
mktemp(strcpy(infile, AddPath(CFG->temppath, "GDXXXXXX")));
|
|
strcpy(outfile, CFG->uudecodepath);
|
|
|
|
GMenuDomarks MenuDomarks;
|
|
|
|
int source = AA->Mark.Count() ? MenuDomarks.Run(LNG->Decode) : WRITE_CURRENT;
|
|
bool overwrite = true;
|
|
|
|
if(source == WRITE_QUIT)
|
|
return;
|
|
|
|
bool old_quotespacing = CFG->switches.get(quotespacing);
|
|
CFG->switches.set(quotespacing, false);
|
|
|
|
if(source == WRITE_MARKED) {
|
|
for(uint n=0; n<AA->Mark.Count(); n++) {
|
|
if(overwrite and n)
|
|
overwrite = false; // Overwrite only the first time
|
|
w_progress(MODE_UPDATE, C_INFOW, n+1, AA->Mark.Count(), LNG->Preparing);
|
|
AA->LoadMsg(msg, AA->Mark[n], 79);
|
|
SaveLines(overwrite ? MODE_WRITE : MODE_APPEND, infile, msg, 79);
|
|
}
|
|
if(AA->Mark.Count())
|
|
w_progress(MODE_QUIT, BLACK_|_BLACK, 0, 0, NULL);
|
|
}
|
|
else if(source == WRITE_CURRENT) {
|
|
AA->LoadMsg(msg, msg->msgno, 79);
|
|
SaveLines(MODE_WRITE, infile, msg, 79);
|
|
}
|
|
|
|
CFG->switches.set(quotespacing, old_quotespacing);
|
|
|
|
uulist* item;
|
|
int i, res;
|
|
|
|
w_info(LNG->WaitUUdecoding);
|
|
|
|
UUInitialize();
|
|
UUSetOption(UUOPT_SAVEPATH, 0, outfile);
|
|
if((res = UULoadFile(infile, NULL, 0)) == UURET_OK) {
|
|
|
|
for (i=0; (item=UUGetFileListItem(i)) != NULL; i++) {
|
|
if ((item->state & UUFILE_OK) == 0)
|
|
continue;
|
|
if ((res = UUDecodeFile(item, NULL)) == UURET_OK) {
|
|
ok = true;
|
|
w_infof(LNG->CompletedUUdecode, item->filename);
|
|
}
|
|
}
|
|
}
|
|
UUCleanUp ();
|
|
|
|
remove(infile);
|
|
|
|
if(not ok)
|
|
w_info(LNG->NotUUencoded);
|
|
}
|
|
else
|
|
w_info(LNG->UUEinvalidpath);
|
|
|
|
if(not ok)
|
|
waitkeyt(10000);
|
|
|
|
w_info(NULL);
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
void Make_Userlist(const char* userlist)
|
|
{
|
|
word* crclist;
|
|
word crc, crcs=0;
|
|
uint n, x;
|
|
char userline[80], adrs[40];
|
|
|
|
GMsg* msg = (GMsg*)throw_calloc(1, sizeof(GMsg));
|
|
|
|
crclist = (word*)throw_calloc(AA->Msgn.Count()+1, sizeof(word));
|
|
gfile fp(userlist, "ab", CFG->sharemode);
|
|
if (fp.isopen())
|
|
{
|
|
w_progress(MODE_NEW, C_INFOW, 0, AA->Msgn.Count(), LNG->GenUserlist);
|
|
for(n=AA->Msgn.Count(); n; n--) {
|
|
update_statuslinef(LNG->ReadingMsg, "ST_READINGMSG", n, AA->Msgn.Count());
|
|
w_progress(MODE_UPDATE, C_INFOW, (AA->Msgn.Count()-n)+1, AA->Msgn.Count(), NULL);
|
|
AA->LoadMsg(msg, AA->Msgn.CvtReln(n), CFG->dispmargin);
|
|
crc = strCrc16(msg->by, false);
|
|
for(x=0; x<crcs; x++)
|
|
if(crclist[x] == crc)
|
|
break; // We have already used it
|
|
if (x >= crcs)
|
|
{
|
|
crclist[crcs++] = crc;
|
|
strrevname(userline, msg->by);
|
|
msg->orig.make_string(adrs);
|
|
fp.Printf("%-36.36s%24.24s\r\n", userline, adrs);
|
|
}
|
|
}
|
|
throw_free(crclist);
|
|
w_progress(MODE_QUIT, BLACK_|_BLACK, 0, 0, NULL);
|
|
}
|
|
|
|
ResetMsg(msg);
|
|
throw_free(msg);
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
void MakeUserList() {
|
|
|
|
if(AA->Msgn.Count()) {
|
|
uint temp = AA->lastread();
|
|
if(not edit_pathname(CFG->userlistfile, sizeof(Path), LNG->UserlistName, 0))
|
|
return;
|
|
Make_Userlist(AddPath(CFG->goldpath, CFG->userlistfile));
|
|
AA->set_lastread(temp);
|
|
}
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
void TouchSemaphore() {
|
|
|
|
Path file;
|
|
*file = NUL;
|
|
if(edit_string(file, sizeof(Path), LNG->TouchSemaphore, 0))
|
|
TouchFile(file);
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
void make_pathreport(const char* reportfile)
|
|
{
|
|
gfile fp(reportfile, "wt");
|
|
if (fp.isopen())
|
|
{
|
|
std::string path;
|
|
ftn_addr address;
|
|
std::vector<ftn_addr> alist;
|
|
GMsg* msg = (GMsg*)throw_calloc(1, sizeof(GMsg));
|
|
w_progress(MODE_NEW, C_INFOW, 0, AA->Msgn.Count(), "Generating PATH report");
|
|
for(int n=AA->Msgn.Count(); n>=AA->lastread(); n--) {
|
|
update_statuslinef(LNG->ReadingMsg, "ST_READINGMSG", n, AA->Msgn.Count());
|
|
w_progress(MODE_UPDATE, C_INFOW, n, AA->Msgn.Count(), NULL);
|
|
AA->LoadMsg(msg, AA->Msgn.CvtReln(n), CFG->dispmargin-(int)CFG->switches.get(disppagebar));
|
|
address = msg->orig;
|
|
int x;
|
|
for(x=0; x<alist.size(); x++) {
|
|
if(alist[x] == address)
|
|
break; // We have already used it
|
|
}
|
|
if(x >= alist.size()) {
|
|
alist.push_back(address);
|
|
INam buf;
|
|
strcpy(buf, msg->By());
|
|
strchg(buf, ' ', '_');
|
|
std::string temp;
|
|
fp.Printf("%s %s ", buf, address.make_string(temp).c_str());
|
|
path = "";
|
|
Line* line = msg->lin;
|
|
while(line) {
|
|
if(line->kludge == GKLUD_PATH)
|
|
path += line->txt.c_str() + 6;
|
|
line = line->next;
|
|
}
|
|
if(path.length()) {
|
|
gstrarray links;
|
|
tokenize(links, path.c_str(), " ");
|
|
for(int i=0; i<links.size(); i++)
|
|
address = links[i];
|
|
}
|
|
fp.Printf("%s\n", path.c_str());
|
|
}
|
|
}
|
|
w_progress(MODE_QUIT, BLACK_|_BLACK, 0, 0, NULL);
|
|
ResetMsg(msg);
|
|
throw_free(msg);
|
|
}
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
void MakePathreport() {
|
|
|
|
if(AA->Msgn.Count()) {
|
|
uint temp = AA->lastread();
|
|
if(not edit_pathname(CFG->pathreportfile, sizeof(Path), LNG->Pathreport, 0))
|
|
return;
|
|
make_pathreport(AddPath(CFG->goldpath, CFG->pathreportfile));
|
|
AA->set_lastread(temp);
|
|
}
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|