[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Nmh-commits] CVS: nmh/uip anno.c,1.4,1.5 annosbr.c,1.3,1.4 send.c,1.5,1
From: |
Jon Steinhart <address@hidden> |
Subject: |
[Nmh-commits] CVS: nmh/uip anno.c,1.4,1.5 annosbr.c,1.3,1.4 send.c,1.5,1.6 sendsbr.c,1.4,1.5 viamail.c,1.7,1.8 whatnowsbr.c,1.5,1.6 |
Date: |
Mon, 19 Aug 2002 16:50:45 -0400 |
Update of /cvsroot/nmh/nmh/uip
In directory subversions:/tmp/cvs-serv29623/nmh/uip
Modified Files:
anno.c annosbr.c send.c sendsbr.c viamail.c whatnowsbr.c
Log Message:
Added an improved user interface for sending messages with attachments.
Index: anno.c
===================================================================
RCS file: /cvsroot/nmh/nmh/uip/anno.c,v
retrieving revision 1.4
retrieving revision 1.5
diff -C2 -r1.4 -r1.5
*** anno.c 2 Jul 2002 22:09:14 -0000 1.4
--- anno.c 19 Aug 2002 20:50:42 -0000 1.5
***************
*** 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.4
diff -C2 -r1.3 -r1.4
*** annosbr.c 2 Jul 2002 22:09:14 -0000 1.3
--- annosbr.c 19 Aug 2002 20:50:42 -0000 1.4
***************
*** 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: send.c
===================================================================
RCS file: /cvsroot/nmh/nmh/uip/send.c,v
retrieving revision 1.5
retrieving revision 1.6
diff -C2 -r1.5 -r1.6
*** send.c 2 Jul 2002 22:09:15 -0000 1.5
--- send.c 19 Aug 2002 20:50:42 -0000 1.6
***************
*** 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.5
diff -C2 -r1.4 -r1.5
*** sendsbr.c 2 Jul 2002 22:09:15 -0000 1.4
--- sendsbr.c 19 Aug 2002 20:50:42 -0000 1.5
***************
*** 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: viamail.c
===================================================================
RCS file: /cvsroot/nmh/nmh/uip/viamail.c,v
retrieving revision 1.7
retrieving revision 1.8
diff -C2 -r1.7 -r1.8
*** viamail.c 2 Jul 2002 22:09:15 -0000 1.7
--- viamail.c 19 Aug 2002 20:50:42 -0000 1.8
***************
*** 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.6
diff -C2 -r1.5 -r1.6
*** whatnowsbr.c 2 Jul 2002 22:09:15 -0000 1.5
--- whatnowsbr.c 19 Aug 2002 20:50:42 -0000 1.6
***************
*** 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 anno.c,1.4,1.5 annosbr.c,1.3,1.4 send.c,1.5,1.6 sendsbr.c,1.4,1.5 viamail.c,1.7,1.8 whatnowsbr.c,1.5,1.6,
Jon Steinhart <address@hidden> <=