/*
* mshcmds.c -- command handlers in msh
*
* $Id: mshcmds.c,v 1.12 2003/09/30 16:58:43 gbburkhardt Exp $
*
* This code is Copyright (c) 2002, by the authors of nmh. See the
* COPYRIGHT file in the root directory of the nmh distribution for
* complete copyright information.
*/
#include <h/mh.h>
#include <h/signals.h>
#include <h/dropsbr.h>
#include <h/fmt_scan.h>
#include <h/scansbr.h>
#include <h/tws.h>
#include <h/mts.h>
#include <errno.h>
#include <setjmp.h>
#include <signal.h>
#include <h/msh.h>
#include <h/picksbr.h>
static char delim3[] = "-------"; /* from burst.c */
static int mhlnum;
static FILE *mhlfp;
#if defined(NNTP) && defined(MPOP)
# undef MPOP
#endif
#ifdef MPOP
# ifdef BPOP
extern int pmsh;
extern char response[];
# endif
#endif /* MPOP */
/*
* Type for a compare function for qsort. This keeps
* the compiler happy.
*/
typedef int (*qsort_comp) (const void *, const void *);
/*
* prototypes
*/
void clear_screen (void); /* from termsbr.c */
int SOprintf (char *, ...); /* from termsbr.c */
int sc_width (void); /* from termsbr.c */
/*
* static prototypes
*/
static int burst (struct Msg *, int, int, int, int);
static void forw (char *, char *, int, char **);
static void rmm (void);
static void show (int);
static int eom_action (int);
static FILE *mhl_action (char *);
static int ask (int);
static int is_nontext (int);
static int get_fields (char *, char *, int, struct Msg *);
static int msgsort (struct Msg *, struct Msg *);
static int subsort (struct Msg *, struct Msg *);
static char *sosmash (char *, char *);
static int process (int, char *, int, char **);
static void copy_message (int, FILE *);
static void copy_digest (int, FILE *);
/* from mhlsbr.c */
int mhlsbr (int, char **, FILE *(*)());
void
forkcmd (char **args, char *pgm)
{
int child_id;
char *vec[MAXARGS];
vec[0] = r1bindex (pgm, '/');
copyip (args, vec + 1, MAXARGS - 1);
if (fmsh) {
context_del (pfolder);
context_replace (pfolder, fmsh);/* update current folder */
seq_save (mp);
context_save (); /* save the context file */
}
fflush (stdout);
switch (child_id = fork ()) {
case NOTOK:
advise ("fork", "unable to");
return;
case OK:
closefds (3);
SIGNAL (SIGINT, istat);
SIGNAL (SIGQUIT, qstat);
execvp (pgm, vec);
fprintf (stderr, "unable to exec ");
perror (cmd_name);
_exit (1);
default:
pidXwait (child_id, NULL);
break;
}
if (fmsh) { /* assume the worst case */
mp->msgflags |= MODIFIED;
modified++;
}
}
static struct swit distswit[] = {
#define DIANSW 0
{ "annotate", 0 },
#define DINANSW 1
{ "noannotate", 0 },
#define DIDFSW 2
{ "draftfolder +folder", 0 },
#define DIDMSW 3
{ "draftmessage msg", 0 },
#define DINDFSW 4
{ "nodraftfolder", 0 },
#define DIEDTSW 5
{ "editor editor", 0 },
#define DINEDSW 6
{ "noedit", 0 },
#define DIFRMSW 7
{ "form formfile", 0 },
#define DIINSW 8
{ "inplace", 0 },
#define DININSW 9
{ "noinplace", 0 },
#define DIWHTSW 10
{ "whatnowproc program", 0 },
#define DINWTSW 11
{ "nowhatnowproc", 0 },
#define DIHELP 12
{ "help", 0 },
{ NULL, 0 }
};
void
distcmd (char **args)
{
int vecp = 1;
char *cp, *msg = NULL;
char buf[BUFSIZ], *vec[MAXARGS];
if (fmsh) {
forkcmd (args, cmd_name);
return;
}
while ((cp = *args++)) {
if (*cp == '-')
switch (smatch (++cp, distswit)) {
case AMBIGSW:
ambigsw (cp, distswit);
return;
case UNKWNSW:
fprintf (stderr, "-%s unknown\n", cp);
return;
case DIHELP:
snprintf (buf, sizeof(buf), "%s [msgs] [switches]", cmd_name);
print_help (buf, distswit, 1);
return;
case DIANSW: /* not implemented */
case DINANSW:
case DIINSW:
case DININSW:
continue;
case DINDFSW:
case DINEDSW:
case DINWTSW:
vec[vecp++] = --cp;
continue;
case DIEDTSW:
case DIFRMSW:
case DIDFSW:
case DIDMSW:
case DIWHTSW:
vec[vecp++] = --cp;
if (!(cp = *args++) || *cp == '-') {
advise (NULL, "missing argument to %s", args[-2]);
return;
}
vec[vecp++] = cp;
continue;
}
if (*cp == '+' || *cp == '@') {
advise (NULL, "sorry, no folders allowed!");
return;
}
else
if (msg) {
advise (NULL, "only one message at a time!");
return;
}
else
msg = cp;
}
vec[0] = cmd_name;
vec[vecp++] = "-file";
vec[vecp] = NULL;
if (!msg)
msg = "cur";
if (!m_convert (mp, msg))
return;
seq_setprev (mp);
if (mp->numsel > 1) {
advise (NULL, "only one message at a time!");
return;
}
process (mp->hghsel, cmd_name, vecp, vec);
seq_setcur (mp, mp->hghsel);
}
static struct swit explswit[] = {
#define EXINSW 0
{ "inplace", 0 },
#define EXNINSW 1
{ "noinplace", 0 },
#define EXQISW 2
{ "quiet", 0 },
#define EXNQISW 3
{ "noquiet", 0 },
#define EXVBSW 4
{ "verbose", 0 },
#define EXNVBSW 5
{ "noverbose", 0 },
#define EXHELP 6
{ "help", 0 },
{ NULL, 0 }
};
void
explcmd (char **args)
{
int inplace = 0, quietsw = 0, verbosw = 0;
int msgp = 0, hi, msgnum;
char *cp, buf[BUFSIZ], *msgs[MAXARGS];
struct Msg *smsgs;
if (fmsh) {
forkcmd (args, cmd_name);
return;
}
while ((cp = *args++)) {
if (*cp == '-')
switch (smatch (++cp, explswit)) {
case AMBIGSW:
ambigsw (cp, explswit);
return;
case UNKWNSW:
fprintf (stderr, "-%s unknown\n", cp);
return;
case EXHELP:
snprintf (buf, sizeof(buf), "%s [msgs] [switches]", cmd_name);
print_help (buf, explswit, 1);
return;
case EXINSW:
inplace++;
continue;
case EXNINSW:
inplace = 0;
continue;
case EXQISW:
quietsw++;
continue;
case EXNQISW:
quietsw = 0;
continue;
case EXVBSW:
verbosw++;
continue;
case EXNVBSW:
verbosw = 0;
continue;
}
if (*cp == '+' || *cp == '@') {
advise (NULL, "sorry, no folders allowed!");
return;
}
else
msgs[msgp++] = cp;
}
if (!msgp)
msgs[msgp++] = "cur";
for (msgnum = 0; msgnum < msgp; msgnum++)
if (!m_convert (mp, msgs[msgnum]))
return;
seq_setprev (mp);
smsgs = (struct Msg *)
calloc ((size_t) (MAXFOLDER + 2), sizeof *smsgs);
if (smsgs == NULL)
adios (NULL, "unable to allocate folder storage");
hi = mp->hghmsg + 1;
interrupted = 0;
for (msgnum = mp->lowsel;
msgnum <= mp->hghsel && !interrupted;
msgnum++)
if (is_selected (mp, msgnum))
if (burst (smsgs, msgnum, inplace, quietsw, verbosw) != OK)
break;
free ((char *) smsgs);
if (inplace)
seq_setcur (mp, mp->lowsel);
else
if (hi <= mp->hghmsg)
seq_setcur (mp, hi);
mp->msgflags |= MODIFIED;
modified++;
}
static int
burst (struct Msg *smsgs, int msgnum, int inplace, int quietsw, int verbosw)
{
int i, j, ld3, wasdlm, msgp;
long pos;
char c, buffer[BUFSIZ];
register FILE *zp;
ld3 = strlen (delim3);
if (Msgs[msgnum].m_scanl) {
free (Msgs[msgnum].m_scanl);
Msgs[msgnum].m_scanl = NULL;
}
pos = ftell (zp = msh_ready (msgnum, 1));
for (msgp = 0; msgp <= MAXFOLDER;) {
while (fgets (buffer, sizeof buffer, zp) != NULL
&& buffer[0] == '\n'
&& pos < Msgs[msgnum].m_stop)
pos += (long) strlen (buffer);
if (feof (zp) || pos >= Msgs[msgnum].m_stop)
break;
fseek (zp, pos, SEEK_SET);
smsgs[msgp].m_start = pos;
for (c = 0;
pos < Msgs[msgnum].m_stop
&& fgets (buffer, sizeof buffer, zp) != NULL;
c = buffer[0])
if (strncmp (buffer, delim3, ld3) == 0
&& (msgp == 1 || c == '\n')
&& peekc (zp) == '\n')
break;
else
pos += (long) strlen (buffer);
wasdlm = strncmp (buffer, delim3, ld3) == 0;
if (smsgs[msgp].m_start != pos)
smsgs[msgp++].m_stop = (c == '\n' && wasdlm) ? pos - 1 : pos;
if (feof (zp) || pos >= Msgs[msgnum].m_stop) {
if (wasdlm)
smsgs[msgp - 1].m_stop -= ((long) strlen (buffer) + 1);
break;
}
pos += (long) strlen (buffer);
}
switch (msgp--) { /* toss "End of XXX Digest" */
case 0:
adios (NULL, "burst() botch -- you lose big");
case 1:
if (!quietsw)
printf ("message %d not in digest format\n", msgnum);
return OK;
default:
if (verbosw)
printf ("%d message%s exploded from digest %d\n",
msgp, msgp != 1 ? "s" : "", msgnum);
break;
}
if ((i = msgp + mp->hghmsg) > MAXFOLDER) {
advise (NULL, "more than %d messages", MAXFOLDER);
return NOTOK;
}
if (!(mp = folder_realloc (mp, mp->lowoff, i)))
adios (NULL, "unable to allocate folder storage");
j = mp->hghmsg;
mp->hghmsg += msgp;
mp->nummsg += msgp;
if (mp->hghsel > msgnum)
mp->hghsel += msgp;
if (inplace)
for (i = mp->hghmsg; j > msgnum; i--, j--) {
if (verbosw)
printf ("message %d becomes message %d\n", j, i);
Msgs[i].m_bboard_id = Msgs[j].m_bboard_id;
Msgs[i].m_top = Msgs[j].m_top;
Msgs[i].m_start = Msgs[j].m_start;
Msgs[i].m_stop = Msgs[j].m_stop;
Msgs[i].m_scanl = NULL;
if (Msgs[j].m_scanl) {
free (Msgs[j].m_scanl);
Msgs[j].m_scanl = NULL;
}
copy_msg_flags (mp, i, j);
}
if (Msgs[msgnum].m_bboard_id == 0)
readid (msgnum);
unset_selected (mp, msgnum);
i = inplace ? msgnum + msgp : mp->hghmsg;
for (j = msgp; j >= (inplace ? 0 : 1); i--, j--) {
if (verbosw && i != msgnum)
printf ("message %d of digest %d becomes message %d\n",
j, msgnum, i);
Msgs[i].m_bboard_id = Msgs[msgnum].m_bboard_id;
Msgs[i].m_top = Msgs[j].m_top;
Msgs[i].m_start = smsgs[j].m_start;
Msgs[i].m_stop = smsgs[j].m_stop;
Msgs[i].m_scanl = NULL;
copy_msg_flags (mp, i, msgnum);
}
return OK;
}
static struct swit fileswit[] = {
#define FIDRFT 0
{ "draft", 0 },
#define FILINK 1
{ "link", 0 },
#define FINLINK 2
{ "nolink", 0 },
#define FIPRES 3
{ "preserve", 0 },
#define FINPRES 4
{ "nopreserve", 0 },
#define FISRC 5
{ "src +folder", 0 },
#define FIFILE 6
{ "file file", 0 },
#define FIPROC 7
{ "rmmproc program", 0 },
#define FINPRC 8
{ "normmproc", 0 },
#define FIHELP 9
{ "help", 0 },
{ NULL, 0 }
};
void
filecmd (char **args)
{
int linksw = 0, msgp = 0;
int vecp = 1, i, msgnum;
char *cp, buf[BUFSIZ];
char *msgs[MAXARGS], *vec[MAXARGS];
if (fmsh) {
forkcmd (args, cmd_name);
return;
}
while ((cp = *args++)) {
if (*cp == '-')
switch (i = smatch (++cp, fileswit)) {
case AMBIGSW:
ambigsw (cp, fileswit);
return;
case UNKWNSW:
fprintf (stderr, "-%s unknown\n", cp);
return;
case FIHELP:
snprintf (buf, sizeof(buf), "%s +folder... [msgs] [switches]", cmd_name);
print_help (buf, fileswit, 1);
return;
case FILINK:
linksw++;
continue;
case FINLINK:
linksw = 0;
continue;
case FIPRES:
case FINPRES:
continue;
case FISRC:
case FIDRFT:
case FIFILE:
case FIPROC:
case FINPRC:
advise (NULL, "sorry, -%s not allowed!", fileswit[i].sw);
return;
}
if (*cp == '+' || *cp == '@')
vec[vecp++] = cp;
else
msgs[msgp++] = cp;
}
vec[0] = cmd_name;
vec[vecp++] = "-file";
vec[vecp] = NULL;
if (!msgp)
msgs[msgp++] = "cur";
for (msgnum = 0; msgnum < msgp; msgnum++)
if (!m_convert (mp, msgs[msgnum]))
return;
seq_setprev (mp);
interrupted = 0;
for (msgnum = mp->lowsel;
msgnum <= mp->hghsel && !interrupted;
msgnum++)
if (is_selected (mp, msgnum))
if (process (msgnum, fileproc, vecp, vec)) {
unset_selected (mp, msgnum);
mp->numsel--;
}
if (mp->numsel != mp->nummsg || linksw)
seq_setcur (mp, mp->hghsel);
if (!linksw)
rmm ();
}
int
filehak (char **args)
{
int result, vecp = 0;
char *cp, *cwd, *vec[MAXARGS];
while ((cp = *args++)) {
if (*cp == '-')
switch (smatch (++cp, fileswit)) {
case AMBIGSW:
case UNKWNSW:
case FIHELP:
return NOTOK;
case FILINK:
case FINLINK:
case FIPRES:
case FINPRES:
continue;
case FISRC:
case FIDRFT:
case FIFILE:
return NOTOK;
}
if (*cp == '+' || *cp == '@')
vec[vecp++] = cp;
}
vec[vecp] = NULL;
result = NOTOK;
cwd = NULL;
for (vecp = 0; (cp = vec[vecp]) && result == NOTOK; vecp++) {
if (cwd == NULL)
cwd = getcpy (pwd ());
chdir (m_maildir (""));
cp = path (cp + 1, *cp == '+' ? TFOLDER : TSUBCWF);
if (access (m_maildir (cp), F_OK) == NOTOK)
result = OK;
free (cp);
}
if (cwd)
chdir (cwd);
return result;
}
static struct swit foldswit[] = {
#define FLALSW 0
{ "all", 0 },
#define FLFASW 1
{ "fast", 0 },
#define FLNFASW 2
{ "nofast", 0 },
#define FLHDSW 3
{ "header", 0 },
#define FLNHDSW 4
{ "noheader", 0 },
#define FLPKSW 5
{ "pack", 0 },
#define FLNPKSW 6
{ "nopack", 0 },
#define FLRCSW 7
{ "recurse", 0 },
#define FLNRCSW 8
{ "norecurse", 0 },
#define FLTLSW 9
{ "total", 0 },
#define FLNTLSW 10
{ "nototal", 0 },
#define FLPRSW 11
{ "print", 0 },
#define FLPUSW 12
{ "push", 0 },
#define FLPOSW 13
{ "pop", 0 },
#define FLLISW 14
{ "list", 0 },
#define FLHELP 15
{ "help", 0 },
{ NULL, 0 }
};
void
foldcmd (char **args)
{
int fastsw = 0, headersw = 0, packsw = 0;
int hole, msgnum;
char *cp, *folder = NULL, *msg = NULL;
char buf[BUFSIZ], **vec = args;
if (args == NULL)
goto fast;
while ((cp = *args++)) {
if (*cp == '-')
switch (smatch (++cp, foldswit)) {
case AMBIGSW:
ambigsw (cp, foldswit);
return;
case UNKWNSW:
fprintf (stderr, "-%s unknown\n", cp);
return;
case FLHELP:
snprintf (buf, sizeof(buf), "%s [+folder] [msg] [switches]", cmd_name);
print_help (buf, foldswit, 1);
return;
case FLALSW: /* not implemented */
case FLRCSW:
case FLNRCSW:
case FLTLSW:
case FLNTLSW:
case FLPRSW:
case FLPUSW:
case FLPOSW:
case FLLISW:
continue;
case FLFASW:
fastsw++;
continue;
case FLNFASW:
fastsw = 0;
continue;
case FLHDSW:
headersw++;
continue;
case FLNHDSW:
headersw = 0;
continue;
case FLPKSW:
packsw++;
continue;
case FLNPKSW:
packsw = 0;
continue;
}
if (*cp == '+' || *cp == '@') {
if (folder) {
advise (NULL, "only one folder at a time!\n");
return;
}
else
folder = fmsh ? path (cp + 1, *cp == '+' ? TFOLDER : TSUBCWF)
: cp + 1;
}
else
if (msg) {
advise (NULL, "only one message at a time!\n");
return;
}
else
msg = cp;
}
if (folder) {
if (*folder == 0) {
advise (NULL, "null folder names are not permitted");
return;
}
if (fmsh) {
if (access (m_maildir (folder), R_OK) == NOTOK) {
advise (folder, "unable to read");
return;
}
}
else {
strncpy (buf, folder, sizeof(buf));
if (expand (buf) == NOTOK)
return;
folder = buf;
if (access (folder, R_OK) == NOTOK) {
advise (folder, "unable to read");
return;
}
}
m_reset ();
if (fmsh)
fsetup (folder);
else
setup (folder);
readids (0);
display_info (0);
}
if (msg) {
if (!m_convert (mp, msg))
return;
seq_setprev (mp);
if (mp->numsel > 1) {
advise (NULL, "only one message at a time!");
return;
}
seq_setcur (mp, mp->hghsel);
}
if (packsw) {
if (fmsh) {
forkcmd (vec, cmd_name);
return;
}
if (mp->lowoff > 1 && !(mp = folder_realloc (mp, 1, mp->hghmsg)))
adios (NULL, "unable to allocate folder storage");
for (msgnum = mp->lowmsg, hole = 1; msgnum <= mp->hghmsg; msgnum++)
if (does_exist (mp, msgnum)) {
if (msgnum != hole) {
Msgs[hole].m_bboard_id = Msgs[msgnum].m_bboard_id;
Msgs[hole].m_top = Msgs[msgnum].m_top;
Msgs[hole].m_start = Msgs[msgnum].m_start;
Msgs[hole].m_stop = Msgs[msgnum].m_stop;
Msgs[hole].m_scanl = NULL;
if (Msgs[msgnum].m_scanl) {
free (Msgs[msgnum].m_scanl);
Msgs[msgnum].m_scanl = NULL;
}
copy_msg_flags (mp, hole, msgnum);
if (mp->curmsg == msgnum)
seq_setcur (mp, hole);
}
hole++;
}
if (mp->nummsg > 0) {
mp->lowmsg = 1;
mp->hghmsg = hole - 1;
}
mp->msgflags |= MODIFIED;
modified++;
}
fast: ;
if (fastsw)
printf ("%s\n", fmsh ? fmsh : mp->foldpath);
else {
if (headersw)
printf ("\t\tFolder %*s# of messages (%*srange%*s); cur%*smsg\n",
DMAXFOLDER, "", DMAXFOLDER - 2, "", DMAXFOLDER - 2, "",
DMAXFOLDER - 2, "");
printf (args ? "%22s " : "%s ", fmsh ? fmsh : mp->foldpath);
/* check for empty folder */
if (mp->nummsg == 0) {
printf ("has no messages%*s",
mp->msgflags & OTHERS ? DMAXFOLDER * 2 + 4 : 0, "");
} else {
printf ("has %*d message%s (%*d-%*d)",
DMAXFOLDER, mp->nummsg, mp->nummsg != 1 ? "s" : "",
DMAXFOLDER, mp->lowmsg, DMAXFOLDER, mp->hghmsg);
if (mp->curmsg >= mp->lowmsg
&& mp->curmsg <= mp->hghmsg)
printf ("; cur=%*d", DMAXFOLDER, mp->curmsg);
}
printf (".\n");
}
}
static struct swit forwswit[] = {
#define FOANSW 0
{ "annotate", 0 },
#define FONANSW 1
{ "noannotate", 0 },
#define FODFSW 2
{ "draftfolder +folder", 0 },
#define FODMSW 3
{ "draftmessage msg", 0 },
#define FONDFSW 4
{ "nodraftfolder", 0 },
#define FOEDTSW 5
{ "editor editor", 0 },
#define FONEDSW 6
{ "noedit", 0 },
#define FOFTRSW 7
{ "filter filterfile", 0 },
#define FOFRMSW 8
{ "form formfile", 0 },
#define FOFTSW 9
{ "format", 5 },
#define FONFTSW 10
{ "noformat", 7 },
#define FOINSW 11
{ "inplace", 0 },
#define FONINSW 12
{ "noinplace", 0 },
#define FOMISW 13
{ "mime", 0 },
#define FONMISW 14
{ "nomime", 0 },
#define FOWHTSW 15
{ "whatnowproc program", 0 },
#define FONWTSW 16
{ "nowhatnow", 0 },
#define FOHELP 17
{ "help", 0 },
{ NULL, 0 }
};
void
forwcmd (char **args)
{
int msgp = 0, vecp = 1, msgnum;
char *cp, *filter = NULL, buf[BUFSIZ];
char *msgs[MAXARGS], *vec[MAXARGS];
if (fmsh) {
forkcmd (args, cmd_name);
return;
}
while ((cp = *args++)) {
if (*cp == '-')
switch (smatch (++cp, forwswit)) {
case AMBIGSW:
ambigsw (cp, forwswit);
return;
case UNKWNSW:
fprintf (stderr, "-%s unknown\n", cp);
return;
case FOHELP:
snprintf (buf, sizeof(buf), "%s [msgs] [switches]", cmd_name);
print_help (buf, forwswit, 1);
return;
case FOANSW: /* not implemented */
case FONANSW:
case FOINSW:
case FONINSW:
case FOMISW:
case FONMISW:
continue;
case FONDFSW:
case FONEDSW:
case FONWTSW:
vec[vecp++] = --cp;
continue;
case FOEDTSW:
case FOFRMSW:
case FODFSW:
case FODMSW:
case FOWHTSW:
vec[vecp++] = --cp;
if (!(cp = *args++) || *cp == '-') {
advise (NULL, "missing argument to %s", args[-2]);
return;
}
vec[vecp++] = cp;
continue;
case FOFTRSW:
if (!(filter = *args++) || *filter == '-') {
advise (NULL, "missing argument to %s", args[-2]);
return;
}
continue;
case FOFTSW:
if (access (filter = myfilter, R_OK) == NOTOK) {
advise (filter, "unable to read default filter file");
return;
}
continue;
case FONFTSW:
filter = NULL;
continue;
}
if (*cp == '+' || *cp == '@') {
advise (NULL, "sorry, no folders allowed!");
return;
}
else
msgs[msgp++] = cp;
}
/* foil search of .mh_profile */
snprintf (buf, sizeof(buf), "%sXXXXXX", invo_name);
/*
Mkstemp work postponed until later -Doug
#ifdef HAVE_MKSTEMP
vec[0] = (char *)mkstemp (buf);
#else
*/
vec[0] = (char *)mktemp (buf);
/*
#endif
*/
vec[vecp++] = "-file";
vec[vecp] = NULL;
if (!msgp)
msgs[msgp++] = "cur";
for (msgnum = 0; msgnum < msgp; msgnum++)
if (!m_convert (mp, msgs[msgnum]))
return;
seq_setprev (mp);
if (filter) {
strncpy (buf, filter, sizeof(buf));
if (expand (buf) == NOTOK)
return;
if (access (filter = getcpy (etcpath (buf)), R_OK) == NOTOK) {
advise (filter, "unable to read");
free (filter);
return;
}
}
forw (cmd_name, filter, vecp, vec);
seq_setcur (mp, mp->hghsel);
if (filter)
free (filter);
}
static void
forw (char *proc, char *filter, int vecp, char **vec)
{
int i, child_id, msgnum, msgcnt;
char tmpfil[80], *args[MAXARGS];
FILE *out;
strncpy (tmpfil, m_tmpfil (invo_name), sizeof(tmpfil));
interrupted = 0;
if (filter)
switch (child_id = fork ()) {
case NOTOK:
advise ("fork", "unable to");
return;
case OK: /* "trust me" */
if (freopen (tmpfil, "w", stdout) == NULL) {
fprintf (stderr, "unable to create ");
perror (tmpfil);
_exit (1);
}
args[0] = r1bindex (mhlproc, '/');
i = 1;
args[i++] = "-forwall";
args[i++] = "-form";
args[i++] = filter;
for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++)
if (is_selected (mp, msgnum))
args[i++] = getcpy (m_name (msgnum));
args[i] = NULL;
mhlsbr (i, args, mhl_action);
m_eomsbr ((int (*) ()) 0);
fclose (stdout);
_exit (0);
default:
if (pidXwait (child_id, NULL))
interrupted++;
break;
}
else {
if ((out = fopen (tmpfil, "w")) == NULL) {
advise (tmpfil, "unable to create temporary file");
return;
}
msgcnt = 1;
for (msgnum = mp->lowsel;
msgnum <= mp->hghsel && !interrupted;
msgnum++)
if (is_selected (mp, msgnum)) {
fprintf (out, "\n\n-------");
if (msgnum == mp->lowsel)
fprintf (out, " Forwarded Message%s",
mp->numsel > 1 ? "s" : "");
else
fprintf (out, " Message %d", msgcnt);
fprintf (out, "\n\n");
copy_digest (msgnum, out);
msgcnt++;
}
fprintf (out, "\n\n------- End of Forwarded Message%s\n",
mp->numsel > 1 ? "s" : "");
fclose (out);
}
fflush (stdout);
if (!interrupted)
switch (child_id = fork ()) {
case NOTOK:
advise ("fork", "unable to");
break;
case OK:
closefds (3);
SIGNAL (SIGINT, istat);
SIGNAL (SIGQUIT, qstat);
vec[vecp++] = tmpfil;
vec[vecp] = NULL;
execvp (proc, vec);
fprintf (stderr, "unable to exec ");
perror (proc);
_exit (1);
default:
pidXwait (child_id, NULL);
break;
}
unlink (tmpfil);
}
static char *hlpmsg[] = {
"The %s program emulates many of the commands found in the nmh",
"system. Instead of operating on nmh folders, commands to %s concern",
"a single file.",
"",
"To see the list of commands available, just type a ``?'' followed by",
"the RETURN key. To find out what switches each command takes, type",
"the name of the command followed by ``-help''. To leave %s, use the",
"``quit'' command.",
"",
"Although a lot of nmh commands are found in %s, not all are fully",
"implemented. %s will always recognize all legal switches for a",
"given command though, and will let you know when you ask for an",
"option that it is unable to perform.",
"",
"Running %s is fun, but using nmh from your shell is far superior.",
"After you have familiarized yourself with the nmh style by using %s,",
"you should try using nmh from the shell. You can still use %s for",
"message files that aren't in nmh format, such as BBoard files.",
NULL
};
void
helpcmd (char **args)
{
int i;
for (i = 0; hlpmsg[i]; i++) {
printf (hlpmsg[i], invo_name);
putchar ('\n');
}
}
static struct swit markswit[] = {
#define MADDSW 0
{ "add", 0 },
#define MDELSW 1
{ "delete", 0 },
#define MLSTSW 2
{ "list", 0 },
#define MSEQSW 3
{ "sequence name", 0 },
#define MPUBSW 4
{ "public", 0 },
#define MNPUBSW 5
{ "nopublic", 0 },
#define MZERSW 6
{ "zero", 0 },
#define MNZERSW 7
{ "nozero", 0 },
#define MHELP 8
{ "help", 0 },
#define MDBUGSW 9
{ "debug", -5 },
{ NULL, 0 }
};
void
markcmd (char **args)
{
int addsw = 0, deletesw = 0, debugsw = 0;
int listsw = 0, zerosw = 0, seqp = 0;
int msgp = 0, msgnum;
char *cp, buf[BUFSIZ];
char *seqs[NUMATTRS + 1], *msgs[MAXARGS];
while ((cp = *args++)) {
if (*cp == '-') {
switch (smatch (++cp, markswit)) {
case AMBIGSW:
ambigsw (cp, markswit);
return;
case UNKWNSW:
fprintf (stderr, "-%s unknown\n", cp);
return;
case MHELP:
snprintf (buf, sizeof(buf), "%s [msgs] [switches]", cmd_name);
print_help (buf, markswit, 1);
return;
case MADDSW:
addsw++;
deletesw = listsw = 0;
continue;
case MDELSW:
deletesw++;
addsw = listsw = 0;
continue;
case MLSTSW:
listsw++;
addsw = deletesw = 0;
continue;
case MSEQSW:
if (!(cp = *args++) || *cp == '-') {
advise (NULL, "missing argument to %s", args[-2]);
return;
}
if (seqp < NUMATTRS)
seqs[seqp++] = cp;
else {
advise (NULL, "only %d sequences allowed!", NUMATTRS);
return;
}
continue;
case MPUBSW: /* not implemented */
case MNPUBSW:
continue;
case MDBUGSW:
debugsw++;
continue;
case MZERSW:
zerosw++;
continue;
case MNZERSW:
zerosw = 0;
continue;
}
}
if (*cp == '+' || *cp == '@') {
advise (NULL, "sorry, no folders allowed!");
return;
} else {
msgs[msgp++] = cp;
}
}
if (!addsw && !deletesw && !listsw) {
if (seqp)
addsw++;
else
if (debugsw)
listsw++;
else {
seqs[seqp++] = "unseen";
deletesw++;
zerosw = 0;
if (!msgp)
msgs[msgp++] = "all";
}
}
if (!msgp)
msgs[msgp++] = listsw ? "all" :"cur";
for (msgnum = 0; msgnum < msgp; msgnum++)
if (!m_convert (mp, msgs[msgnum]))
return;
if (debugsw) {
printf ("invo_name=%s mypath=%s defpath=%s\n",
invo_name, mypath, defpath);
printf ("ctxpath=%s context flags=%s\n",
ctxpath, snprintb (buf, sizeof(buf), (unsigned) ctxflags, DBITS));
printf ("foldpath=%s flags=%s\n",
mp->foldpath,
snprintb (buf, sizeof(buf), (unsigned) mp->msgflags, FBITS));
printf ("hghmsg=%d lowmsg=%d nummsg=%d curmsg=%d\n",
mp->hghmsg, mp->lowmsg, mp->nummsg, mp->curmsg);
printf ("lowsel=%d hghsel=%d numsel=%d\n",
mp->lowsel, mp->hghsel, mp->numsel);
printf ("lowoff=%d hghoff=%d\n", mp->lowoff, mp->hghoff);
}
if (seqp == 0 && (addsw || deletesw)) {
advise (NULL, "-%s requires at least one -sequence argument",
addsw ? "add" : "delete");
return;
}
seqs[seqp] = NULL;
if (addsw) {
for (seqp = 0; seqs[seqp]; seqp++)
if (!seq_addsel (mp, seqs[seqp], 0, zerosw))
return;
}
if (deletesw) {
for (seqp = 0; seqs[seqp]; seqp++)
if (!seq_delsel (mp, seqs[seqp], 0, zerosw))
return;
}
/* Listing messages in sequences */
if (listsw) {
if (seqp) {
/* list the given sequences */
for (seqp = 0; seqs[seqp]; seqp++)
seq_print (mp, seqs[seqp]);
} else {
/* else list them all */
seq_printall (mp);
}
interrupted = 0;
if (debugsw)
for (msgnum = mp->lowsel;
msgnum <= mp->hghsel && !interrupted;
msgnum++)
if (is_selected (mp, msgnum)) {
printf ("%*d: id=%d top=%d start=%ld stop=%ld %s\n",
DMAXFOLDER,
msgnum,
Msgs[msgnum].m_bboard_id,
Msgs[msgnum].m_top,
(long) Msgs[msgnum].m_start,
(long) Msgs[msgnum].m_stop,
snprintb (buf, sizeof(buf),
(unsigned) mp->msgstats[msgnum - mp->lowoff],
seq_bits (mp)));
if (Msgs[msgnum].m_scanl)
printf ("%s", Msgs[msgnum].m_scanl);
}
}
}
static struct swit mhnswit[] = {
#define MHNAUTOSW 0
{ "auto", 0 },
#define MHNNAUTOSW 1
{ "noauto", 0 },
#define MHNDEBUGSW 2
{ "debug", -5 },
#define MHNEBCDICSW 3
{ "ebcdicsafe", 0 },
#define MHNNEBCDICSW 4
{ "noebcdicsafe", 0 },
#define MHNFORMSW 5
{ "form formfile", 4 },
#define MHNHEADSW 6
{ "headers", 0 },
#define MHNNHEADSW 7
{ "noheaders", 0 },
#define MHNLISTSW 8
{ "list", 0 },
#define MHNNLISTSW 9
{ "nolist", 0 },
#define MHNPARTSW 10
{ "part number", 0 },
#define MHNSIZESW 11
{ "realsize", 0 },
#define MHNNSIZESW 12
{ "norealsize", 0 },
#define MHNRFC934SW 13
{ "rfc934mode", 0 },
#define MHNNRFC934SW 14
{ "norfc934mode", 0 },
#define MHNSERIALSW 15
{ "serialonly", 0 },
#define MHNNSERIALSW 16
{ "noserialonly", 0 },
#define MHNSHOWSW 17
{ "show", 0 },
#define MHNNSHOWSW 18
{ "noshow", 0 },
#define MHNSTORESW 19
{ "store", 0 },
#define MHNNSTORESW 20
{ "nostore", 0 },
#define MHNTYPESW 21
{ "type content", 0 },
#define MHNVERBSW 22
{ "verbose", 0 },
#define MHNNVERBSW 23
{ "noverbose", 0 },
#define MHNHELPSW 24
{ "help", 0 },
#define MHNPROGSW 25
{ "moreproc program", -4 },
#define MHNNPROGSW 26
{ "nomoreproc", -3 },
#define MHNLENSW 27
{ "length lines", -4 },
#define MHNWIDSW 28
{ "width columns", -4 },
{ NULL, 0 }
};
void
mhncmd (char **args)
{
int msgp = 0, vecp = 1;
int msgnum;
char *cp, buf[BUFSIZ];
char *msgs[MAXARGS], *vec[MAXARGS];
if (fmsh) {
forkcmd (args, cmd_name);
return;
}
while ((cp = *args++)) {
if (*cp == '-') {
switch (smatch (++cp, mhnswit)) {
case AMBIGSW:
ambigsw (cp, mhnswit);
return;
case UNKWNSW:
fprintf (stderr, "-%s unknown\n", cp);
return;
case MHNHELPSW:
snprintf (buf, sizeof(buf), "%s [msgs] [switches]", cmd_name);
print_help (buf, mhnswit, 1);
return;
case MHNAUTOSW:
case MHNNAUTOSW:
case MHNDEBUGSW:
case MHNEBCDICSW:
case MHNNEBCDICSW:
case MHNHEADSW:
case MHNNHEADSW:
case MHNLISTSW:
case MHNNLISTSW:
case MHNSIZESW:
case MHNNSIZESW:
case MHNRFC934SW:
case MHNNRFC934SW:
case MHNSERIALSW:
case MHNNSERIALSW:
case MHNSHOWSW:
case MHNNSHOWSW:
case MHNSTORESW:
case MHNNSTORESW:
case MHNVERBSW:
case MHNNVERBSW:
case MHNNPROGSW:
vec[vecp++] = --cp;
continue;
case MHNFORMSW:
case MHNPARTSW:
case MHNTYPESW:
case MHNPROGSW:
case MHNLENSW:
case MHNWIDSW:
vec[vecp++] = --cp;
if (!(cp = *args++) || *cp == '-') {
advise (NULL, "missing argument to %s", args[-2]);
return;
}
vec[vecp++] = cp;
continue;
}
}
if (*cp == '+' || *cp == '@') {
advise (NULL, "sorry, no folders allowed!");
return;
} else {
msgs[msgp++] = cp;
}
}
vec[0] = cmd_name;
vec[vecp++] = "-file";
vec[vecp] = NULL;
if (!msgp)
msgs[msgp++] = "cur";
for (msgnum = 0; msgnum < msgp; msgnum++)
if (!m_convert (mp, msgs[msgnum]))
return;
seq_setprev (mp);
interrupted = 0;
for (msgnum = mp->lowsel;
msgnum <= mp->hghsel && !interrupted;
msgnum++)
if (is_selected (mp, msgnum))
if (process (msgnum, cmd_name, vecp, vec)) {
unset_selected (mp, msgnum);
mp->numsel--;
}
seq_setcur (mp, mp->hghsel);
}
static struct swit packswit[] = {
#define PAFISW 0
{ "file name", 0 },
#define PAHELP 1
{ "help", 0 },
{ NULL, 0 }
};
static int mbx_style = MMDF_FORMAT;
void
packcmd (char **args)
{
int msgp = 0, md, msgnum;
char *cp, *file = NULL;
char buf[BUFSIZ], *msgs[MAXARGS];
struct stat st;
if (fmsh) {
forkcmd (args, cmd_name);
return;
}
while ((cp = *args++)) {
if (*cp == '-')
switch (smatch (++cp, packswit)) {
case AMBIGSW:
ambigsw (cp, packswit);
return;
case UNKWNSW:
fprintf (stderr, "-%s unknown\n", cp);
return;
case PAHELP:
snprintf (buf, sizeof(buf), "%s [msgs] [switches]", cmd_name);
print_help (buf, packswit, 1);
return;
case PAFISW:
if (!(file = *args++) || *file == '-') {
advise (NULL, "missing argument to %s", args[-2]);
return;
}
continue;
}
if (*cp == '+' || *cp == '@') {
advise (NULL, "sorry, no folders allowed!");
return;
}
else
msgs[msgp++] = cp;
}
if (!file)
file = "./msgbox";
file = path (file, TFILE);
if (stat (file, &st) == NOTOK) {
if (errno != ENOENT) {
advise (file, "error on file");
goto done_pack;
}
md = getanswer (cp = concat ("Create file \"", file, "\"? ", NULL));
free (cp);
if (!md)
goto done_pack;
}
if (!msgp)
msgs[msgp++] = "all";
for (msgnum = 0; msgnum < msgp; msgnum++)
if (!m_convert (mp, msgs[msgnum]))
goto done_pack;
seq_setprev (mp);
if ((md = mbx_open (file, mbx_style, getuid (), getgid (), m_gmprot ())) == NOTOK) {
advise (file, "unable to open");
goto done_pack;
}
for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++)
if (is_selected (mp, msgnum))
if (pack (file, md, msgnum) == NOTOK)
break;
mbx_close (file, md);
if (mp->hghsel != mp->curmsg)
seq_setcur (mp, mp->lowsel);
done_pack: ;
free (file);
}
int
pack (char *mailbox, int md, int msgnum)
{
register FILE *zp;
if (Msgs[msgnum].m_bboard_id == 0)
readid (msgnum);
zp = msh_ready (msgnum, 1);
return mbx_write (mailbox, md, zp, Msgs[msgnum].m_bboard_id,
0L, ftell (zp), Msgs[msgnum].m_stop, 1, 1);
}
int
packhak (char **args)
{
int result;
char *cp, *file = NULL;
while ((cp = *args++)) {
if (*cp == '-')
switch (smatch (++cp, packswit)) {
case AMBIGSW:
case UNKWNSW:
case PAHELP:
return NOTOK;
case PAFISW:
if (!(file = *args++) || *file == '-')
return NOTOK;
continue;
}
if (*cp == '+' || *cp == '@')
return NOTOK;
}
file = path (file ? file : "./msgbox", TFILE);
result = access (file, F_OK) == NOTOK ? OK : NOTOK;
free (file);
return result;
}
static struct swit pickswit[] = {
#define PIANSW 0
{ "and", 0 },
#define PIORSW 1
{ "or", 0 },
#define PINTSW 2
{ "not", 0 },
#define PILBSW 3
{ "lbrace", 0 },
#define PIRBSW 4
{ "rbrace", 0 },
#define PICCSW 5
{ "cc pattern", 0 },
#define PIDASW 6
{ "date pattern", 0 },
#define PIFRSW 7
{ "from pattern", 0 },
#define PISESW 8
{ "search pattern", 0 },
#define PISUSW 9
{ "subject pattern", 0 },
#define PITOSW 10
{ "to pattern", 0 },
#define PIOTSW 11
{ "-othercomponent pattern", 15 },
#define PIAFSW 12
{ "after date", 0 },
#define PIBFSW 13
{ "before date", 0 },
#define PIDFSW 14
{ "datefield field", 5 },
#define PISQSW 15
{ "sequence name", 0 },
#define PIPUSW 16
{ "public", 0 },
#define PINPUSW 17
{ "nopublic", 0 },
#define PIZRSW 18
{ "zero", 0 },
#define PINZRSW 19
{ "nozero", 0 },
#define PILISW 20
{ "list", 0 },
#define PINLISW 21
{ "nolist", 0 },
#define PIHELP 22
{ "help", 0 },
{ NULL, 0 }
};
void
pickcmd (char **args)
{
int zerosw = 1, msgp = 0, seqp = 0;
int vecp = 0, hi, lo, msgnum;
char *cp, buf[BUFSIZ], *msgs[MAXARGS];
char *seqs[NUMATTRS], *vec[MAXARGS];
register FILE *zp;
while ((cp = *args++)) {
if (*cp == '-') {
if (*++cp == '-') {
vec[vecp++] = --cp;
goto pattern;
}
switch (smatch (cp, pickswit)) {
case AMBIGSW:
ambigsw (cp, pickswit);
return;
case UNKWNSW:
fprintf (stderr, "-%s unknown\n", cp);
return;
case PIHELP:
snprintf (buf, sizeof(buf), "%s [msgs] [switches]", cmd_name);
print_help (buf, pickswit, 1);
return;
case PICCSW:
case PIDASW:
case PIFRSW:
case PISUSW:
case PITOSW:
case PIDFSW:
case PIAFSW:
case PIBFSW:
case PISESW:
vec[vecp++] = --cp;
pattern: ;
if (!(cp = *args++)) {/* allow -xyz arguments */
advise (NULL, "missing argument to %s", args[-2]);
return;
}
vec[vecp++] = cp;
continue;
case PIOTSW:
advise (NULL, "internal error!");
return;
case PIANSW:
case PIORSW:
case PINTSW:
case PILBSW:
case PIRBSW:
vec[vecp++] = --cp;
continue;
case PISQSW:
if (!(cp = *args++) || *cp == '-') {
advise (NULL, "missing argument to %s", args[-2]);
return;
}
if (seqp < NUMATTRS)
seqs[seqp++] = cp;
else {
advise (NULL, "only %d sequences allowed!", NUMATTRS);
return;
}
continue;
case PIZRSW:
zerosw++;
continue;
case PINZRSW:
zerosw = 0;
continue;
case PIPUSW: /* not implemented */
case PINPUSW:
case PILISW:
case PINLISW:
continue;
}
}
if (*cp == '+' || *cp == '@') {
advise (NULL, "sorry, no folders allowed!");
return;
}
else
msgs[msgp++] = cp;
}
vec[vecp] = NULL;
if (!msgp)
msgs[msgp++] = "all";
for (msgnum = 0; msgnum < msgp; msgnum++)
if (!m_convert (mp, msgs[msgnum]))
return;
seq_setprev (mp);
interrupted = 0;
if (!pcompile (vec, NULL))
return;
lo = mp->lowsel;
hi = mp->hghsel;
for (msgnum = mp->lowsel;
msgnum <= mp->hghsel && !interrupted;
msgnum++)
if (is_selected (mp, msgnum)) {
zp = msh_ready (msgnum, 1);
if (pmatches (zp, msgnum, fmsh ? 0L : Msgs[msgnum].m_start,
fmsh ? 0L : Msgs[msgnum].m_stop)) {
if (msgnum < lo)
lo = msgnum;
if (msgnum > hi)
hi = msgnum;
}
else {
unset_selected (mp, msgnum);
mp->numsel--;
}
}
if (interrupted)
return;
mp->lowsel = lo;
mp->hghsel = hi;
if (mp->numsel <= 0) {
advise (NULL, "no messages match specification");
return;
}
seqs[seqp] = NULL;
for (seqp = 0; seqs[seqp]; seqp++)
if (!seq_addsel (mp, seqs[seqp], 0, zerosw))
return;
printf ("%d hit%s\n", mp->numsel, mp->numsel == 1 ? "" : "s");
}
static struct swit replswit[] = {
#define REANSW 0
{ "annotate", 0 },
#define RENANSW 1
{ "noannotate", 0 },
#define RECCSW 2
{ "cc type", 0 },
#define RENCCSW 3
{ "nocc type", 0 },
#define REDFSW 4
{ "draftfolder +folder", 0 },
#define REDMSW 5
{ "draftmessage msg", 0 },
#define RENDFSW 6
{ "nodraftfolder", 0 },
#define REEDTSW 7
{ "editor editor", 0 },
#define RENEDSW 8
{ "noedit", 0 },
#define REFCCSW 9
{ "fcc +folder", 0 },
#define REFLTSW 10
{ "filter filterfile", 0 },
#define REFRMSW 11
{ "form formfile", 0 },
#define REINSW 12
{ "inplace", 0 },
#define RENINSW 13
{ "noinplace", 0 },
#define REQUSW 14
{ "query", 0 },
#define RENQUSW 15
{ "noquery", 0 },
#define REWHTSW 16
{ "whatnowproc program", 0 },
#define RENWTSW 17
{ "nowhatnow", 0 },
#define REWIDSW 19
{ "width columns", 0 },
#define REHELP 20
{ "help", 0 },
{ NULL, 0 }
};
void
replcmd (char **args)
{
int vecp = 1;
char *cp, *msg = NULL;
char buf[BUFSIZ], *vec[MAXARGS];
if (fmsh) {
forkcmd (args, cmd_name);
return;
}
while ((cp = *args++)) {
if (*cp == '-')
switch (smatch (++cp, replswit)) {
case AMBIGSW:
ambigsw (cp, replswit);
return;
case UNKWNSW:
fprintf (stderr, "-%s unknown\n", cp);
return;
case REHELP:
snprintf (buf, sizeof(buf), "%s [msgs] [switches]", cmd_name);
print_help (buf, replswit, 1);
return;
case REANSW: /* not implemented */
case RENANSW:
case REINSW:
case RENINSW:
continue;
case REQUSW:
case RENQUSW:
case RENDFSW:
case RENEDSW:
case RENWTSW:
vec[vecp++] = --cp;
continue;
case RECCSW:
case RENCCSW:
case REEDTSW:
case REFCCSW:
case REFLTSW:
case REFRMSW:
case REWIDSW:
case REDFSW:
case REDMSW:
case REWHTSW:
vec[vecp++] = --cp;
if (!(cp = *args++) || *cp == '-') {
advise (NULL, "missing argument to %s", args[-2]);
return;
}
vec[vecp++] = cp;
continue;
}
if (*cp == '+' || *cp == '@') {
advise (NULL, "sorry, no folders allowed!");
return;
}
else
if (msg) {
advise (NULL, "only one message at a time!");
return;
}
else
msg = cp;
}
vec[0] = cmd_name;
vec[vecp++] = "-file";
vec[vecp] = NULL;
if (!msg)
msg = "cur";
if (!m_convert (mp, msg))
return;
seq_setprev (mp);
if (mp->numsel > 1) {
advise (NULL, "only one message at a time!");
return;
}
process (mp->hghsel, cmd_name, vecp, vec);
seq_setcur (mp, mp->hghsel);
}
static struct swit rmmswit[] = {
#define RMHELP 0
{ "help", 0 },
{ NULL, 0 }
};
void
rmmcmd (char **args)
{
int msgp = 0, msgnum;
char *cp, buf[BUFSIZ], *msgs[MAXARGS];
while ((cp = *args++)) {
if (*cp == '-')
switch (smatch (++cp, rmmswit)) {
case AMBIGSW:
ambigsw (cp, rmmswit);
return;
case UNKWNSW:
fprintf (stderr, "-%s unknown\n", cp);
return;
case RMHELP:
snprintf (buf, sizeof(buf), "%s [msgs] [switches]", cmd_name);
print_help (buf, rmmswit, 1);
return;
}
if (*cp == '+' || *cp == '@') {
advise (NULL, "sorry, no folders allowed!");
return;
}
else
msgs[msgp++] = cp;
}
if (!msgp)
msgs[msgp++] = "cur";
for (msgnum = 0; msgnum < msgp; msgnum++)
if (!m_convert (mp, msgs[msgnum]))
return;
seq_setprev (mp);
rmm ();
}
static void
rmm (void)
{
register int msgnum, vecp;
register char *cp;
char buffer[BUFSIZ], *vec[MAXARGS];
if (fmsh) {
if (rmmproc) {
if (mp->numsel > MAXARGS - 1) {
advise (NULL, "more than %d messages for %s exec",
MAXARGS - 1, rmmproc);
return;
}
vecp = 0;
for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++)
if (is_selected (mp, msgnum))
vec[vecp++] = getcpy (m_name (msgnum));
vec[vecp] = NULL;
forkcmd (vec, rmmproc);
for (vecp = 0; vec[vecp]; vecp++)
free (vec[vecp]);
}
else
for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++)
if (is_selected (mp, msgnum)) {
strncpy (buffer, m_backup (cp = m_name (msgnum)), sizeof(buffer));
if (rename (cp, buffer) == NOTOK)
admonish (buffer, "unable to rename %s to", cp);
}
}
for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++)
if (is_selected (mp, msgnum)) {
set_deleted (mp, msgnum);
unset_exists (mp, msgnum);
#ifdef MPOP
#ifdef BPOP
if (pmsh && pop_dele (msgnum) != OK)
fprintf (stderr, "%s", response);
#endif
#endif /* MPOP */
}
if ((mp->nummsg -= mp->numsel) <= 0) {
if (fmsh)
admonish (NULL, "no messages remaining in +%s", fmsh);
else
admonish (NULL, "no messages remaining in %s", mp->foldpath);
mp->lowmsg = mp->hghmsg = mp->nummsg = 0;
}
if (mp->lowsel == mp->lowmsg) {
for (msgnum = mp->lowmsg + 1; msgnum <= mp->hghmsg; msgnum++)
if (does_exist (mp, msgnum))
break;
mp->lowmsg = msgnum;
}
if (mp->hghsel == mp->hghmsg) {
for (msgnum = mp->hghmsg - 1; msgnum >= mp->lowmsg; msgnum--)
if (does_exist (mp, msgnum))
break;
mp->hghmsg = msgnum;
}
mp->msgflags |= MODIFIED;
modified++;
}
static struct swit scanswit[] = {
#define SCCLR 0
{ "clear", 0 },
#define SCNCLR 1
{ "noclear", 0 },
#define SCFORM 2
{ "form formatfile", 0 },
#define SCFMT 3
{ "format string", 5 },
#define SCHEAD 4
{ "header", 0 },
#define SCNHEAD 5
{ "noheader", 0 },
#define SCWID 6
{ "width columns", 0 },
#define SCHELP 7
{ "help", 0 },
{ NULL, 0 }
};
void
scancmd (char **args)
{
#define equiv(a,b) (a ? b && !strcmp (a, b) : !b)
int clearsw = 0, headersw = 0, width = 0, msgp = 0;
int msgnum, optim, state;
char *cp, *form = NULL, *format = NULL;
char buf[BUFSIZ], *nfs, *msgs[MAXARGS];
register FILE *zp;
#ifdef MPOP
#ifdef BPOP
static int p_optim = 0;
#endif
#endif /* MPOP */
static int s_optim = 0;
static char *s_form = NULL, *s_format = NULL;
while ((cp = *args++)) {
if (*cp == '-')
switch (smatch (++cp, scanswit)) {
case AMBIGSW:
ambigsw (cp, scanswit);
return;
case UNKWNSW:
fprintf (stderr, "-%s unknown\n", cp);
return;
case SCHELP:
snprintf (buf, sizeof(buf), "%s [msgs] [switches]", cmd_name);
print_help (buf, scanswit, 1);
return;
case SCCLR:
clearsw++;
continue;
case SCNCLR:
clearsw = 0;
continue;
case SCHEAD:
headersw++;
continue;
case SCNHEAD:
headersw = 0;
continue;
case SCFORM:
if (!(form = *args++) || *form == '-') {
advise (NULL, "missing argument to %s", args[-2]);
return;
}
format = NULL;
continue;
case SCFMT:
if (!(format = *args++) || *format == '-') {
advise (NULL, "missing argument to %s", args[-2]);
return;
}
form = NULL;
continue;
case SCWID:
if (!(cp = *args++) || *cp == '-') {
advise (NULL, "missing argument to %s", args[-2]);
return;
}
width = atoi (cp);
continue;
}
if (*cp == '+' || *cp == '@') {
advise (NULL, "sorry, no folders allowed!");
return;
}
else
msgs[msgp++] = cp;
}
if (!msgp)
msgs[msgp++] = "all";
for (msgnum = 0; msgnum < msgp; msgnum++)
if (!m_convert (mp, msgs[msgnum]))
return;
seq_setprev (mp);
/* Get new format string */
nfs = new_fs (form, format, FORMAT);
/* force scansbr to (re)compile format */
if (scanl) {
free (scanl);
scanl = NULL;
}
if (s_optim == 0) {
s_optim = optim = 1;
s_form = form ? getcpy (form) : NULL;
s_format = format ? getcpy (format) : NULL;
#ifdef MPOP
#ifdef BPOP
if (pmsh) {
int i;
char *dp, *ep, *fp;
if (width == 0)
width = sc_width ();
for (dp = nfs, i = 0; *dp; dp++, i++)
if (*dp == '\\' || *dp == '"' || *dp == '\n')
i++;
i++;
if ((ep = malloc ((unsigned) i)) == NULL)
adios (NULL, "out of memory");
for (dp = nfs, fp = ep; *dp; dp++) {
if (*dp == '\n') {
*fp++ = '\\', *fp++ = 'n';
continue;
}
if (*dp == '"' || *dp == '\\')
*fp++ = '\\';
*fp++ = *dp;
}
*fp = NULL;
if (pop_command ("XTND SCAN %d \"%s\"", width, ep) == OK)
p_optim = 1;
free (ep);
}
#endif
#endif /* MPOP */
}
else
optim = equiv (s_form, form) && equiv (s_format, format);
#ifdef MPOP
#ifdef BPOP
if (p_optim && optim) {
for (msgnum = mp->lowmsg; msgnum <= mp->hghmsg; msgnum++)
if (!is_selected(mp, msgnum) || Msgs[msgnum].m_scanl)
break;
if (msgnum > mp->hghmsg && pop_command ("LIST") == OK) {
fprintf (stderr, "Stand-by...");
fflush (stderr);
for (;;) {
int size;
switch (pop_multiline ()) {
case NOTOK:
fprintf (stderr, "%s", response);
/* and fall... */
case DONE:
fprintf (stderr,"\n");
break;
case OK:
if (sscanf (response, "%d %d", &msgnum, &size) == 2
&& mp->lowmsg <= msgnum
&& msgnum <= mp->hghmsg
&& (cp = strchr(response, '#'))
&& *++cp)
Msgs[msgnum].m_scanl = concat (cp, "\n", NULL);
continue;
}
break;
}
}
}
#endif
#endif /* MPOP */
interrupted = 0;
for (msgnum = mp->lowsel;
msgnum <= mp->hghsel && !interrupted;
msgnum++)
if (is_selected (mp, msgnum)) {
if (optim && Msgs[msgnum].m_scanl)
printf ("%s", Msgs[msgnum].m_scanl);
else {
#ifdef MPOP
#ifdef BPOP
if (p_optim
&& optim
&& is_virtual (mp, msgnum)
&& pop_command ("LIST %d", msgnum) == OK
&& (cp = strchr(response, '#'))
&& *++cp) {
Msgs[msgnum].m_scanl = concat (cp, "\n", NULL);
printf ("%s", Msgs[msgnum].m_scanl);
continue;
}
#endif
#endif /* MPOP */
zp = msh_ready (msgnum, 0);
switch (state = scan (zp, msgnum, 0, nfs, width,
msgnum == mp->curmsg,
is_unseen (mp, msgnum),
headersw ? (fmsh ? fmsh : mp->foldpath) : NULL,
fmsh ? 0L : (long) (Msgs[msgnum].m_stop - Msgs[msgnum].m_start),
1)) {
case SCNMSG:
case SCNENC:
case SCNERR:
if (optim)
Msgs[msgnum].m_scanl = getcpy (scanl);
break;
default:
advise (NULL, "scan() botch (%d)", state);
return;
case SCNEOF:
printf ("%*d empty\n", DMAXFOLDER, msgnum);
break;
}
}
headersw = 0;
}
if (clearsw)
clear_screen ();
}
static struct swit showswit[] = {
#define SHDRAFT 0
{ "draft", 5 },
#define SHFORM 1
{ "form formfile", 4 },
#define SHPROG 2
{ "moreproc program", 4 },
#define SHNPROG 3
{ "nomoreproc", 3 },
#define SHLEN 4
{ "length lines", 4 },
#define SHWID 5
{ "width columns", 4 },
#define SHSHOW 6
{ "showproc program", 4 },
#define SHNSHOW 7
{ "noshowproc", 3 },
#define SHHEAD 8
{ "header", 4 },
#define SHNHEAD 9
{ "noheader", 3 },
#define SHHELP 10
{ "help", 0 },
{ NULL, 0 }
};
void
showcmd (char **args)
{
int headersw = 1, nshow = 0, msgp = 0, vecp = 1;
int mhl = 0, seqnum = -1, mode = 0, i, msgnum;
char *cp, *proc = showproc, buf[BUFSIZ];
char *msgs[MAXARGS], *vec[MAXARGS];
if (!strcasecmp (cmd_name, "next"))
mode = 1;
else
if (!strcasecmp (cmd_name, "prev"))
mode = -1;
while ((cp = *args++)) {
if (*cp == '-')
switch (i = smatch (++cp, showswit)) {
case AMBIGSW:
ambigsw (cp, showswit);
return;
case UNKWNSW:
case SHNPROG:
vec[vecp++] = --cp;
continue;
case SHHELP:
snprintf (buf, sizeof(buf), "%s %s[switches] [switches for showproc]",
cmd_name, mode ? NULL : "[msgs] ");
print_help (buf, showswit, 1);
return;
case SHFORM:
case SHPROG:
case SHLEN:
case SHWID:
vec[vecp++] = --cp;
if (!(cp = *args++) || *cp == '-') {
advise (NULL, "missing argument to %s", args[-2]);
return;
}
vec[vecp++] = cp;
continue;
case SHHEAD:
headersw++;
continue;
case SHNHEAD:
headersw = 0;
continue;
case SHSHOW:
if (!(proc = *args++) || *proc == '-') {
advise (NULL, "missing argument to %s", args[-2]);
return;
}
nshow = 0;
continue;
case SHNSHOW:
nshow++;
continue;
case SHDRAFT:
advise (NULL, "sorry, -%s not allowed!", showswit[i].sw);
return;
}
if (*cp == '+' || *cp == '@') {
advise (NULL, "sorry, no folders allowed!");
return;
}
else
if (mode) {
fprintf (stderr,
"usage: %s [switches] [switches for showproc]\n",
cmd_name);
return;
}
else
msgs[msgp++] = cp;
}
vec[vecp] = NULL;
if (!msgp)
msgs[msgp++] = mode > 0 ? "next" : mode < 0 ? "prev" : "cur";
for (msgnum = 0; msgnum < msgp; msgnum++)
if (!m_convert (mp, msgs[msgnum]))
return;
seq_setprev (mp);
if (!nshow && !getenv ("NOMHNPROC"))
for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++)
if (is_selected (mp, msgnum) && is_nontext (msgnum)) {
proc = showmimeproc;
vec[vecp++] = "-file";
vec[vecp] = NULL;
goto finish;
}
if (nshow)
proc = catproc;
else
if (strcmp (showproc, "mhl") == 0) {
proc = mhlproc;
mhl++;
}
finish: ;
seqnum = seq_getnum (mp, "unseen");
vec[0] = r1bindex (proc, '/');
if (mhl) {
msgp = vecp;
for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++)
if (is_selected (mp, msgnum)) {
vec[vecp++] = getcpy (m_name (msgnum));
if (seqnum != -1)
seq_delmsg (mp, "unseen", msgnum);
}
vec[vecp] = NULL;
if (mp->numsel == 1 && headersw)
show (mp->lowsel);
mhlsbr (vecp, vec, mhl_action);
m_eomsbr ((int (*)()) 0);
while (msgp < vecp)
free (vec[msgp++]);
} else {
interrupted = 0;
for (msgnum = mp->lowsel;
msgnum <= mp->hghsel && !interrupted;
msgnum++)
if (is_selected (mp, msgnum)) {
switch (ask (msgnum)) {
case NOTOK: /* QUIT */
break;
case OK: /* INTR */
continue;
default:
if (mp->numsel == 1 && headersw)
show (msgnum);
if (nshow)
copy_message (msgnum, stdout);
else
process (msgnum, proc, vecp, vec);
if (seqnum != -1)
seq_delmsg (mp, "unseen", msgnum);
continue;
}
break;
}
}
seq_setcur (mp, mp->hghsel);
}
static void
show (int msgnum)
{
if (Msgs[msgnum].m_bboard_id == 0)
readid (msgnum);
printf ("(Message %d", msgnum);
if (Msgs[msgnum].m_bboard_id > 0)
printf (", %s: %d", BBoard_ID, Msgs[msgnum].m_bboard_id);
printf (")\n");
}
static int
eom_action (int c)
{
return (ftell (mhlfp) >= Msgs[mhlnum].m_stop);
}
static FILE *
mhl_action (char *name)
{
int msgnum;
if ((msgnum = m_atoi (name)) < mp->lowmsg
|| msgnum > mp->hghmsg
|| !does_exist (mp, msgnum))
return NULL;
mhlnum = msgnum;
mhlfp = msh_ready (msgnum, 1);
if (!fmsh)
m_eomsbr (eom_action);
return mhlfp;
}
static int
ask (int msgnum)
{
char buf[BUFSIZ];
if (mp->numsel == 1 || !interactive || redirected)
return DONE;
if (SOprintf ("Press <return> to list \"%d\"...", msgnum)) {
if (mp->lowsel != msgnum)
printf ("\n\n\n");
printf ("Press <return> to list \"%d\"...", msgnum);
}
fflush (stdout);
buf[0] = 0;
#ifndef BSD42
read (fileno (stdout), buf, sizeof buf);
#else /* BSD42 */
switch (setjmp (sigenv)) {
case OK:
should_intr = 1;
read (fileno (stdout), buf, sizeof buf);/* fall... */
default:
should_intr = 0;
break;
}
#endif /* BSD42 */
if (strchr(buf, '\n') == NULL)
putchar ('\n');
if (told_to_quit) {
told_to_quit = interrupted = 0;
return NOTOK;
}
if (interrupted) {
interrupted = 0;
return OK;
}
return DONE;
}
#include <h/mime.h>
static int
is_nontext (int msgnum)
{
int result, state;
char *bp, *cp, *dp;
char buf[BUFSIZ], name[NAMESZ];
FILE *fp;
if (Msgs[msgnum].m_flags & MHNCHK)
return (Msgs[msgnum].m_flags & MHNYES);
Msgs[msgnum].m_flags |= MHNCHK;
fp = msh_ready (msgnum, 1);
for (state = FLD;;)
switch (state = m_getfld (state, name, buf, sizeof buf, fp)) {
case FLD:
case FLDPLUS:
case FLDEOF:
/*
* Check Content-Type field
*/
if (!strcasecmp (name, TYPE_FIELD)) {
int passno;
char c;
cp = add (buf, NULL);
while (state == FLDPLUS) {
state = m_getfld (state, name, buf, sizeof buf, fp);
cp = add (buf, cp);
}
bp = cp;
passno = 1;
again:
for (; isspace (*bp); bp++)
continue;
if (*bp == '(') {
int i;
for (bp++, i = 0;;) {
switch (*bp++) {
case '\0':
invalid:
result = 0;
goto out;
case '\\':
if (*bp++ == '\0')
goto invalid;
continue;
case '(':
i++;
/* and fall... */
default:
continue;
case ')':
if (--i < 0)
break;
continue;
}
break;
}
}
if (passno == 2) {
if (*bp != '/')
goto invalid;
bp++;
passno = 3;
goto again;
}
for (dp = bp; istoken (*dp); dp++)
continue;
c = *dp;
*dp = '\0';
if (!*bp)
goto invalid;
if (passno > 1) {
if ((result = (strcasecmp (bp, "plain") != 0)))
goto out;
*dp = c;
for (dp++; isspace (*dp); dp++)
continue;
if (*dp) {
if ((result = !uprf (dp, "charset")))
goto out;
dp += sizeof "charset" - 1;
while (isspace (*dp))
dp++;
if (*dp++ != '=')
goto invalid;
while (isspace (*dp))
dp++;
if (*dp == '"') {
if ((bp = strchr(++dp, '"')))
*bp = '\0';
} else {
for (bp = dp; *bp; bp++)
if (isspace (*bp)) {
*bp = '\0';
break;
}
}
} else {
/* Default character set */
dp = "US-ASCII";
}
/* Check the character set */
result = !check_charset (dp, strlen (dp));
} else {
if (!(result = (strcasecmp (bp, "text") != 0))) {
*dp = c;
bp = dp;
passno = 2;
goto again;
}
}
out:
free (cp);
if (result) {
Msgs[msgnum].m_flags |= MHNYES;
return result;
}
break;
}
/*
* Check Content-Transfer-Encoding field
*/
if (!strcasecmp (name, ENCODING_FIELD)) {
cp = add (buf, NULL);
while (state == FLDPLUS) {
state = m_getfld (state, name, buf, sizeof buf, fp);
cp = add (buf, cp);
}
for (bp = cp; isspace (*bp); bp++)
continue;
for (dp = bp; istoken (*dp); dp++)
continue;
*dp = '\0';
result = (strcasecmp (bp, "7bit")
&& strcasecmp (bp, "8bit")
&& strcasecmp (bp, "binary"));
free (cp);
if (result) {
Msgs[msgnum].m_flags |= MHNYES;
return result;
}
break;
}
/*
* Just skip the rest of this header
* field and go to next one.
*/
while (state == FLDPLUS)
state = m_getfld (state, name, buf, sizeof(buf), fp);
break;
/*
* We've passed the message header,
* so message is just text.
*/
default:
return 0;
}
}
static struct swit sortswit[] = {
#define SODATE 0
{ "datefield field", 0 },
#define SOSUBJ 1
{ "textfield field", 0 },
#define SONSUBJ 2
{ "notextfield", 0 },
#define SOLIMT 3
{ "limit days", 0 },
#define SONLIMT 4
{ "nolimit", 0 },
#define SOVERB 5
{ "verbose", 0 },
#define SONVERB 6
{ "noverbose", 0 },
#define SOHELP 7
{ "help", 0 },
{ NULL, 0 }
};
void
sortcmd (char **args)
{
int msgp = 0, msgnum;
char *cp, *datesw = NULL, *subjsw = NULL;
char buf[BUFSIZ], *msgs[MAXARGS];
struct tws tb;
if (fmsh) {
forkcmd (args, cmd_name);
return;
}
while ((cp = *args++)) {
if (*cp == '-')
switch (smatch (++cp, sortswit)) {
case AMBIGSW:
ambigsw (cp, sortswit);
return;
case UNKWNSW:
fprintf (stderr, "-%s unknown\n", cp);
return;
case SOHELP:
snprintf (buf, sizeof(buf), "%s [msgs] [switches]", cmd_name);
print_help (buf, sortswit, 1);
return;
case SODATE:
if (datesw) {
advise (NULL, "only one date field at a time!");
return;
}
if (!(datesw = *args++) || *datesw == '-') {
advise (NULL, "missing argument to %s", args[-2]);
return;
}
continue;
case SOSUBJ:
if (subjsw) {
advise (NULL, "only one text field at a time!");
return;
}
if (!(subjsw = *args++) || *subjsw == '-') {
advise (NULL, "missing argument to %s", args[-2]);
return;
}
continue;
case SONSUBJ:
subjsw = (char *)0;
continue;
case SOLIMT: /* too hard */
if (!(cp = *args++) || *cp == '-') {
advise (NULL, "missing argument to %s", args[-2]);
return;
}
case SONLIMT:
case SOVERB: /* not implemented */
case SONVERB:
continue;
}
if (*cp == '+' || *cp == '@') {
advise (NULL, "sorry, no folders allowed!");
return;
}
else
msgs[msgp++] = cp;
}
if (!msgp)
msgs[msgp++] = "all";
if (!datesw)
datesw = "Date";
for (msgnum = 0; msgnum < msgp; msgnum++)
if (!m_convert (mp, msgs[msgnum]))
return;
seq_setprev (mp);
twscopy (&tb, dlocaltimenow ());
for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) {
if (Msgs[msgnum].m_scanl) {
free (Msgs[msgnum].m_scanl);
Msgs[msgnum].m_scanl = NULL;
}
if (is_selected (mp, msgnum)) {
if (get_fields (datesw, subjsw, msgnum, &Msgs[msgnum]))
twscopy (&Msgs[msgnum].m_tb,
msgnum != mp->lowsel ? &Msgs[msgnum - 1].m_tb : &tb);
}
else /* m_scaln is already NULL */
twscopy (&Msgs[msgnum].m_tb, &tb);
Msgs[msgnum].m_stats = mp->msgstats[msgnum - mp->lowoff];
if (mp->curmsg == msgnum)
Msgs[msgnum].m_stats |= CUR;
}
qsort ((char *) &Msgs[mp->lowsel], mp->hghsel - mp->lowsel + 1,
sizeof(struct Msg), (qsort_comp) (subjsw ? subsort : msgsort));
for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) {
if (subjsw && Msgs[msgnum].m_scanl) {
free (Msgs[msgnum].m_scanl); /* from subjsort */
Msgs[msgnum].m_scanl = NULL;
}
mp->msgstats[msgnum - mp->lowoff] = Msgs[msgnum].m_stats & ~CUR;
if (Msgs[msgnum].m_stats & CUR)
seq_setcur (mp, msgnum);
}
mp->msgflags |= MODIFIED;
modified++;
}
/*
* get_fields - parse message, and get date and subject if needed.
* We'll use the msgp->m_tb tws struct for the date, and overload
* the msgp->m_scanl field with our subject string.
*/
static int
get_fields (char *datesw, char *subjsw, int msgnum, struct Msg *msgp)
{
int state, gotdate = 0;
char *bp, buf[BUFSIZ], name[NAMESZ];
struct tws *tw = (struct tws *) 0;
register FILE *zp;
zp = msh_ready (msgnum, 0);
for (state = FLD;;) {
switch (state = m_getfld (state, name, buf, sizeof buf, zp)) {
case FLD:
case FLDEOF:
case FLDPLUS:
if (!strcasecmp (name, datesw)) {
bp = getcpy (buf);
while (state == FLDPLUS) {
state = m_getfld (state, name, buf, sizeof buf, zp);
bp = add (buf, bp);
}
if ((tw = dparsetime (bp)) == NULL)
admonish (NULL,
"unable to parse %s field in message %d",
datesw, msgnum);
else
twscopy (&(msgp->m_tb), tw);
free (bp);
if (!subjsw) /* not using this, or already done */
break; /* all done! */
gotdate++;
}
else if (subjsw && !strcasecmp(name, subjsw)) {
bp = getcpy (buf);
while (state == FLDPLUS) {
state = m_getfld (state, name, buf, sizeof buf, zp);
bp = add (buf, bp);
}
msgp->m_scanl = sosmash(subjsw, bp);
if (gotdate)
break; /* date done so we're done */
else
subjsw = (char *)0;/* subject done, need date */
} else {
while (state == FLDPLUS) /* flush this one */
state = m_getfld (state, name, buf, sizeof buf, zp);
}
continue;
case BODY:
case BODYEOF:
case FILEEOF:
break;
case LENERR:
case FMTERR:
admonish (NULL, "format error in message %d", msgnum);
if (msgp->m_scanl) { /* this might need free'd */
free (msgp->m_scanl); /* probably can't use subj anyway */
msgp->m_scanl = NULL;
}
return NOTOK;
default:
adios (NULL, "internal error -- you lose");
}
break;
}
if (tw)
return OK; /* not an error if subj not found */
admonish (NULL, "no %s field in message %d", datesw, msgnum);
return NOTOK; /* NOTOK means use some other date */
}
/*
* sort routines
*/
static int
msgsort (struct Msg *a, struct Msg *b)
{
return twsort (&a->m_tb, &b->m_tb);
}
static int
subsort (struct Msg *a, struct Msg *b)
{
register int i;
if (a->m_scanl && b->m_scanl)
if ((i = strcmp (a->m_scanl, b->m_scanl)))
return (i);
return twsort (&a->m_tb, &b->m_tb);
}
/*
* try to make the subject "canonical": delete leading "re:", everything
* but letters & smash letters to lower case.
*/
static char *
sosmash (char *subj, char *s)
{
register char *cp, *dp, c;
if (s) {
cp = s;
dp = s; /* dst pointer */
if (!strcasecmp (subj, "subject"))
while ((c = *cp)) {
if (! isspace(c)) {
if(uprf(cp, "re:"))
cp += 2;
else {
if (isalnum(c))
*dp++ = isupper(c) ? tolower(c) : c;
break;
}
}
cp++;
}
while ((c = *cp++)) {
if (isalnum(c))
*dp++ = isupper(c) ? tolower(c) : c;
}
*dp = '\0';
}
return s;
}
static int
process (int msgnum, char *proc, int vecp, char **vec)
{
int child_id, status;
char tmpfil[80];
FILE *out;
if (fmsh) {
strncpy (tmpfil, m_name (msgnum), sizeof(tmpfil));
context_del (pfolder);
context_replace (pfolder, fmsh);/* update current folder */
seq_save (mp);
context_save (); /* save the context file */
goto ready;
}
strncpy (tmpfil, m_scratch ("", invo_name), sizeof(tmpfil));
if ((out = fopen (tmpfil, "w")) == NULL) {
int olderr;
char newfil[80];
olderr = errno;
strncpy (newfil, m_tmpfil (invo_name), sizeof(newfil));
if ((out = fopen (newfil, "w")) == NULL) {
errno = olderr;
advise (tmpfil, "unable to create temporary file");
return NOTOK;
} else {
strncpy (tmpfil, newfil, sizeof(tmpfil));
}
}
copy_message (msgnum, out);
fclose (out);
ready: ;
fflush (stdout);
switch (child_id = fork ()) {
case NOTOK:
advise ("fork", "unable to");
status = NOTOK;
break;
case OK:
closefds (3);
SIGNAL (SIGINT, istat);
SIGNAL (SIGQUIT, qstat);
vec[vecp++] = tmpfil;
vec[vecp] = NULL;
execvp (proc, vec);
fprintf (stderr, "unable to exec ");
perror (proc);
_exit (1);
default:
status = pidXwait (child_id, NULL);
break;
}
if (!fmsh)
unlink (tmpfil);
return status;
}
static void
copy_message (int msgnum, FILE *out)
{
long pos;
static char buffer[BUFSIZ];
register FILE *zp;
zp = msh_ready (msgnum, 1);
if (fmsh) {
while (fgets (buffer, sizeof buffer, zp) != NULL) {
fputs (buffer, out);
if (interrupted && out == stdout)
break;
}
}
else {
pos = ftell (zp);
while (fgets (buffer, sizeof buffer, zp) != NULL
&& pos < Msgs[msgnum].m_stop) {
fputs (buffer, out);
pos += (long) strlen (buffer);
if (interrupted && out == stdout)
break;
}
}
}
static void
copy_digest (int msgnum, FILE *out)
{
char c;
long pos;
static char buffer[BUFSIZ];
register FILE *zp;
c = '\n';
zp = msh_ready (msgnum, 1);
if (!fmsh)
pos = ftell (zp);
while (fgets (buffer, sizeof buffer, zp) != NULL
&& !fmsh && pos < Msgs[msgnum].m_stop) {
if (c == '\n' && *buffer == '-')
fputc (' ', out);
fputs (buffer, out);
c = buffer[strlen (buffer) - 1];
if (!fmsh)
pos += (long) strlen (buffer);
if (interrupted && out == stdout)
break;
}
}
syntax highlighted by Code2HTML, v. 0.9.1