- invo_name = r1bindex (argv[0], '/');
-
- /* read user profile/context */
- context_read();
-
- arguments = getarguments (invo_name, argc, argv, 1);
- argp = arguments;
-
- while ((cp = *argp++)) {
- 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);
- print_help (buf, switches, 1);
- done (1);
- case VERSIONSW:
- print_version(invo_name);
- done (1);
-
- case COMPSW:
- if (comp)
- adios (NULL, "only one component at a time!");
- if (!(comp = *argp++) || *comp == '-')
- adios (NULL, "missing argument to %s", argp[-2]);
- 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!");
- if (!(text = *argp++) || *text == '-')
- 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 (strcmp(*argp, "all") == 0)
- number = -1;
-
- else if (!(number = atoi(*argp)))
- adios (NULL, "missing argument to %s", argp[-2]);
-
- argp++;
- }
-
- delete = number;
- continue;
-
- case APPENDSW: /* append annotations instead of default prepend */
- append = 1;
- continue;
-
- case PRESERVESW: /* preserve access and modification times on annotated message */
- annopreserve(1);
- continue;
-
- case NOPRESERVESW: /* don't preserve access and modification times on annotated message (default) */
- annopreserve(0);
- continue;
- }
+ invo_name = mhbasename(argv[0]);
+ context_read();
+
+ arguments = getarguments(invo_name, argc, argv, 1);
+ argp = arguments;
+
+ while ((cp = *argp++)) {
+ 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);
+ print_help(buf, switches, 1);
+ done(1);
+ case VERSIONSW:
+ print_version(invo_name);
+ done(1);
+
+ case DELETESW: /* delete annotations */
+ mode = MODE_DEL;
+ continue;
+
+ case LISTSW: /* produce a listing */
+ mode = MODE_LIST;
+ continue;
+
+ case COMPSW:
+ if (comp)
+ adios(NULL, "only one component at a time!");
+ if (!(comp = *argp++) || *comp == '-')
+ adios(NULL, "missing argument to %s",
+ argp[-2]);
+ continue;
+
+ case TEXTSW:
+ if (text)
+ adios(NULL, "only one body at a time!");
+ if (!(text = *argp++) || *text == '-')
+ adios(NULL, "missing argument to %s",
+ argp[-2]);
+ continue;
+
+ case NUMBERSW: /* number listing or delete by number */
+ if (mode == MODE_ADD) {
+ adios(NULL, "-number switch must appear after -list or -delete, only.");
+ }
+ if (mode == MODE_LIST) {
+ number = 1;
+ continue;
+ }
+ /* MODE_DEL */
+ if (number) {
+ adios(NULL, "only one number at a time!");
+ }
+ if (*argp && strcmp(*argp, "all")==0) {
+ number = -1;
+ argp++;
+ continue;
+ }
+ if (!*argp || !(number = atoi(*argp))) {
+ adios(NULL, "missing argument to %s",
+ argp[-1]);
+ }
+ if (number < 0) {
+ adios(NULL, "invalid number (%d).",
+ number);
+ }
+ argp++;
+ continue;
+
+ case DATESW:
+ datesw++;
+ continue;
+ case NDATESW:
+ datesw = 0;
+ continue;
+
+ case APPENDSW:
+ append = 1;
+ continue;
+
+ case PRESERVESW:
+ preserve = 1;
+ continue;
+
+ case NOPRESERVESW:
+ preserve = 0;
+ continue;
+ }
+ }
+ if (*cp == '+' || *cp == '@') {
+ if (folder)
+ adios(NULL, "only one folder at a time!");
+ else
+ folder = getcpy(expandfol(cp));
+ } else if (*cp == '/' || *cp == '.') {
+ if (file)
+ adios(NULL, "only one file at a time!");
+ file = cp;
+ } else {
+ app_msgarg(&msgs, cp);
+ }
+ }
+
+ if (file && (folder || msgs.size)) {
+ adios(NULL, "Don't intermix files and messages.");
+ }
+ if (!datesw && !text) {
+ adios(NULL, "-nodate without -text is a no-op.");
+ }
+ if (number && text) {
+ adios(NULL, "Don't combine -number with -text.");
+ }
+
+ if (file) {
+ if (mode == MODE_LIST)
+ annolist(file, comp, number);
+ else
+ annotate(file, comp, text, datesw, number,
+ append, preserve);
+ done(0);
+ }
+
+ if (!msgs.size)
+ app_msgarg(&msgs, seq_cur);
+ if (!folder)
+ folder = getcurfol();
+ maildir = toabsdir(folder);
+
+ if (chdir(maildir) == NOTOK)
+ adios(maildir, "unable to change directory to");
+
+ /* read folder and create message structure */
+ if (!(mp = folder_read(folder)))
+ adios(NULL, "unable to read folder %s", folder);
+
+ /* check for empty folder */
+ if (mp->nummsg == 0)
+ adios(NULL, "no messages in %s", folder);
+
+ /* parse all the message ranges/sequences and set SELECTED */
+ for (msgnum = 0; msgnum < msgs.size; msgnum++)
+ if (!m_convert(mp, msgs.msgs[msgnum]))
+ done(1);
+
+ /* annotate all the SELECTED messages */
+ for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) {
+ if (is_selected(mp, msgnum)) {
+ if (mode == MODE_LIST)
+ annolist(m_name(msgnum), comp, number);
+ else
+ annotate(m_name(msgnum), comp, text, datesw,
+ number, append, preserve);
+ }
+ }
+
+ context_replace(curfolder, folder);
+ seq_setcur(mp, mp->lowsel);
+ seq_save(mp);
+ folder_free(mp);
+ context_save();
+ done(0);
+ return 1;
+}
+
+static void
+make_comp(unsigned char **ap)
+{
+ unsigned char *cp;
+ char buffer[BUFSIZ];
+
+ if (!*ap) {
+ printf("Enter component name: ");
+ fflush(stdout);
+
+ if (!fgets(buffer, sizeof buffer, stdin)) {
+ done(1);
+ }
+ *ap = trimcpy(buffer);
+ }
+
+ if ((cp = *ap + strlen(*ap) - 1) > *ap && *cp == ':')
+ *cp = '\0';
+ if (strlen(*ap) == 0)
+ adios(NULL, "null component name");
+ if (**ap == '-')
+ adios(NULL, "invalid component name %s", *ap);
+ if (strlen(*ap) >= NAMESZ)
+ adios(NULL, "too large component name %s", *ap);
+
+ for (cp = *ap; *cp; cp++)
+ if (!isalnum(*cp) && *cp != '-')
+ adios(NULL, "invalid component name %s", *ap);
+}
+
+
+/*
+** Produce a listing of all header fields (annotations) whose field
+** name matches comp. Number the listing if number is set.
+*/
+static void
+annolist(char *file, unsigned char *comp, int number)
+{
+ int c;
+ int count = 1; /* header field (annotation) counter */
+ char *cp;
+ char *field;
+ int field_size;
+ FILE *fp;
+ int length;
+ int n; /* number of bytes written */
+
+ if ((fp = fopen(file, "r")) == NULL) {
+ adios(file, "unable to open");
+ }
+
+ /* We'll grow this buffer as needed. */
+ field = (char *)mh_xmalloc(field_size = 256);
+
+ make_comp(&comp);
+ length = strlen(comp); /* Convenience copy. */
+
+ 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') {
+ ungetc(c, fp);
+ c = '\n';
+ break;
+ }
+ if (++n >= field_size - 1) {
+ field = (char *)mh_xrealloc(field,
+ field_size += 256);
+ cp = field + n - 1;
+ }
+ }
+ *cp = '\0';
+
+ if (strncasecmp(field, comp, length)==0 &&
+ field[length] == ':') {
+ for (cp = field + length + 1;
+ *cp == ' ' || *cp == '\t'; cp++) {
+ continue;
+ }
+ if (number) {
+ printf("%d\t", count++);
+ }
+ printf("%s\n", cp);
+ }
+
+ } while (*field && *field != '-');
+
+ free(field);
+ fclose(fp);
+
+ return;
+}
+
+
+static int
+annotate(char *file, unsigned char *comp, char *text, int datesw,
+ int number, int append, int preserve)
+{
+ int fd;
+ struct utimbuf b;
+ int perms, tmpfd;
+ char tmpfil[BUFSIZ];
+ struct stat st;
+ FILE *tmp;
+
+ /* open and lock the file to be annotated */
+ if ((fd = lkopen(file, O_RDWR, 0)) == NOTOK) {
+ switch (errno) {
+ case ENOENT:
+ break;
+ default:
+ admonish(file, "unable to lock and open");
+ break;
+ }
+ return 1;
+ }
+
+ if (stat(file, &st) == -1) {
+ advise("can't get access and modification times for %s", file);
+ preserve = 0;