[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Nmh-commits] CVS: nmh/uip Makefile.in,1.15,1.15.2.1 anno.c,1.4,1.4.2.1
From: |
Jon Steinhart <address@hidden> |
Subject: |
[Nmh-commits] CVS: nmh/uip Makefile.in,1.15,1.15.2.1 anno.c,1.4,1.4.2.1 annosbr.c,1.3,1.3.2.1 burst.c,1.4,1.4.2.1 flist.c,1.4,1.4.2.1 folder.c,1.4,1.4.2.1 inc.c,1.13,1.13.2.1 install-mh.c,1.4,1.4.2.1 mhstoresbr.c,1.7,1.7.2.1 rcvstore.c,1.7,1.7.2.1 refile.c,1.4,1.4.2.1 rmf.c,1.4,1.4.2.1 rmm.c,1.4,1.4.2.1 scan.c,1.8.2.1,1.8.2.2 send.c,1.5,1.5.2.1 sendsbr.c,1.4,1.4.2.1 sortm.c,1.5,1.5.2.1 viamail.c,1.7,1.7.2.1 whatnowsbr.c,1.5,1.5.2.1 |
Date: |
Fri, 28 Feb 2003 14:08:39 -0500 |
Update of /cvsroot/nmh/nmh/uip
In directory subversions:/tmp/cvs-serv6328/nmh/uip
Modified Files:
Tag: RELEASE_1_1
Makefile.in anno.c annosbr.c burst.c flist.c folder.c inc.c
install-mh.c mhstoresbr.c rcvstore.c refile.c rmf.c rmm.c
scan.c send.c sendsbr.c sortm.c viamail.c whatnowsbr.c
Log Message:
Merged in changes from main branch. There are two classes of changes:
improved attachment handing for originating messages, and hooks that
provide an interface that allows external programs to to synchronize
a database with the contents of mail folders.
Index: Makefile.in
===================================================================
RCS file: /cvsroot/nmh/nmh/uip/Makefile.in,v
retrieving revision 1.15
retrieving revision 1.15.2.1
diff -C2 -r1.15 -r1.15.2.1
*** Makefile.in 9 Jan 2001 06:40:12 -0000 1.15
--- Makefile.in 28 Feb 2003 19:08:36 -0000 1.15.2.1
***************
*** 58,62 ****
# commands to build
! CMDS = ali anno burst comp dist flist folder forw mark mhbuild \
mhlist mhmail mhn mhparam mhpath mhshow mhstore msgchk \
msh packf pick prompter refile repl rmf rmm scan send show \
--- 58,62 ----
# commands to build
! CMDS = ali anno burst comp dist flist folder forw install-mh mark mhbuild \
mhlist mhmail mhn mhparam mhpath mhshow mhstore msgchk \
msh packf pick prompter refile repl rmf rmm scan send show \
***************
*** 70,74 ****
# misc support binaries
! MISC = ap conflict dp fmtdump install-mh mhl post rcvdist rcvpack \
rcvstore rcvtty slocal spost viamail mhtest
--- 70,74 ----
# misc support binaries
! MISC = ap conflict dp fmtdump mhl post rcvdist rcvpack \
rcvstore rcvtty slocal spost viamail mhtest
***************
*** 252,256 ****
# install everything
! install: install-cmds install-lcmds install-misc install-scmds
# install commands
--- 252,256 ----
# install everything
! install: install-cmds install-misc install-lcmds install-scmds
# install commands
***************
*** 271,274 ****
--- 271,275 ----
$(LN) $(bindir)/show $(bindir)/prev
$(LN) $(bindir)/show $(bindir)/next
+ $(LN) $(bindir)/install-mh $(libdir)/install-mh
# install misc support binaries
Index: anno.c
===================================================================
RCS file: /cvsroot/nmh/nmh/uip/anno.c,v
retrieving revision 1.4
retrieving revision 1.4.2.1
diff -C2 -r1.4 -r1.4.2.1
*** anno.c 2 Jul 2002 22:09:14 -0000 1.4
--- anno.c 28 Feb 2003 19:08:36 -0000 1.4.2.1
***************
*** 8,11 ****
--- 8,47 ----
* COPYRIGHT file in the root directory of the nmh distribution for
* complete copyright information.
+ *
+ * Four new options have been added: delete, list, number, and draft.
+ * Message header fields are used by the new MIME attachment code in
+ * the send command. Adding features to generalize the anno command
+ * seemed to be a better approach than the creation of a new command
+ * whose features would overlap with those of the anno command.
+ *
+ * The -draft option causes anno to operate on the current draft file
+ * instead of on a message sequence.
+ *
+ * The -delete option deletes header elements that match the -component
+ * field name. If -delete is used without the -text option, the first
+ * header field whose field name matches the component name is deleted.
+ * If the -delete is used with the -text option, and the -text argument
+ * begins with a /, the first header field whose field name matches the
+ * component name and whose field body matches the text is deleted. If
+ * the -text argument does not begin with a /, then the text is assumed
+ * to be the last component of a path name, and the first header field
+ * whose field name matches the component name and a field body whose
+ * last path name component matches the text is deleted. If the -delete
+ * option is used with the new -number option described below, the nth
+ * header field whose field name matches the component name is deleted.
+ * No header fields are deleted if none of the above conditions are met.
+ *
+ * The -list option outputs the field bodies from each header field whose
+ * field name matches the component name, one per line. If no -text
+ * option is specified, only the last path name component of each field
+ * body is output. The entire field body is output if the -text option
+ * is used; the contents of the -text argument are ignored. If the -list
+ * option is used in conjuction with the new -number option described
+ * below, each line is numbered starting with 1. A tab separates the
+ * number from the field body.
+ *
+ * The -number option works with both the -delete and -list options as
+ * described above. The -number option takes an optional argument. A
+ * value of 1 is assumed if this argument is absent.
*/
***************
*** 36,39 ****
--- 72,85 ----
#define HELPSW 7
{ "help", 0 },
+ #define DRFTSW 8
+ { "draft", 2 },
+ #define LISTSW 9
+ { "list", 1 },
+ #define DELETESW 10
+ { "delete", 2 },
+ #define NUMBERSW 11
+ { "number", 2 },
+ #define APPENDSW 12
+ { "append", 1 },
{ NULL, 0 }
};
***************
*** 54,57 ****
--- 100,109 ----
char **argp, **arguments, **msgs;
struct msgs *mp;
+ int append = 0; /* append annotations instead
of default prepend */
+ int delete = -1; /* delete header element if set
*/
+ char *draft = (char *)0; /* draft file name */
+ int isdf = 0; /* return needed for m_draft()
*/
+ int list = 0; /* list header elements if set
*/
+ int number = 0; /* delete specific number of
like elements if set */
#ifdef LOCALE
***************
*** 78,88 ****
if (*cp == '-') {
switch (smatch (++cp, switches)) {
! case AMBIGSW:
ambigsw (cp, switches);
done (1);
! case UNKWNSW:
adios (NULL, "-%s unknown", cp);
! case HELPSW:
snprintf (buf, sizeof(buf), "%s [+folder] [msgs]
[switches]",
invo_name);
--- 130,140 ----
if (*cp == '-') {
switch (smatch (++cp, switches)) {
! case AMBIGSW:
ambigsw (cp, switches);
done (1);
! case UNKWNSW:
adios (NULL, "-%s unknown", cp);
! case HELPSW:
snprintf (buf, sizeof(buf), "%s [+folder] [msgs]
[switches]",
invo_name);
***************
*** 93,97 ****
done (1);
! case COMPSW:
if (comp)
adios (NULL, "only one component at a time!");
--- 145,149 ----
done (1);
! case COMPSW:
if (comp)
adios (NULL, "only one component at a time!");
***************
*** 100,118 ****
continue;
! case DATESW:
datesw++;
continue;
! case NDATESW:
datesw = 0;
continue;
! case INPLSW:
inplace++;
continue;
! case NINPLSW:
inplace = 0;
continue;
! case TEXTSW:
if (text)
adios (NULL, "only one body at a time!");
--- 152,170 ----
continue;
! case DATESW:
datesw++;
continue;
! case NDATESW:
datesw = 0;
continue;
! case INPLSW:
inplace++;
continue;
! case NINPLSW:
inplace = 0;
continue;
! case TEXTSW:
if (text)
adios (NULL, "only one body at a time!");
***************
*** 120,123 ****
--- 172,204 ----
adios (NULL, "missing argument to %s", argp[-2]);
continue;
+
+ case DELETESW: /* delete annotations */
+ delete = 0;
+ continue;
+
+ case DRFTSW: /* draft message specified */
+ draft = "";
+ continue;
+
+ case LISTSW: /* produce a listing */
+ list = 1;
+ continue;
+
+ case NUMBERSW: /* number listing or delete by number */
+ if (number != 0)
+ adios (NULL, "only one number at a time!");
+
+ if (argp - arguments == argc - 1 || **argp == '-')
+ number = 1;
+
+ else if (!(number = atoi(*argp++)))
+ adios (NULL, "missing argument to %s", argp[-2]);
+
+ delete = number;
+ continue;
+
+ case APPENDSW: /* append annotations instead of
default prepend */
+ append = 1;
+ continue;
}
}
***************
*** 142,145 ****
--- 223,248 ----
}
+ /*
+ * We're dealing with the draft message instead of message numbers.
+ * Get the name of the draft and deal with it just as we do with
+ * message numbers below.
+ */
+
+ if (draft != (char *)0) {
+ if (nummsgs != 0)
+ adios(NULL, "can only have message numbers or -draft.");
+
+ draft = getcpy(m_draft(folder, (char *)0, 1, &isdf));
+
+ make_comp(&comp);
+
+ if (list)
+ annolist(draft, comp, text, number);
+ else
+ annotate (draft, comp, text, inplace, datesw, delete, append);
+
+ return (done(0));
+ }
+
#ifdef UCI
if (strcmp(invo_name, "fanno") == 0) /* ugh! */
***************
*** 174,180 ****
/* annotate all the SELECTED messages */
! for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++)
! if (is_selected(mp, msgnum))
! annotate (m_name (msgnum), comp, text, inplace, datesw);
context_replace (pfolder, folder); /* update current folder */
--- 277,288 ----
/* annotate all the SELECTED messages */
! for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) {
! if (is_selected(mp, msgnum)) {
! if (list)
! annolist(m_name(msgnum), comp, text, number);
! else
! annotate (m_name (msgnum), comp, text, inplace, datesw, delete,
append);
! }
! }
context_replace (pfolder, folder); /* update current folder */
***************
*** 186,190 ****
}
-
static void
make_comp (char **ap)
--- 294,297 ----
***************
*** 215,217 ****
adios (NULL, "invalid component name %s", *ap);
}
-
--- 322,323 ----
Index: annosbr.c
===================================================================
RCS file: /cvsroot/nmh/nmh/uip/annosbr.c,v
retrieving revision 1.3
retrieving revision 1.3.2.1
diff -C2 -r1.3 -r1.3.2.1
*** annosbr.c 2 Jul 2002 22:09:14 -0000 1.3
--- annosbr.c 28 Feb 2003 19:08:36 -0000 1.3.2.1
***************
*** 20,28 ****
* static prototypes
*/
! static int annosbr (int, char *, char *, char *, int, int);
int
! annotate (char *file, char *comp, char *text, int inplace, int datesw)
{
int i, fd;
--- 20,28 ----
* static prototypes
*/
! static int annosbr (int, char *, char *, char *, int, int, int, int);
int
! annotate (char *file, char *comp, char *text, int inplace, int datesw, int
delete, int append)
{
int i, fd;
***************
*** 31,38 ****
if ((fd = lkopen (file, O_RDWR, 0)) == NOTOK) {
switch (errno) {
! case ENOENT:
break;
! default:
admonish (file, "unable to lock and open");
break;
--- 31,38 ----
if ((fd = lkopen (file, O_RDWR, 0)) == NOTOK) {
switch (errno) {
! case ENOENT:
break;
! default:
admonish (file, "unable to lock and open");
break;
***************
*** 41,52 ****
}
! i = annosbr (fd, file, comp, text, inplace, datesw);
lkclose (fd, file);
return i;
}
static int
! annosbr (int fd, char *file, char *comp, char *text, int inplace, int datesw)
{
int mode, tmpfd;
--- 41,146 ----
}
! i = annosbr (fd, file, comp, text, inplace, datesw, delete, append);
lkclose (fd, file);
return i;
}
+ /*
+ * Produce a listing of all header fields (annotations) whose field name
matches
+ * comp. Number the listing if number is set. Treate the field bodies as
path
+ * names and just output the last component unless text is non-NULL. We
don't
+ * care what text is set to.
+ */
+
+ void
+ annolist(char *file, char *comp, char *text, int number)
+ {
+ int c; /* current character */
+ int count; /* header field (annotation) counter */
+ char *cp; /* miscellaneous character pointer */
+ char *field; /* buffer for header field */
+ int field_size; /* size of field buffer */
+ FILE *fp; /* file pointer made from locked file
descriptor */
+ int length; /* length of field name */
+ int n; /* number of bytes written */
+ char *sp; /* another miscellaneous character pointer */
+
+ if ((fp = fopen(file, "r")) == (FILE *)0)
+ adios(file, "unable to open");
+
+ /*
+ * Allocate a buffer to hold the header components as they're read in.
+ * This buffer might need to be quite large, so we grow it as needed.
+ */
+
+ if ((field = (char *)malloc(field_size = 256)) == (char *)0)
+ adios(NULL, "can't allocate field buffer.");
+
+ /*
+ * Get the length of the field name since we use it often.
+ */
+
+ length = strlen(comp);
+
+ count = 0;
+
+ do {
+ /*
+ * Get a line from the input file, growing the field buffer as
needed. We do this
+ * so that we can fit an entire line in the buffer making it easy
to do a string
+ * comparison on both the field name and the field body which
might be a long path
+ * name.
+ */
+
+ for (n = 0, cp = field; (c = getc(fp)) != EOF; *cp++ = c) {
+ if (c == '\n' && (c = getc(fp)) != ' ' && c != '\t') {
+ (void)ungetc(c, fp);
+ c = '\n';
+ break;
+ }
+
+ if (++n >= field_size - 1) {
+ if ((field = (char *)realloc((void *)field, field_size += 256))
== (char *)0)
+ adios(NULL, "can't grow field buffer.");
+
+ cp = field + n - 1;
+ }
+ }
+
+ /*
+ * NUL-terminate the field..
+ */
+
+ *cp = '\0';
+
+ if (strncasecmp(field, comp, length) == 0 && field[length] == ':') {
+ for (cp = field + length + 1; *cp == ' ' || *cp == '\t'; cp++)
+ ;
+
+ if (number)
+ (void)printf("%d\t", ++count);
+
+ if (text == (char *)0 && (sp = strrchr(cp, '/')) != (char *)0)
+ cp = sp + 1;
+
+ (void)printf("%s\n", cp);
+ }
+
+ } while (*field != '\0' && *field != '-');
+
+ /*
+ * Clean up.
+ */
+
+ free(field);
+
+ (void)fclose(fp);
+
+ return;
+ }
+
static int
! annosbr (int fd, char *file, char *comp, char *text, int inplace, int datesw,
int delete, int append)
{
int mode, tmpfd;
***************
*** 54,58 ****
char buffer[BUFSIZ], tmpfil[BUFSIZ];
struct stat st;
! FILE *tmp;
mode = fstat (fd, &st) != NOTOK ? (st.st_mode & 0777) : m_gmprot ();
--- 148,159 ----
char buffer[BUFSIZ], tmpfil[BUFSIZ];
struct stat st;
! FILE *tmp;
! int c; /* current character */
! int count; /* header field (annotation) counter */
! char *field; /* buffer for header field */
! int field_size; /* size of field buffer */
! FILE *fp; /* file pointer made from locked file
descriptor */
! int length; /* length of field name */
! int n; /* number of bytes written */
mode = fstat (fd, &st) != NOTOK ? (st.st_mode & 0777) : m_gmprot ();
***************
*** 66,85 ****
chmod (tmpfil, mode);
! if (datesw)
! fprintf (tmp, "%s: %s\n", comp, dtimenow (0));
! if ((cp = text)) {
do {
! while (*cp == ' ' || *cp == '\t')
! cp++;
! sp = cp;
! while (*cp && *cp++ != '\n')
! continue;
! if (cp - sp)
! fprintf (tmp, "%s: %*.*s", comp, cp - sp, cp - sp, sp);
! } while (*cp);
! if (cp[-1] != '\n' && cp != text)
! putc ('\n', tmp);
}
fflush (tmp);
cpydata (fd, fileno (tmp), file, tmpfil);
fclose (tmp);
--- 167,364 ----
chmod (tmpfil, mode);
! /*
! * We're going to need to copy some of the message file to the temporary
! * file while examining the contents. Convert the message file
descriptor
! * to a file pointer since it's a lot easier and more efficient to
use
! * stdio for this. Also allocate a buffer to hold the header
components
! * as they're read in. This buffer is grown as needed later.
! */
!
! if (delete >= 0 || append != 0) {
! if ((fp = fdopen(fd, "r")) == (FILE *)0)
! adios(NULL, "unable to fdopen file.");
!
! if ((field = (char *)malloc(field_size = 256)) == (char *)0)
! adios(NULL, "can't allocate field buffer.");
! }
!
! /*
! * We're trying to delete a header field (annotation )if the
delete flag is
! * non-negative. A value greater than zero means that we're
deleting the
! * nth header field that matches the field (component) name. A
value of
! * zero means that we're deleting the first field in which both
the field
! * name matches the component name and the field body matches the
text.
! * The text is matched in its entirety if it begins with a slash;
otherwise
! * the text is matched against whatever portion of the field body
follows
! * the last slash. This allows matching of both absolute and
relative path
! * names. This is because this functionality was added to support
attachments.
! * It might be worth having a separate flag to indicate path name
matching to
! * make it more general.
! */
!
! if (delete >= 0) {
! /*
! * Get the length of the field name since we use it often.
! */
!
! length = strlen(comp);
!
! /*
! * Initialize the field counter. This is only used if we're deleting
by
! * number.
! */
!
! count = 0;
!
! /*
! * Copy lines from the input file to the temporary file until we
either find the one
! * that we're looking for (which we don't copy) or we reach the end of
the headers.
! * Both a blank line and a line beginning with a - terminate the
headers so that we
! * can handle both drafts and RFC-2822 format messages.
! */
!
do {
! /*
! * Get a line from the input file, growing the field buffer as
needed. We do this
! * so that we can fit an entire line in the buffer making it easy
to do a string
! * comparison on both the field name and the field body which
might be a long path
! * name.
! */
!
! for (n = 0, cp = field; (c = getc(fp)) != EOF; *cp++ = c) {
! if (c == '\n' && (c = getc(fp)) != ' ' && c != '\t') {
! (void)ungetc(c, fp);
! c = '\n';
! break;
! }
!
! if (++n >= field_size - 1) {
! if ((field = (char *)realloc((void *)field, field_size *=
2)) == (char *)0)
! adios(NULL, "can't grow field buffer.");
!
! cp = field + n - 1;
! }
! }
!
! /*
! * NUL-terminate the field..
! */
!
! *cp = '\0';
!
! /*
! * Check for a match on the field name. We delete the line by not
copying it to the
! * temporary file if
! *
! * o The delete flag is 0, meaning that we're going to delete
the first matching
! * field, and the text is NULL meaning that we don't care
about the field body.
! *
! * o The delete flag is 0, meaning that we're going to delete
the first matching
! * field, and the text begins with a / meaning that we're
looking for a full
! * path name, and the text matches the field body.
! *
! * o The delete flag is 0, meaning that we're going to delete
the first matching
! * field, the text does not begin with a / meaning that we're
looking for the
! * last path name component, and the last path name component
matches the text.
! *
! * o The delete flag is non-zero meaning that we're going to
delete the nth field
! * with a matching field name, and this is the nth matching
field name.
! */
!
! if (strncasecmp(field, comp, length) == 0 && field[length] == ':') {
! if (delete == 0) {
! if (text == (char *)0)
! break;
!
! for (cp = field + length + 1; *cp == ' ' || *cp == '\t';
cp++)
! ;
!
! if (*text == '/') {
! if (strcmp(cp, text) == 0)
! break;
! }
! else {
! if ((sp = strrchr(cp, '/')) != (char *)0)
! cp = sp + 1;
!
! if (strcmp(cp, text) == 0)
! break;
! }
! }
!
! else if (++count == delete)
! break;
! }
!
! /*
! * This line wasn't a match so copy it to the temporary file.
! */
!
! if ((n = fputs(field, tmp)) == EOF || (c == '\n' && fputc('\n',
tmp) == EOF))
! adios(NULL, "unable to write temporary file.");
!
! } while (*field != '\0' && *field != '-');
!
! /*
! * Get rid of the field buffer because we're done with it.
! */
!
! free((void *)field);
! }
!
! else {
! /*
! * Find the end of the headers before adding the annotations if we're
! * appending instead of the default prepending.
! */
!
! if (append) {
! /*
! * Copy lines from the input file to the temporary file until we
! * reach the end of the headers.
! */
!
! while ((c = getc(fp)) != EOF) {
! (void)putc(c, tmp);
!
! if (c == '\n') {
! (void)ungetc(c = getc(fp), fp);
!
! if (c == '\n' || c == '-')
! break;
! }
! }
! }
!
! if (datesw)
! fprintf (tmp, "%s: %s\n", comp, dtimenow (0));
! if ((cp = text)) {
! do {
! while (*cp == ' ' || *cp == '\t')
! cp++;
! sp = cp;
! while (*cp && *cp++ != '\n')
! continue;
! if (cp - sp)
! fprintf (tmp, "%s: %*.*s", comp, cp - sp, cp - sp, sp);
! } while (*cp);
! if (cp[-1] != '\n' && cp != text)
! putc ('\n', tmp);
! }
}
+
fflush (tmp);
+
+ /*
+ * We've been messing with the input file position. Move the
input file
+ * descriptor to the current place in the file because the stock data
+ * copying routine uses the descriptor, not the pointer.
+ */
+
+ if (append || delete >= 0) {
+ if (lseek(fd, (off_t)ftell(fp), SEEK_SET) == (off_t)-1)
+ adios(NULL, "can't seek.");
+ }
+
cpydata (fd, fileno (tmp), file, tmpfil);
fclose (tmp);
***************
*** 88,92 ****
--- 367,381 ----
if ((tmpfd = open (tmpfil, O_RDONLY)) == NOTOK)
adios (tmpfil, "unable to open for re-reading");
+
lseek (fd, (off_t) 0, SEEK_SET);
+
+ /*
+ * We're making the file shorter if we're deleting a header field
+ * so the file has to be truncated or it will contain garbage.
+ */
+
+ if (delete >= 0 && ftruncate(fd, 0) == -1)
+ adios(tmpfil, "unable to truncate.");
+
cpydata (tmpfd, fd, tmpfil, file);
close (tmpfd);
***************
*** 111,114 ****
--- 400,412 ----
}
}
+
+ /*
+ * Close the delete file so that we don't run out of file pointers
if
+ * we're doing piles of files. Note that this will make the
close() in
+ * lkclose() fail, but that failure is ignored so it's not a
problem.
+ */
+
+ if (delete >= 0)
+ (void)fclose(fp);
return 0;
Index: burst.c
===================================================================
RCS file: /cvsroot/nmh/nmh/uip/burst.c,v
retrieving revision 1.4
retrieving revision 1.4.2.1
diff -C2 -r1.4 -r1.4.2.1
*** burst.c 2 Jul 2002 22:09:14 -0000 1.4
--- burst.c 28 Feb 2003 19:08:36 -0000 1.4.2.1
***************
*** 43,47 ****
*/
static int find_delim (int, struct smsg *);
! static void burst (struct msgs **, int, struct smsg *, int, int, int);
static void cpybrst (FILE *, FILE *, char *, char *, int);
--- 43,47 ----
*/
static int find_delim (int, struct smsg *);
! static void burst (struct msgs **, int, struct smsg *, int, int, int, char *);
static void cpybrst (FILE *, FILE *, char *, char *, int);
***************
*** 157,161 ****
printf ("%d message%s exploded from digest %d\n",
numburst, numburst > 1 ? "s" : "", msgnum);
! burst (&mp, msgnum, smsgs, numburst, inplace, verbosw);
} else {
if (numburst == 0) {
--- 157,161 ----
printf ("%d message%s exploded from digest %d\n",
numburst, numburst > 1 ? "s" : "", msgnum);
! burst (&mp, msgnum, smsgs, numburst, inplace, verbosw, maildir);
} else {
if (numburst == 0) {
***************
*** 257,261 ****
static void
burst (struct msgs **mpp, int msgnum, struct smsg *smsgs, int numburst,
! int inplace, int verbosw)
{
int i, j, mode;
--- 257,261 ----
static void
burst (struct msgs **mpp, int msgnum, struct smsg *smsgs, int numburst,
! int inplace, int verbosw, char *maildir)
{
int i, j, mode;
***************
*** 297,300 ****
--- 297,303 ----
* source message, to make room for each of the messages
* contained within the digest.
+ *
+ * This is equivalent to refiling a message from the point
+ * of view of the external hooks.
*/
if (inplace) {
***************
*** 308,311 ****
--- 311,319 ----
if (rename (f2, f1) == NOTOK)
admonish (f1, "unable to rename %s to", f2);
+
+ (void)snprintf(f1, sizeof (f1), "%s/%d", maildir, i);
+ (void)snprintf(f2, sizeof (f2), "%s/%d", maildir, j);
+ ext_hook("ref-hook", f1, f2);
+
copy_msg_flags (mp, i, j);
clear_msg_flags (mp, j);
***************
*** 317,321 ****
unset_selected (mp, msgnum);
! /* new hghmsg is hghmsg + numburst */
i = inplace ? msgnum + numburst : mp->hghmsg;
for (j = numburst; j >= (inplace ? 0 : 1); i--, j--) {
--- 325,347 ----
unset_selected (mp, msgnum);
! /* new hghmsg is hghmsg + numburst
! *
! * At this point, there is an array of numburst smsgs, each element of
! * which contains the starting and stopping offsets (seeks) of the message
! * in the digest. The inplace flag is set if the original digest is
replaced
! * by a message containing the table of contents. smsgs[0] is that table
of
! * contents. Go through the message numbers in reverse order (high to
low).
! *
! * Set f1 to the name of the destination message, f2 to the name of a
scratch
! * file. Extract a message from the digest to the scratch file. Move the
! * original message to a backup file if the destination message number is
the
! * same as the number of the original message, which only happens if the
! * inplace flag is set. Then move the scratch file to the destination
message.
! *
! * Moving the original message to the backup file is equivalent to
deleting the
! * message from the point of view of the external hooks. And bursting
each
! * message is equivalent to adding a new message.
! */
!
i = inplace ? msgnum + numburst : mp->hghmsg;
for (j = numburst; j >= (inplace ? 0 : 1); i--, j--) {
***************
*** 337,343 ****
--- 363,376 ----
if (rename (f1, f3) == NOTOK)
admonish (f3, "unable to rename %s to", f1);
+
+ (void)snprintf(f3, sizeof (f3), "%s/%d", maildir, i);
+ ext_hook("del-hook", f3, (char *)0);
}
if (rename (f2, f1) == NOTOK)
admonish (f1, "unable to rename %s to", f2);
+
+ (void)snprintf(f3, sizeof (f3), "%s/%d", maildir, i);
+ ext_hook("add-hook", f3, (char *)0);
+
copy_msg_flags (mp, i, msgnum);
mp->msgflags |= SEQMOD;
Index: flist.c
===================================================================
RCS file: /cvsroot/nmh/nmh/uip/flist.c,v
retrieving revision 1.4
retrieving revision 1.4.2.1
diff -C2 -r1.4 -r1.4.2.1
*** flist.c 4 Feb 2000 20:28:23 -0000 1.4
--- flist.c 28 Feb 2003 19:08:36 -0000 1.4.2.1
***************
*** 698,705 ****
register struct node *np;
- /* sanity check - check that context has been read */
- if (defpath == NULL)
- adios (NULL, "oops, context hasn't been read yet");
-
snprintf (atrcur, sizeof(atrcur), "atr-%s-", current);
atrlen = strlen (atrcur);
--- 698,701 ----
Index: folder.c
===================================================================
RCS file: /cvsroot/nmh/nmh/uip/folder.c,v
retrieving revision 1.4
retrieving revision 1.4.2.1
diff -C2 -r1.4 -r1.4.2.1
*** folder.c 2 Jul 2002 22:09:14 -0000 1.4
--- folder.c 28 Feb 2003 19:08:36 -0000 1.4.2.1
***************
*** 819,826 ****
register struct node *np;
- /* sanity check - check that context has been read */
- if (defpath == NULL)
- adios (NULL, "oops, context hasn't been read yet");
-
snprintf (atrcur, sizeof(atrcur), "atr-%s-", current);
atrlen = strlen (atrcur);
--- 819,822 ----
Index: inc.c
===================================================================
RCS file: /cvsroot/nmh/nmh/uip/inc.c,v
retrieving revision 1.13
retrieving revision 1.13.2.1
diff -C2 -r1.13 -r1.13.2.1
*** inc.c 2 Jul 2002 22:09:14 -0000 1.13
--- inc.c 28 Feb 2003 19:08:36 -0000 1.13.2.1
***************
*** 246,249 ****
--- 246,250 ----
struct stat st, s1;
FILE *aud = NULL;
+ char b[MAXPATHLEN + 1];
#ifdef POP
***************
*** 803,807 ****
newmsg = folder_addmsg(mp, tmpfilenam);
#endif
-
/* create scanline for new message */
switch (i = scan (in, msgnum + 1, msgnum + 1, nfs, width,
--- 804,807 ----
***************
*** 827,830 ****
--- 827,837 ----
case SCNMSG:
case SCNENC:
+ /*
+ * Run the external program hook on the message.
+ */
+
+ (void)snprintf(b, sizeof (b), "%s/%d", maildir, msgnum + 1);
+ (void)ext_hook("add-hook", b, (char *)0);
+
if (aud)
fputs (scanl, aud);
Index: install-mh.c
===================================================================
RCS file: /cvsroot/nmh/nmh/uip/install-mh.c,v
retrieving revision 1.4
retrieving revision 1.4.2.1
diff -C2 -r1.4 -r1.4.2.1
*** install-mh.c 2 Jul 2002 22:09:14 -0000 1.4
--- install-mh.c 28 Feb 2003 19:08:36 -0000 1.4.2.1
***************
*** 1,3 ****
-
/*
* install-mh.c -- initialize the nmh environment of a new user
--- 1,2 ----
***************
*** 10,15 ****
*/
! #include <h/mh.h>
! #include <pwd.h>
static struct swit switches[] = {
--- 9,14 ----
*/
! #include <h/mh.h> /* mh internals */
! #include <pwd.h> /* structure for getpwuid()
results */
static struct swit switches[] = {
***************
*** 20,35 ****
#define HELPSW 2
{ "help", 0 },
{ NULL, 0 }
};
- static char *message[] = {
- "Prior to using nmh, it is necessary to have a file in your login",
- "directory (%s) named %s which contains information",
- "to direct certain nmh operations. The only item which is required",
- "is the path to use for all nmh folder operations. The suggested nmh",
- "path for you is %s/Mail...",
- NULL
- };
-
/*
* static prototypes
--- 19,27 ----
#define HELPSW 2
{ "help", 0 },
+ #define CHECKSW 3
+ { "check", 1 },
{ NULL, 0 }
};
/*
* static prototypes
***************
*** 41,46 ****
main (int argc, char **argv)
{
! int i, autof = 0;
! char *cp, *path, buf[BUFSIZ];
char *dp, **arguments, **argp;
struct node *np;
--- 33,38 ----
main (int argc, char **argv)
{
! int autof = 0;
! char *cp, *pathname, buf[BUFSIZ];
char *dp, **arguments, **argp;
struct node *np;
***************
*** 48,51 ****
--- 40,44 ----
struct stat st;
FILE *in, *out;
+ int check;
#ifdef LOCALE
***************
*** 56,59 ****
--- 49,54 ----
argp = arguments;
+ check = 0;
+
while ((dp = *argp++)) {
if (*dp == '-') {
***************
*** 76,79 ****
--- 71,78 ----
autof++;
continue;
+
+ case CHECKSW:
+ check = 1;
+ continue;
}
} else {
***************
*** 82,117 ****
}
! /* straight from context_read ... */
! if (mypath == NULL) {
! if ((mypath = getenv ("HOME"))) {
! mypath = getcpy (mypath);
! } else {
! if ((pw = getpwuid (getuid ())) == NULL
! || pw->pw_dir == NULL
! || *pw->pw_dir == 0)
! adios (NULL, "no HOME envariable");
! else
! mypath = getcpy (pw->pw_dir);
! }
! if ((cp = mypath + strlen (mypath) - 1) > mypath && *cp == '/')
! *cp = 0;
}
! defpath = concat (mypath, "/", mh_profile, NULL);
if (stat (defpath, &st) != NOTOK) {
! if (autof)
adios (NULL, "invocation error");
else
! adios (NULL,
! "You already have an nmh profile, use an editor to modify
it");
}
if (!autof && gans ("Do you want help? ", anoyes)) {
! putchar ('\n');
! for (i = 0; message[i]; i++) {
! printf (message[i], mypath, mh_profile);
! putchar ('\n');
! }
! putchar ('\n');
}
--- 81,136 ----
}
! /*
! * Find user's home directory. Try the HOME environment variable
first,
! * the home directory field in the password file if that's not
found.
! */
!
! if ((mypath = getenv("HOME")) == (char *)0) {
! if ((pw = getpwuid(getuid())) == (struct passwd *)0 || *pw->pw_dir ==
'\0')
! adios(NULL, "cannot determine your home directory");
! else
! mypath = pw->pw_dir;
}
!
! /*
! * Find the user's profile. Check for the existence of an MH
environment
! * variable first with non-empty contents. Convert any relative
path name
! * found there to an absolute one. Look for the profile in the
user's home
! * directory if the MH environment variable isn't set.
! */
!
! if ((cp = getenv("MH")) && *cp != '\0')
! defpath = path(cp, TFILE);
! else
! defpath = concat(mypath, "/", mh_profile, NULL);
!
! /*
! * Check for the existence of the profile file. It's an error if
it exists and
! * this isn't an installation check. An installation check fails
if it does not
! * exist, succeeds if it does.
! */
if (stat (defpath, &st) != NOTOK) {
! if (check)
! done(0);
!
! else if (autof)
adios (NULL, "invocation error");
else
! adios (NULL, "You already have an nmh profile, use an editor to
modify it");
! }
! else if (check) {
! done(1);
}
if (!autof && gans ("Do you want help? ", anoyes)) {
! (void)printf(
! "\n"
! "Prior to using nmh, it is necessary to have a file in your login\n"
! "directory (%s) named %s which contains information\n"
! "to direct certain nmh operations. The only item which is required\n"
! "is the path to use for all nmh folder operations. The suggested
nmh\n"
! "path for you is %s/Mail...\n"
! "\n", mypath, mh_profile, mypath);
}
***************
*** 122,126 ****
cp, "\".\nDo you want to use it for nmh? ", NULL);
if (gans (cp, anoyes))
! path = "Mail";
else
goto query;
--- 141,145 ----
cp, "\".\nDo you want to use it for nmh? ", NULL);
if (gans (cp, anoyes))
! pathname = "Mail";
else
goto query;
***************
*** 135,139 ****
mypath, "/", "Mail\"? ", NULL);
if (autof || gans (cp, anoyes))
! path = "Mail";
else {
query:
--- 154,158 ----
mypath, "/", "Mail\"? ", NULL);
if (autof || gans (cp, anoyes))
! pathname = "Mail";
else {
query:
***************
*** 141,148 ****
anoyes)) {
printf ("What is the path? %s/", mypath);
! path = geta ();
} else {
printf ("What is the whole path? /");
! path = concat ("/", geta (), NULL);
}
}
--- 160,167 ----
anoyes)) {
printf ("What is the path? %s/", mypath);
! pathname = geta ();
} else {
printf ("What is the whole path? /");
! pathname = concat ("/", geta (), NULL);
}
}
***************
*** 150,158 ****
chdir (mypath);
! if (chdir (path) == NOTOK) {
! cp = concat ("\"", path, "\" doesn't exist; Create it? ", NULL);
if (autof || gans (cp, anoyes))
! if (makedir (path) == 0)
! adios (NULL, "unable to create %s", path);
} else {
printf ("[Using existing directory]\n");
--- 169,177 ----
chdir (mypath);
! if (chdir (pathname) == NOTOK) {
! cp = concat ("\"", pathname, "\" doesn't exist; Create it? ", NULL);
if (autof || gans (cp, anoyes))
! if (makedir (pathname) == 0)
! adios (NULL, "unable to create %s", pathname);
} else {
printf ("[Using existing directory]\n");
***************
*** 166,170 ****
np = m_defs;
np->n_name = getcpy ("Path");
! np->n_field = getcpy (path);
np->n_context = 0;
np->n_next = NULL;
--- 185,189 ----
np = m_defs;
np->n_name = getcpy ("Path");
! np->n_field = getcpy (pathname);
np->n_context = 0;
np->n_next = NULL;
Index: mhstoresbr.c
===================================================================
RCS file: /cvsroot/nmh/nmh/uip/mhstoresbr.c,v
retrieving revision 1.7
retrieving revision 1.7.2.1
diff -C2 -r1.7 -r1.7.2.1
*** mhstoresbr.c 2 Jul 2002 22:09:14 -0000 1.7
--- mhstoresbr.c 28 Feb 2003 19:08:36 -0000 1.7.2.1
***************
*** 922,926 ****
if ((mp = folder_read (folder))) {
/* Link file into folder */
! msgnum = folder_addmsg (&mp, filename, 0, 0, 0);
} else {
advise (NULL, "unable to read folder %s", folder);
--- 922,926 ----
if ((mp = folder_read (folder))) {
/* Link file into folder */
! msgnum = folder_addmsg (&mp, filename, 0, 0, 0, 0);
} else {
advise (NULL, "unable to read folder %s", folder);
Index: rcvstore.c
===================================================================
RCS file: /cvsroot/nmh/nmh/uip/rcvstore.c,v
retrieving revision 1.7
retrieving revision 1.7.2.1
diff -C2 -r1.7 -r1.7.2.1
*** rcvstore.c 2 Jul 2002 22:09:15 -0000 1.7
--- rcvstore.c 28 Feb 2003 19:08:36 -0000 1.7.2.1
***************
*** 204,208 ****
* to the Unseen-Sequence's.
*/
! if ((msgnum = folder_addmsg (&mp, tmpfilenam, 0, unseensw, 0)) == -1)
done (1);
--- 204,208 ----
* to the Unseen-Sequence's.
*/
! if ((msgnum = folder_addmsg (&mp, tmpfilenam, 0, unseensw, 0, 0)) == -1)
done (1);
Index: refile.c
===================================================================
RCS file: /cvsroot/nmh/nmh/uip/refile.c,v
retrieving revision 1.4
retrieving revision 1.4.2.1
diff -C2 -r1.4 -r1.4.2.1
*** refile.c 2 Jul 2002 22:09:15 -0000 1.4
--- refile.c 28 Feb 2003 19:08:36 -0000 1.4.2.1
***************
*** 67,71 ****
static void clsfolds (struct st_fold *, int);
static void remove_files (int, char **);
! static int m_file (char *, struct st_fold *, int, int);
--- 67,71 ----
static void clsfolds (struct st_fold *, int);
static void remove_files (int, char **);
! static int m_file (char *, struct st_fold *, int, int, int);
***************
*** 214,218 ****
opnfolds (folders, foldp);
for (i = 0; i < filep; i++)
! if (m_file (files[i], folders, foldp, preserve))
done (1);
/* If -nolink, then "remove" files */
--- 214,218 ----
opnfolds (folders, foldp);
for (i = 0; i < filep; i++)
! if (m_file (files[i], folders, foldp, preserve, 0))
done (1);
/* If -nolink, then "remove" files */
***************
*** 248,256 ****
opnfolds (folders, foldp);
! /* Link all the selected messages into destination folders */
for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) {
if (is_selected (mp, msgnum)) {
cp = getcpy (m_name (msgnum));
! if (m_file (cp, folders, foldp, preserve))
done (1);
free (cp);
--- 248,261 ----
opnfolds (folders, foldp);
! /* Link all the selected messages into destination folders.
! *
! * This causes the add hook to be run for messages that are
! * linked into another folder. The refile hook is run for
! * messages that are moved to another folder.
! */
for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) {
if (is_selected (mp, msgnum)) {
cp = getcpy (m_name (msgnum));
! if (m_file (cp, folders, foldp, preserve, !linkf))
done (1);
free (cp);
***************
*** 270,276 ****
}
! /* If -nolink, then "remove" messages from source folder */
if (!linkf) {
! folder_delmsgs (mp, unlink_msgs);
}
--- 275,285 ----
}
! /* If -nolink, then "remove" messages from source folder.
! *
! * Note that folder_delmsgs does not call the delete hook
! * because the message has already been handled above.
! */
if (!linkf) {
! folder_delmsgs (mp, unlink_msgs, 1);
}
***************
*** 388,392 ****
static int
! m_file (char *msgfile, struct st_fold *folders, int nfolders, int preserve)
{
int msgnum;
--- 397,401 ----
static int
! m_file (char *msgfile, struct st_fold *folders, int nfolders, int preserve,
int refile)
{
int msgnum;
***************
*** 394,398 ****
for (fp = folders, ep = folders + nfolders; fp < ep; fp++) {
! if ((msgnum = folder_addmsg (&fp->f_mp, msgfile, 1, 0, preserve)) == -1)
return 1;
}
--- 403,407 ----
for (fp = folders, ep = folders + nfolders; fp < ep; fp++) {
! if ((msgnum = folder_addmsg (&fp->f_mp, msgfile, 1, 0, preserve,
nfolders == 1 && refile)) == -1)
return 1;
}
Index: rmf.c
===================================================================
RCS file: /cvsroot/nmh/nmh/uip/rmf.c,v
retrieving revision 1.4
retrieving revision 1.4.2.1
diff -C2 -r1.4 -r1.4.2.1
*** rmf.c 2 Jul 2002 22:09:15 -0000 1.4
--- rmf.c 28 Feb 2003 19:08:36 -0000 1.4.2.1
***************
*** 153,156 ****
--- 153,162 ----
others = 0;
+ /*
+ * Run the external delete hook program.
+ */
+
+ (void)ext_hook("del-hook", maildir, (char *)0);
+
j = strlen(BACKUP_PREFIX);
while ((dp = readdir (dd))) {
***************
*** 217,224 ****
register char *cp;
register struct node *np, *pp;
-
- /* sanity check - check that context has been read */
- if (defpath == NULL)
- adios (NULL, "oops, context hasn't been read yet");
alen = strlen ("atr-");
--- 223,226 ----
Index: rmm.c
===================================================================
RCS file: /cvsroot/nmh/nmh/uip/rmm.c,v
retrieving revision 1.4
retrieving revision 1.4.2.1
diff -C2 -r1.4 -r1.4.2.1
*** rmm.c 2 Jul 2002 22:09:15 -0000 1.4
--- rmm.c 28 Feb 2003 19:08:36 -0000 1.4.2.1
***************
*** 146,150 ****
/* "remove" the SELECTED messages */
! folder_delmsgs (mp, unlink_msgs);
seq_save (mp); /* synchronize message sequences */
--- 146,150 ----
/* "remove" the SELECTED messages */
! folder_delmsgs (mp, unlink_msgs, 0);
seq_save (mp); /* synchronize message sequences */
Index: scan.c
===================================================================
RCS file: /cvsroot/nmh/nmh/uip/scan.c,v
retrieving revision 1.8.2.1
retrieving revision 1.8.2.2
diff -C2 -r1.8.2.1 -r1.8.2.2
Index: send.c
===================================================================
RCS file: /cvsroot/nmh/nmh/uip/send.c,v
retrieving revision 1.5
retrieving revision 1.5.2.1
diff -C2 -r1.5 -r1.5.2.1
*** send.c 2 Jul 2002 22:09:15 -0000 1.5
--- send.c 28 Feb 2003 19:08:36 -0000 1.5.2.1
***************
*** 103,106 ****
--- 103,108 ----
#define USERSW 39
{ "user", SASLminc(-4) },
+ #define ATTACHSW 40
+ { "attach", 6 },
{ NULL, 0 }
};
***************
*** 141,144 ****
--- 143,147 ----
struct msgs *mp;
struct stat st;
+ char *attach = (char *)0; /* header field name for attachments */
#ifdef UCI
FILE *fp;
***************
*** 274,277 ****
--- 277,285 ----
vec[vecp++] = cp;
continue;
+
+ case ATTACHSW:
+ if (!(attach = *argp++) || *attach == '-')
+ adios (NULL, "missing argument to %s", argp[-2]);
+ continue;
}
} else {
***************
*** 437,441 ****
for (msgnum = 0; msgnum < msgp; msgnum++) {
! switch (sendsbr (vec, vecp, msgs[msgnum], &st, 1)) {
case DONE:
done (++status);
--- 445,449 ----
for (msgnum = 0; msgnum < msgp; msgnum++) {
! switch (sendsbr (vec, vecp, msgs[msgnum], &st, 1, attach)) {
case DONE:
done (++status);
Index: sendsbr.c
===================================================================
RCS file: /cvsroot/nmh/nmh/uip/sendsbr.c,v
retrieving revision 1.4
retrieving revision 1.4.2.1
diff -C2 -r1.4 -r1.4.2.1
*** sendsbr.c 2 Jul 2002 22:09:15 -0000 1.4
--- sendsbr.c 28 Feb 2003 19:08:36 -0000 1.4.2.1
***************
*** 43,50 ****
static jmp_buf env;
/*
* external prototypes
*/
! int sendsbr (char **, int, char *, struct stat *, int);
int done (int);
char *getusername (void);
--- 43,58 ----
static jmp_buf env;
+ static char body_file_name[MAXPATHLEN + 1]; /* name of
temporary file for body content */
+ static char composition_file_name[MAXPATHLEN + 1]; /* name of
mhbuild composition temporary file */
+ static int field_size; /* size of
header field buffer */
+ static char *field; /* header field
buffer */
+ static FILE *draft_file; /* draft file
pointer */
+ static FILE *body_file; /* body file
pointer */
+ static FILE *composition_file; /* composition
file pointer */
+
/*
* external prototypes
*/
! int sendsbr (char **, int, char *, struct stat *, int, char *);
int done (int);
char *getusername (void);
***************
*** 60,63 ****
--- 68,76 ----
static int sendaux (char **, int, char *, struct stat *);
+ static int attach(char *, char *);
+ static void clean_up_temporary_files(void);
+ static int get_line(void);
+ static void make_mime_composition_file_entry(char *);
+
/*
***************
*** 66,74 ****
int
! sendsbr (char **vec, int vecp, char *drft, struct stat *st, int rename_drft)
{
int status;
char buffer[BUFSIZ], file[BUFSIZ];
struct stat sts;
armed++;
--- 79,119 ----
int
! sendsbr (char **vec, int vecp, char *drft, struct stat *st, int rename_drft,
char *attachment_header_field_name)
{
int status;
char buffer[BUFSIZ], file[BUFSIZ];
struct stat sts;
+ char *original_draft; /* name of original draft file
*/
+ char *p; /* string pointer for building
file name */
+
+ /*
+ * Save the original name of the draft file. The name of the
draft file is changed
+ * to a temporary file containing the built MIME message if there
are attachments.
+ * We need the original name so that it can be renamed after the
message is sent.
+ */
+
+ original_draft = drft;
+
+ /*
+ * There might be attachments if a header field name for
attachments is supplied.
+ * Convert the draft to a MIME message. Use the mhbuild
composition file for the
+ * draft if there was a successful conversion because that now
contains the MIME
+ * message. A nice side effect of this is that it leaves the
original draft file
+ * untouched so that it can be retrieved and modified if desired.
+ */
+
+ if (attachment_header_field_name != (char *)0) {
+ switch (attach(attachment_header_field_name, drft)) {
+ case OK:
+ drft = composition_file_name;
+ break;
+
+ case NOTOK:
+ return (NOTOK);
+
+ case DONE:
+ break;
+ }
+ }
armed++;
***************
*** 99,103 ****
/* rename the original draft */
if (rename_drft && status == OK &&
! rename (drft, strncpy (buffer, m_backup (drft),
sizeof(buffer))) == NOTOK)
advise (buffer, "unable to rename %s to", drft);
break;
--- 144,148 ----
/* rename the original draft */
if (rename_drft && status == OK &&
! rename (original_draft, strncpy (buffer, m_backup
(original_draft), sizeof(buffer))) == NOTOK)
advise (buffer, "unable to rename %s to", drft);
break;
***************
*** 112,118 ****
--- 157,494 ----
unlink (distfile);
+ /*
+ * Get rid of any temporary files that we created for attachments.
Also get rid of
+ * the renamed composition file that mhbuild leaves as a turd. It
looks confusing,
+ * but we use the body file name to help build the renamed
composition file name.
+ */
+
+ if (drft == composition_file_name) {
+ clean_up_temporary_files();
+
+ if (strlen(composition_file_name) >= sizeof (composition_file_name) - 6)
+ advise((char *)0, "unable to remove original composition file.");
+
+ else {
+ if ((p = strrchr(composition_file_name, '/')) == (char *)0)
+ p = composition_file_name;
+ else
+ p++;
+
+ (void)strcpy(body_file_name, p);
+ *p++ = ',';
+ (void)strcpy(p, body_file_name);
+ (void)strcat(p, ".orig");
+
+ (void)unlink(composition_file_name);
+ }
+ }
+
return status;
}
+ static int
+ attach(char *attachment_header_field_name, char *draft_file_name)
+ {
+ char buf[MAXPATHLEN + 6]; /* miscellaneous buffer */
+ int c; /* current character
for body copy */
+ int has_attachment; /* draft has at least
one attachment */
+ int has_body; /* draft has a message
body */
+ int length; /* length of attachment
header field name */
+ char *p; /* miscellaneous string pointer
*/
+
+ /*
+ * Open up the draft file.
+ */
+
+ if ((draft_file = fopen(draft_file_name, "r")) == (FILE *)0)
+ adios((char *)0, "can't open draft file `%s'.", draft_file_name);
+
+ /*
+ * Allocate a buffer to hold the header components as they're read in.
+ * This buffer might need to be quite large, so we grow it as needed.
+ */
+
+ if ((field = (char *)malloc(field_size = 256)) == (char *)0)
+ adios(NULL, "can't allocate field buffer.");
+
+ /*
+ * Scan the draft file for a header field name that matches the
-attach
+ * argument. The existence of one indicates that the draft has
attachments.
+ * Bail out if there are no attachments because we're done. Read
to the
+ * end of the headers even if we have no attachments.
+ */
+
+ length = strlen(attachment_header_field_name);
+
+ has_attachment = 0;
+
+ while (get_line() != EOF && *field != '\0' && *field != '-')
+ if (strncasecmp(field, attachment_header_field_name, length) == 0 &&
field[length] == ':')
+ has_attachment = 1;
+
+ if (has_attachment == 0)
+ return (DONE);
+
+ /*
+ * We have at least one attachment. Look for at least one
non-blank line
+ * in the body of the message which indicates content in the body.
+ */
+
+ has_body = 0;
+
+ while (get_line() != EOF) {
+ for (p = field; *p != '\0'; p++) {
+ if (*p != ' ' && *p != '\t') {
+ has_body = 1;
+ break;
+ }
+ }
+
+ if (has_body)
+ break;
+ }
+
+ /*
+ * Make names for the temporary files.
+ */
+
+ (void)strncpy(body_file_name, m_scratch("", m_maildir(invo_name)), sizeof
(body_file_name));
+ (void)strncpy(composition_file_name, m_scratch("", m_maildir(invo_name)),
sizeof (composition_file_name));
+
+ if (has_body)
+ body_file = fopen(body_file_name, "w");
+
+ composition_file = fopen(composition_file_name, "w");
+
+ if ((has_body && body_file == (FILE *)0) || composition_file == (FILE
*)0) {
+ clean_up_temporary_files();
+ adios((char *)0, "unable to open all of the temporary files.");
+ }
+
+ /*
+ * Start at the beginning of the draft file. Copy all
non-attachment header fields
+ * to the temporary composition file. Then add the dashed line
separator.
+ */
+
+ rewind(draft_file);
+
+ while (get_line() != EOF && *field != '\0' && *field != '-')
+ if (strncasecmp(field, attachment_header_field_name, length) != 0 ||
field[length] != ':')
+ (void)fprintf(composition_file, "%s\n", field);
+
+ (void)fputs("--------\n", composition_file);
+
+ /*
+ * Copy the message body to a temporary file.
+ */
+
+ if (has_body) {
+ while ((c = getc(draft_file)) != EOF)
+ putc(c, body_file);
+
+ (void)fclose(body_file);
+ }
+
+ /*
+ * Add a mhbuild MIME composition file line for the body if there
was one.
+ */
+
+ if (has_body)
+ make_mime_composition_file_entry(body_file_name);
+
+ /*
+ * Now, go back to the beginning of the draft file and look for
header fields
+ * that specify attachments. Add a mhbuild MIME composition file
for each.
+ */
+
+ rewind(draft_file);
+
+ while (get_line() != EOF && *field != '\0' && *field != '-') {
+ if (strncasecmp(field, attachment_header_field_name, length) == 0 &&
field[length] == ':') {
+ for (p = field + length + 1; *p == ' ' || *p == '\t'; p++)
+ ;
+
+ make_mime_composition_file_entry(p);
+ }
+ }
+
+ (void)fclose(composition_file);
+
+ /*
+ * We're ready to roll! Run mhbuild on the composition file.
Note that mhbuild
+ * is in the context as buildmimeproc.
+ */
+
+ (void)sprintf(buf, "%s %s", buildmimeproc, composition_file_name);
+
+ if (system(buf) != 0) {
+ clean_up_temporary_files();
+ return (NOTOK);
+ }
+
+ return (OK);
+ }
+
+ static void
+ clean_up_temporary_files(void)
+ {
+ (void)unlink(body_file_name);
+ (void)unlink(composition_file_name);
+
+ return;
+ }
+
+ static int
+ get_line(void)
+ {
+ int c; /* current character */
+ int n; /* number of bytes in buffer */
+ char *p; /* buffer pointer */
+
+ /*
+ * Get a line from the input file, growing the field buffer as
needed. We do this
+ * so that we can fit an entire line in the buffer making it easy
to do a string
+ * comparison on both the field name and the field body which
might be a long path
+ * name.
+ */
+
+ for (n = 0, p = field; (c = getc(draft_file)) != EOF; *p++ = c) {
+ if (c == '\n' && (c = getc(draft_file)) != ' ' && c != '\t') {
+ (void)ungetc(c, draft_file);
+ c = '\n';
+ break;
+ }
+
+ if (++n >= field_size - 1) {
+ if ((field = (char *)realloc((void *)field, field_size += 256)) ==
(char *)0)
+ adios(NULL, "can't grow field buffer.");
+
+ p = field + n - 1;
+ }
+ }
+
+ /*
+ * NUL-terminate the field..
+ */
+
+ *p = '\0';
+
+ return (c);
+ }
+
+ static void
+ make_mime_composition_file_entry(char *file_name)
+ {
+ int binary; /* binary character
found flag */
+ int c; /* current character */
+ char cmd[MAXPATHLEN + 6]; /* file command buffer */
+ char *content_type; /* mime content type */
+ FILE *fp; /* content and pipe file
pointer */
+ struct node *np; /* context scan node pointer */
+ char *p; /* miscellaneous string pointer
*/
+ struct stat st; /* file status buffer */
+
+ content_type = (char *)0;
+
+ /*
+ * Check the file name for a suffix. Scan the context for that
suffix on a
+ * mhshow-suffix- entry. We use these entries to be compatible
with mhnshow,
+ * and there's no reason to make the user specify each suffix
twice. Context
+ * entries of the form "mhshow-suffix-contenttype" in the name
have the suffix
+ * in the field, including the dot.
+ */
+
+ if ((p = strrchr(file_name, '.')) != (char *)0) {
+ for (np = m_defs; np; np = np->n_next) {
+ if (strncasecmp(np->n_name, "mhshow-suffix-", 14) == 0 &&
strcasecmp(p, np->n_field) == 0) {
+ content_type = np->n_name + 14;
+ break;
+ }
+ }
+ }
+
+ /*
+ * No content type was found, either because there was no matching
entry in the
+ * context or because the file name has no suffix. Open the file
and check for
+ * non-ASCII characters. Choose the content type based on this
check.
+ */
+
+ if (content_type == (char *)0) {
+ if ((fp = fopen(file_name, "r")) == (FILE *)0) {
+ clean_up_temporary_files();
+ adios((char *)0, "unable to access file \"%s\"", file_name);
+ }
+
+ binary = 0;
+
+ while ((c = getc(fp)) != EOF) {
+ if (c > 127 || c < 0) {
+ binary = 1;
+ break;
+ }
+ }
+
+ (void)fclose(fp);
+
+ content_type = binary ? "application/octet-stream" : "text/plain";
+ }
+
+ /*
+ * Make sure that the attachment file exists and is readable.
Append a mhbuild
+ * directive to the draft file. This starts with the content
type. Append a
+ * file name attribute and a private x-unix-mode attribute. Also
append a
+ * description obtained (if possible) by running the "file"
command on the file.
+ */
+
+ if (stat(file_name, &st) == -1 || access(file_name, R_OK) != 0) {
+ clean_up_temporary_files();
+ adios((char *)0, "unable to access file \"%s\"", file_name);
+ }
+
+ (void)fprintf(composition_file, "#%s; name=\"%s\"; x-unix-mode=0%.3ho",
+ content_type, ((p = strrchr(file_name, '/')) == (char *)0) ? file_name :
p + 1, (unsigned short)(st.st_mode & 0777));
+
+ if (strlen(file_name) > MAXPATHLEN) {
+ clean_up_temporary_files();
+ adios((char *)0, "attachment file name `%s' too long.", file_name);
+ }
+
+ (void)sprintf(cmd, "file '%s'", file_name);
+
+ if ((fp = popen(cmd, "r")) != (FILE *)0 && fgets(cmd, sizeof (cmd), fp)
!= (char *)0) {
+ *strchr(cmd, '\n') = '\0';
+
+ /*
+ * The output of the "file" command is of the form
+ *
+ * file: description
+ *
+ * Strip off the "file:" and subsequent white space.
+ */
+
+ for (p = cmd; *p != '\0'; p++) {
+ if (*p == ':') {
+ for (p++; *p != '\0'; p++) {
+ if (*p != '\t')
+ break;
+ }
+ break;
+ }
+ }
+
+ if (*p != '\0')
+ (void)fprintf(composition_file, " [ %s ]", p);
+
+ (void)pclose(fp);
+ }
+
+ /*
+ * Finish up with the file name.
+ */
+
+ (void)fprintf(composition_file, " %s\n", file_name);
+
+ return;
+ }
/*
***************
*** 645,649 ****
if (debugsw)
advise (NULL, "annotate message %d", msgnum);
! annotate (m_name (msgnum), annotext, cp, inplace, 1);
}
}
--- 1021,1025 ----
if (debugsw)
advise (NULL, "annotate message %d", msgnum);
! annotate (m_name (msgnum), annotext, cp, inplace, 1, 0, 0);
}
}
Index: sortm.c
===================================================================
RCS file: /cvsroot/nmh/nmh/uip/sortm.c,v
retrieving revision 1.5
retrieving revision 1.5.2.1
diff -C2 -r1.5 -r1.5.2.1
*** sortm.c 2 Jul 2002 22:09:15 -0000 1.5
--- sortm.c 28 Feb 2003 19:08:36 -0000 1.5.2.1
***************
*** 233,237 ****
if (verbose) { /* announce what we're doing */
if (subjsort)
! printf ("sorting by %s-major %s-minor\n",
submajor ? subjsort : datesw,
submajor ? datesw : subjsort);
--- 233,237 ----
if (verbose) { /* announce what we're doing */
if (subjsort)
! printf ("sorting by %s-major %s-minor\n",
submajor ? subjsort : datesw,
submajor ? datesw : subjsort);
***************
*** 241,245 ****
/* first sort by date, or by subject-major, date-minor */
! qsort ((char *) dlist, nmsgs, sizeof(*dlist),
(qsort_comp) (submajor && subjsort ? txtsort : dsort));
--- 241,245 ----
/* first sort by date, or by subject-major, date-minor */
! qsort ((char *) dlist, nmsgs, sizeof(*dlist),
(qsort_comp) (submajor && subjsort ? txtsort : dsort));
***************
*** 293,297 ****
while (*s && (*s)->s_subj[0] &&
strcmp((*s)->s_subj, s[-1]->s_subj) == 0 &&
! (datelimit == 0 ||
(*s)->s_clock - s[-1]->s_clock <= datelimit)) {
il[(*s)->s_msg] = 0;
--- 293,297 ----
while (*s && (*s)->s_subj[0] &&
strcmp((*s)->s_subj, s[-1]->s_subj) == 0 &&
! (datelimit == 0 ||
(*s)->s_clock - s[-1]->s_clock <= datelimit)) {
il[(*s)->s_msg] = 0;
***************
*** 304,307 ****
--- 304,313 ----
dlist = flist;
}
+
+ /*
+ * At this point, dlist is a sorted array of pointers to smsg structures,
+ * each of which contains a message number.
+ */
+
rename_msgs (mp, dlist);
***************
*** 313,317 ****
}
! static int
read_hdrs (struct msgs *mp, char *datesw)
{
--- 319,323 ----
}
! static int
read_hdrs (struct msgs *mp, char *datesw)
{
***************
*** 432,436 ****
* try to make the subject "canonical": delete
* leading "re:", everything but letters & smash
! * letters to lower case.
*/
register char *cp, *cp2, c;
--- 438,442 ----
* try to make the subject "canonical": delete
* leading "re:", everything but letters & smash
! * letters to lower case.
*/
register char *cp, *cp2, c;
***************
*** 473,477 ****
* sort on dates.
*/
! static int
dsort (struct smsg **a, struct smsg **b)
{
--- 479,483 ----
* sort on dates.
*/
! static int
dsort (struct smsg **a, struct smsg **b)
{
***************
*** 489,493 ****
* sort on subjects.
*/
! static int
subsort (struct smsg **a, struct smsg **b)
{
--- 495,499 ----
* sort on subjects.
*/
! static int
subsort (struct smsg **a, struct smsg **b)
{
***************
*** 500,504 ****
}
! static int
txtsort (struct smsg **a, struct smsg **b)
{
--- 506,510 ----
}
! static int
txtsort (struct smsg **a, struct smsg **b)
{
***************
*** 518,521 ****
--- 524,528 ----
int nxt, old, new;
char *newname, oldname[BUFSIZ];
+ char newbuf[MAXPATHLEN + 1];
for (;;) {
***************
*** 532,540 ****
adios (newname, "unable to rename %s to", oldname);
copy_msg_flags (mp, new, old);
if (mp->curmsg == old)
seq_setcur (mp, new);
! if (nxt == endmsg)
break;
--- 539,551 ----
adios (newname, "unable to rename %s to", oldname);
+ (void)snprintf(oldname, sizeof (oldname), "%s/%d", mp->foldpath, old);
+ (void)snprintf(newbuf, sizeof (newbuf), "%s/%d", mp->foldpath, new);
+ ext_hook("ref-hook", oldname, newbuf);
+
copy_msg_flags (mp, new, old);
if (mp->curmsg == old)
seq_setcur (mp, new);
! if (nxt == endmsg)
break;
***************
*** 551,554 ****
--- 562,566 ----
seqset_t tmpset;
char f1[BUFSIZ], tmpfil[BUFSIZ];
+ char newbuf[MAXPATHLEN + 1];
struct smsg *sp;
***************
*** 556,560 ****
for (i = 0; i < nmsgs; i++) {
! if (! (sp = mlist[i]))
continue; /* did this one */
--- 568,572 ----
for (i = 0; i < nmsgs; i++) {
! if (! (sp = mlist[i]))
continue; /* did this one */
***************
*** 577,580 ****
--- 589,603 ----
if (rename (f1, tmpfil) == NOTOK)
adios (tmpfil, "unable to rename %s to ", f1);
+
+ /*
+ * Run the external hook to refile the old message as message
+ * number 2147483647. This is our way of making a temporary
+ * message number. I don't really like this.
+ */
+
+ (void)snprintf(f1, sizeof (f1), "%s/%d", mp->foldpath, old);
+ (void)snprintf(newbuf, sizeof (newbuf), "%s/2147483647", mp->foldpath);
+ ext_hook("ref-hook", f1, newbuf);
+
get_msg_flags (mp, &tmpset, old);
***************
*** 582,585 ****
--- 605,616 ----
if (rename (tmpfil, m_name(new)) == NOTOK)
adios (m_name(new), "unable to rename %s to", tmpfil);
+
+ /*
+ * Run the external hook to refile the temorary message number
+ * to the real place.
+ */
+
+ (void)snprintf(f1, sizeof (f1), "%s/%d", mp->foldpath, new);
+ ext_hook("ref-hook", newbuf, f1);
set_msg_flags (mp, &tmpset, new);
Index: viamail.c
===================================================================
RCS file: /cvsroot/nmh/nmh/uip/viamail.c,v
retrieving revision 1.7
retrieving revision 1.7.2.1
diff -C2 -r1.7 -r1.7.2.1
*** viamail.c 2 Jul 2002 22:09:15 -0000 1.7
--- viamail.c 28 Feb 2003 19:08:36 -0000 1.7.2.1
***************
*** 238,242 ****
vec[vecp++] = "-verbose";
! switch (sendsbr (vec, vecp, tmpfil, &st, 0)) {
case DONE:
case NOTOK:
--- 238,242 ----
vec[vecp++] = "-verbose";
! switch (sendsbr (vec, vecp, tmpfil, &st, 0, (char *)0)) {
case DONE:
case NOTOK:
Index: whatnowsbr.c
===================================================================
RCS file: /cvsroot/nmh/nmh/uip/whatnowsbr.c,v
retrieving revision 1.5
retrieving revision 1.5.2.1
diff -C2 -r1.5 -r1.5.2.1
*** whatnowsbr.c 2 Jul 2002 22:09:15 -0000 1.5
--- whatnowsbr.c 28 Feb 2003 19:08:36 -0000 1.5.2.1
***************
*** 8,11 ****
--- 8,42 ----
* COPYRIGHT file in the root directory of the nmh distribution for
* complete copyright information.
+ *
+ * Several options have been added to ease the inclusion of attachments
+ * using the header field name mechanism added to anno and send. The
+ * -attach option is used to specify the header field name for attachments.
+ *
+ * Several commands have been added at the whatnow prompt:
+ *
+ * cd [ directory ] This option works just like the shell's
+ * cd command and lets the user change the
+ * directory from which attachments are
+ * taken so that long path names are not
+ * needed with every file.
+ *
+ * ls [ ls-options ] This option works just like the normal
+ * ls command and exists to allow the user
+ * to verify file names in the directory.
+ *
+ * pwd This option works just like the normal
+ * pwd command and exists to allow the user
+ * to verify the directory.
+ *
+ * attach files This option attaches the named files to
+ * the draft.
+ *
+ * alist [-ln] This option lists the attachments on the
+ * draft. -l gets long listings, -n gets
+ * numbered listings.
+ *
+ * detach files This option removes attachments from the
+ * detach -n numbers draft. This can be done by file name or
+ * by attachment number.
*/
***************
*** 32,35 ****
--- 63,68 ----
#define HELPSW 7
{ "help", 0 },
+ #define ATTACHSW 8
+ { "attach header-field-name", 0 },
{ NULL, 0 }
};
***************
*** 59,62 ****
--- 92,107 ----
#define DELETESW 9
{ "delete", 0 },
+ #define CDCMDSW 10
+ { "cd [directory]", 0 },
+ #define PWDCMDSW 11
+ { "pwd", 0 },
+ #define LSCMDSW 12
+ { "ls", 0 },
+ #define ATTACHCMDSW 13
+ { "attach", 0 },
+ #define DETACHCMDSW 14
+ { "detach [-n]", 2 },
+ #define ALISTCMDSW 15
+ { "alist [-ln] ", 2 },
{ NULL, 0 }
};
***************
*** 90,93 ****
--- 135,145 ----
char **argp, **arguments;
struct stat st;
+ char *attach = (char *)0; /* attachment header field name */
+ char cwd[MAXPATHLEN + 1]; /* current working directory */
+ char file[MAXPATHLEN + 1]; /* file name buffer */
+ char shell[MAXPATHLEN + 1]; /* shell response buffer */
+ FILE *f; /* read pointer for bgnd proc */
+ char *l; /* set on -l to alist command */
+ int n; /* set on -n to alist command */
invo_name = r1bindex (argv[0], '/');
***************
*** 99,112 ****
argp = arguments;
while ((cp = *argp++)) {
if (*cp == '-') {
switch (smatch (++cp, whatnowswitches)) {
! case AMBIGSW:
ambigsw (cp, whatnowswitches);
done (1);
! case UNKWNSW:
adios (NULL, "-%s unknown", cp);
! case HELPSW:
snprintf (buf, sizeof(buf), "%s [switches] [file]", invo_name);
print_help (buf, whatnowswitches, 1);
--- 151,172 ----
argp = arguments;
+ /*
+ * Get the initial current working directory.
+ */
+
+ if (getcwd(cwd, sizeof (cwd)) == (char *)0) {
+ adios("getcwd", "could not get working directory");
+ }
+
while ((cp = *argp++)) {
if (*cp == '-') {
switch (smatch (++cp, whatnowswitches)) {
! case AMBIGSW:
ambigsw (cp, whatnowswitches);
done (1);
! case UNKWNSW:
adios (NULL, "-%s unknown", cp);
! case HELPSW:
snprintf (buf, sizeof(buf), "%s [switches] [file]", invo_name);
print_help (buf, whatnowswitches, 1);
***************
*** 116,120 ****
done (1);
! case DFOLDSW:
if (dfolder)
adios (NULL, "only one draft folder at a time!");
--- 176,180 ----
done (1);
! case DFOLDSW:
if (dfolder)
adios (NULL, "only one draft folder at a time!");
***************
*** 124,128 ****
*cp != '@' ? TFOLDER : TSUBCWF);
continue;
! case DMSGSW:
if (dmsg)
adios (NULL, "only one draft message at a time!");
--- 184,188 ----
*cp != '@' ? TFOLDER : TSUBCWF);
continue;
! case DMSGSW:
if (dmsg)
adios (NULL, "only one draft message at a time!");
***************
*** 130,144 ****
adios (NULL, "missing argument to %s", argp[-2]);
continue;
! case NDFLDSW:
dfolder = NULL;
isdf = NOTOK;
continue;
! case EDITRSW:
if (!(ed = *argp++) || *ed == '-')
adios (NULL, "missing argument to %s", argp[-2]);
nedit = 0;
continue;
! case NEDITSW:
nedit++;
continue;
--- 190,204 ----
adios (NULL, "missing argument to %s", argp[-2]);
continue;
! case NDFLDSW:
dfolder = NULL;
isdf = NOTOK;
continue;
! case EDITRSW:
if (!(ed = *argp++) || *ed == '-')
adios (NULL, "missing argument to %s", argp[-2]);
nedit = 0;
continue;
! case NEDITSW:
nedit++;
continue;
***************
*** 148,151 ****
--- 208,218 ----
adios (NULL, "missing argument to %s", argp[-2]);
continue;
+
+ case ATTACHSW:
+ if (attach != (char *)0)
+ adios(NULL, "only one attachment header field name at a
time!");
+ if (!(attach = *argp++) || *attach == '-')
+ adios (NULL, "missing argument to %s", argp[-2]);
+ continue;
}
}
***************
*** 201,205 ****
break;
! case LISTSW:
/* display the draft file */
showfile (++argp, drft);
--- 268,272 ----
break;
! case LISTSW:
/* display the draft file */
showfile (++argp, drft);
***************
*** 233,242 ****
break;
! case SENDSW:
/* Send draft */
sendfile (++argp, drft, 0);
break;
! case REFILEOPT:
/* Refile the draft */
if (refile (++argp, drft) == 0)
--- 300,309 ----
break;
! case SENDSW:
/* Send draft */
sendfile (++argp, drft, 0);
break;
! case REFILEOPT:
/* Refile the draft */
if (refile (++argp, drft) == 0)
***************
*** 244,248 ****
break;
! default:
/* Unknown command */
advise (NULL, "say what?");
--- 311,555 ----
break;
! case CDCMDSW:
! /* Change the working directory for attachments
! *
! * Run the directory through the user's shell so that
! * we can take advantage of any syntax that the user
! * is accustomed to. Read back the absolute path.
! */
!
! if (*++argp == (char *)0) {
! (void)sprintf(buf, "$SHELL -c \"cd;pwd\"");
! }
! else if (strlen(*argp) >= BUFSIZ) {
! adios((char *)0, "arguments too long");
! }
! else {
! (void)sprintf(buf, "$SHELL -c \"cd %s;cd %s;pwd\"", cwd, *argp);
! }
! if ((f = popen(buf, "r")) != (FILE *)0) {
! fgets(cwd, sizeof (cwd), f);
!
! if (strchr(cwd, '\n') != (char *)0)
! *strchr(cwd, '\n') = '\0';
!
! pclose(f);
! }
! else {
! advise("popen", "could not get directory");
! }
!
! break;
!
! case PWDCMDSW:
! /* Print the working directory for attachments */
! printf("%s\n", cwd);
! break;
!
! case LSCMDSW:
! /* List files in the current attachment working directory
! *
! * Use the user's shell so that we can take advantage of any
! * syntax that the user is accustomed to.
! */
!
! cp = buf + sprintf(buf, "$SHELL -c \" cd %s;ls", cwd);
!
! while (*++argp != (char *)0) {
! if (cp + strlen(*argp) + 2 >= buf + BUFSIZ)
! adios((char *)0, "arguments too long");
!
! cp += sprintf(cp, " %s", *argp);
! }
!
! (void)strcat(cp, "\"");
! (void)system(buf);
! break;
!
! case ALISTCMDSW:
! /*
! * List attachments on current draft. Options are:
! *
! * -l long listing (full path names)
! * -n numbers listing
! */
!
! if (attach == (char *)0) {
! advise((char *)0, "can't list because no header field name was
given.");
! break;
! }
!
! l = (char *)0;
! n = 0;
!
! while (*++argp != (char *)0) {
! if (strcmp(*argp, "-l") == 0)
! l = "/";
!
! else if (strcmp(*argp, "-n") == 0)
! n = 1;
!
! else if (strcmp(*argp, "-ln") == 0 || strcmp(*argp, "-nl") ==
0) {
! l = "/";
! n = 1;
! }
!
! else {
! n = -1;
! break;
! }
! }
!
! if (n == -1)
! advise((char *)0, "usage is alist [-ln].");
!
! else
! annolist(drft, attach, l, n);
!
! break;
!
! case ATTACHCMDSW:
! /*
! * Attach files to current draft.
! */
!
! if (attach == (char *)0) {
! advise((char *)0, "can't attach because no header field name
was given.");
! break;
! }
!
! /*
! * Build a command line that causes the user's shell to list the
file name
! * arguments. This handles and wildcard expansion, tilde
expansion, etc.
! */
!
! cp = buf + sprintf(buf, "$SHELL -c \" cd %s;ls", cwd);
!
! while (*++argp != (char *)0) {
! if (cp + strlen(*argp) + 3 >= buf + BUFSIZ)
! adios((char *)0, "arguments too long");
!
! cp += sprintf(cp, " %s", *argp);
! }
!
! (void)strcat(cp, "\"");
!
! /*
! * Read back the response from the shell, which contains a number
of lines
! * with one file name per line. Remove off the newline.
Determine whether
! * we have an absolute or relative path name. Prepend the current
working
! * directory to relative path names. Add the attachment
annotation to the
! * draft.
! */
!
! if ((f = popen(buf, "r")) != (FILE *)0) {
! while (fgets(shell, sizeof (shell), f) != (char *)0) {
! *(strchr(shell, '\n')) = '\0';
!
! if (*shell == '/')
! (void)annotate(drft, attach, shell, 1, 0, -1, 1);
! else {
! (void)sprintf(file, "%s/%s", cwd, shell);
! (void)annotate(drft, attach, file, 1, 0, -1, 1);
! }
! }
!
! pclose(f);
! }
! else {
! advise("popen", "could not get file from shell");
! }
!
! break;
!
! case DETACHCMDSW:
! /*
! * Detach files from current draft.
! */
!
! if (attach == (char *)0) {
! advise((char *)0, "can't detach because no header field name
was given.");
! break;
! }
!
! /*
! * Scan the arguments for a -n. Mixed file names and numbers
aren't allowed,
! * so this catches a -n anywhere in the argument list.
! */
!
! for (n = 0, arguments = argp + 1; *arguments != (char *)0;
arguments++) {
! if (strcmp(*arguments, "-n") == 0) {
! n = 1;
! break;
! }
! }
!
! /*
! * A -n was found so interpret the arguments as attachment numbers.
! * Decrement any remaining argument number that is greater than
the one
! * just processed after processing each one so that the numbering
stays
! * correct.
! */
!
! if (n == 1) {
! for (arguments = argp + 1; *arguments != (char *)0;
arguments++) {
! if (strcmp(*arguments, "-n") == 0)
! continue;
!
! if (**arguments != '\0') {
! n = atoi(*arguments);
! (void)annotate(drft, attach, (char *)0, 1, 0, n, 1);
!
! for (argp = arguments + 1; *argp != (char *)0; argp++) {
! if (atoi(*argp) > n) {
! if (atoi(*argp) == 1)
! *argp = "";
! else
! (void)sprintf(*argp, "%d", atoi(*argp) - 1);
! }
! }
! }
! }
! }
!
! /*
! * The arguments are interpreted as file names. Run them through
the
! * user's shell for wildcard expansion and other goodies. Do this
from
! * the current working directory if the argument is not an
absolute path
! * name (does not begin with a /).
! */
!
! else {
! for (arguments = argp + 1; *arguments != (char *)0;
arguments++) {
! if (**arguments == '/') {
! if (strlen(*arguments) + sizeof ("$SHELL -c \"ls \"")
>= sizeof (buf))
! adios((char *)0, "arguments too long");
!
! (void)sprintf(buf, "$SHELL -c \"ls %s\"", *arguments);
! }
! else {
! if (strlen(cwd) + strlen(*arguments) + sizeof ("$SHELL
-c \" cd ; ls \"") >= sizeof (buf))
! adios((char *)0, "arguments too long");
!
! (void)sprintf(buf, "$SHELL -c \" cd %s;ls %s\"", cwd,
*arguments);
! }
!
! if ((f = popen(buf, "r")) != (FILE *)0) {
! while (fgets(shell, sizeof (cwd), f) != (char *)0) {
! *(strchr(shell, '\n')) = '\0';
! (void)annotate(drft, attach, shell, 1, 0, 0, 1);
! }
!
! pclose(f);
! }
! else {
! advise("popen", "could not get file from shell");
! }
! }
! }
!
! break;
!
! default:
/* Unknown command */
advise (NULL, "say what?");
***************
*** 331,340 ****
switch (pid = vfork ()) {
! case NOTOK:
advise ("fork", "unable to");
status = NOTOK;
break;
! case OK:
if (cwd)
chdir (cwd);
--- 638,647 ----
switch (pid = vfork ()) {
! case NOTOK:
advise ("fork", "unable to");
status = NOTOK;
break;
! case OK:
if (cwd)
chdir (cwd);
***************
*** 358,362 ****
_exit (-1);
! default:
if ((status = pidwait (pid, NOTOK))) {
#ifdef ATTVIBUG
--- 665,669 ----
_exit (-1);
! default:
if ((status = pidwait (pid, NOTOK))) {
#ifdef ATTVIBUG
***************
*** 493,499 ****
sleep (5);
switch (child_id) {
! case NOTOK:
advise (NULL, "unable to fork, so sending directly...");
! case OK:
vecp = 0;
vec[vecp++] = invo_name;
--- 800,806 ----
sleep (5);
switch (child_id) {
! case NOTOK:
advise (NULL, "unable to fork, so sending directly...");
! case OK:
vecp = 0;
vec[vecp++] = invo_name;
***************
*** 511,515 ****
_exit (-1);
! default:
if (pidwait(child_id, OK) == 0)
done (0);
--- 818,822 ----
_exit (-1);
! default:
if (pidwait(child_id, OK) == 0)
done (0);
***************
*** 697,700 ****
--- 1004,1009 ----
#define USERSW 38
{ "user", SASLminc(-4) },
+ #define SNDATTACHSW 39
+ { "attach file", 6 },
{ NULL, 0 }
};
***************
*** 721,724 ****
--- 1030,1034 ----
char **arguments, *vec[MAXARGS];
struct stat st;
+ char *attach = (char *)0; /* attachment header field name */
#ifndef lint
***************
*** 778,789 ****
if (*cp == '-') {
switch (smatch (++cp, sendswitches)) {
! case AMBIGSW:
ambigsw (cp, sendswitches);
return;
! case UNKWNSW:
advise (NULL, "-%s unknown\n", cp);
return;
! case SHELPSW:
snprintf (buf, sizeof(buf), "%s [switches]", sp);
print_help (buf, sendswitches, 1);
--- 1088,1099 ----
if (*cp == '-') {
switch (smatch (++cp, sendswitches)) {
! case AMBIGSW:
ambigsw (cp, sendswitches);
return;
! case UNKWNSW:
advise (NULL, "-%s unknown\n", cp);
return;
! case SHELPSW:
snprintf (buf, sizeof(buf), "%s [switches]", sp);
print_help (buf, sendswitches, 1);
***************
*** 793,804 ****
return;
! case SPSHSW:
pushed++;
continue;
! case NSPSHSW:
pushed = 0;
continue;
! case SPLITSW:
if (!(cp = *argp++) || sscanf (cp, "%d", &splitsw) != 1) {
advise (NULL, "missing argument to %s", argp[-2]);
--- 1103,1114 ----
return;
! case SPSHSW:
pushed++;
continue;
! case NSPSHSW:
pushed = 0;
continue;
! case SPLITSW:
if (!(cp = *argp++) || sscanf (cp, "%d", &splitsw) != 1) {
advise (NULL, "missing argument to %s", argp[-2]);
***************
*** 807,824 ****
continue;
! case UNIQSW:
unique++;
continue;
! case NUNIQSW:
unique = 0;
continue;
! case FORWSW:
forwsw++;
continue;
! case NFORWSW:
forwsw = 0;
continue;
! case VERBSW:
verbsw++;
vec[vecp++] = --cp;
--- 1117,1134 ----
continue;
! case UNIQSW:
unique++;
continue;
! case NUNIQSW:
unique = 0;
continue;
! case FORWSW:
forwsw++;
continue;
! case NFORWSW:
forwsw = 0;
continue;
! case VERBSW:
verbsw++;
vec[vecp++] = --cp;
***************
*** 829,859 ****
continue;
! case DEBUGSW:
debugsw++; /* fall */
! case NFILTSW:
! case FRMTSW:
! case NFRMTSW:
case BITSTUFFSW:
case NBITSTUFFSW:
! case MIMESW:
! case NMIMESW:
! case MSGDSW:
! case NMSGDSW:
! case WATCSW:
! case NWATCSW:
! case MAILSW:
! case SAMLSW:
! case SSNDSW:
! case SOMLSW:
! case SNOOPSW:
case SASLSW:
vec[vecp++] = --cp;
continue;
! case ALIASW:
! case FILTSW:
! case WIDTHSW:
! case CLIESW:
! case SERVSW:
case SASLMECHSW:
case USERSW:
--- 1139,1169 ----
continue;
! case DEBUGSW:
debugsw++; /* fall */
! case NFILTSW:
! case FRMTSW:
! case NFRMTSW:
case BITSTUFFSW:
case NBITSTUFFSW:
! case MIMESW:
! case NMIMESW:
! case MSGDSW:
! case NMSGDSW:
! case WATCSW:
! case NWATCSW:
! case MAILSW:
! case SAMLSW:
! case SSNDSW:
! case SOMLSW:
! case SNOOPSW:
case SASLSW:
vec[vecp++] = --cp;
continue;
! case ALIASW:
! case FILTSW:
! case WIDTHSW:
! case CLIESW:
! case SERVSW:
case SASLMECHSW:
case USERSW:
***************
*** 866,876 ****
continue;
! case SDRFSW:
! case SDRMSW:
if (!(cp = *argp++) || *cp == '-') {
advise (NULL, "missing argument to %s", argp[-2]);
return;
}
! case SNDRFSW:
continue;
}
--- 1176,1193 ----
continue;
! case SDRFSW:
! case SDRMSW:
if (!(cp = *argp++) || *cp == '-') {
advise (NULL, "missing argument to %s", argp[-2]);
return;
}
! case SNDRFSW:
! continue;
!
! case SNDATTACHSW:
! if (!(attach = *argp++) || *attach == '-') {
! advise (NULL, "missing argument to %s", argp[-2]);
! return;
! }
continue;
}
***************
*** 939,943 ****
closefds (3);
! if (sendsbr (vec, vecp, file, &st, 1) == OK)
done (0);
}
--- 1256,1260 ----
closefds (3);
! if (sendsbr (vec, vecp, file, &st, 1, attach) == OK)
done (0);
}
***************
*** 958,966 ****
switch (pid = vfork ()) {
! case NOTOK:
advise ("fork", "unable to");
return 1;
! case OK:
vecp = 0;
vec[vecp++] = r1bindex (whomproc, '/');
--- 1275,1283 ----
switch (pid = vfork ()) {
! case NOTOK:
advise ("fork", "unable to");
return 1;
! case OK:
vecp = 0;
vec[vecp++] = r1bindex (whomproc, '/');
***************
*** 976,980 ****
_exit (-1); /* NOTREACHED */
! default:
return (pidwait (pid, NOTOK) & 0377 ? 1 : 0);
}
--- 1293,1297 ----
_exit (-1); /* NOTREACHED */
! default:
return (pidwait (pid, NOTOK) & 0377 ? 1 : 0);
}
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [Nmh-commits] CVS: nmh/uip Makefile.in,1.15,1.15.2.1 anno.c,1.4,1.4.2.1 annosbr.c,1.3,1.3.2.1 burst.c,1.4,1.4.2.1 flist.c,1.4,1.4.2.1 folder.c,1.4,1.4.2.1 inc.c,1.13,1.13.2.1 install-mh.c,1.4,1.4.2.1 mhstoresbr.c,1.7,1.7.2.1 rcvstore.c,1.7,1.7.2.1 refile.c,1.4,1.4.2.1 rmf.c,1.4,1.4.2.1 rmm.c,1.4,1.4.2.1 scan.c,1.8.2.1,1.8.2.2 send.c,1.5,1.5.2.1 sendsbr.c,1.4,1.4.2.1 sortm.c,1.5,1.5.2.1 viamail.c,1.7,1.7.2.1 whatnowsbr.c,1.5,1.5.2.1,
Jon Steinhart <address@hidden> <=
- Prev by Date:
[Nmh-commits] CVS: nmh/sbr ext_hook.c,NONE,1.1.2.1 Makefile.in,1.13,1.13.2.1 context_del.c,1.2,1.2.2.1 context_find.c,1.2,1.2.2.1 context_read.c,1.2,1.2.2.1 context_replace.c,1.2,1.2.2.1 folder_addmsg.c,1.2,1.2.2.1 folder_delmsgs.c,1.2,1.2.2.1 folder_pack.c,1.2,1.2.2.1 m_convert.c,1.2,1.2.2.1 pidwait.c,1.4,1.4.2.1 seq_read.c,1.2,1.2.2.1 seq_save.c,1.2,1.2.2.1
- Previous by thread:
[Nmh-commits] CVS: nmh/sbr ext_hook.c,NONE,1.1.2.1 Makefile.in,1.13,1.13.2.1 context_del.c,1.2,1.2.2.1 context_find.c,1.2,1.2.2.1 context_read.c,1.2,1.2.2.1 context_replace.c,1.2,1.2.2.1 folder_addmsg.c,1.2,1.2.2.1 folder_delmsgs.c,1.2,1.2.2.1 folder_pack.c,1.2,1.2.2.1 m_convert.c,1.2,1.2.2.1 pidwait.c,1.4,1.4.2.1 seq_read.c,1.2,1.2.2.1 seq_save.c,1.2,1.2.2.1
- Index(es):