📄 mailutil.c
字号:
/* ======================================================================== * Copyright 1988-2008 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== *//* * Program: Mail utility * * Author: Mark Crispin * UW Technology * University of Washington * Seattle, WA 98195 * Internet: MRC@Washington.EDU * * Date: 2 February 1994 * Last Edited: 19 February 2008 */#include <stdio.h>#include <errno.h>extern int errno; /* just in case */#include "c-client.h"#ifdef SYSCONFIG /* defined in env_unix.h */#include <pwd.h>#endif/* Globals */char *version = "13"; /* edit number */int debugp = NIL; /* flag saying debug */int verbosep = NIL; /* flag saying verbose */int rwcopyp = NIL; /* flag saying readwrite copy (for POP) */int kwcopyp = NIL; /* flag saying keyword copy */int ignorep = NIL; /* flag saying ignore keywords */int critical = NIL; /* flag saying in critical code */int trycreate = NIL; /* [TRYCREATE] seen */char *suffix = NIL; /* suffer merge mode suffix text */int ddelim = -1; /* destination delimiter */FILE *f = NIL;/* Usage strings */char *usage2 = "usage: %s %s\n\n%s\n";char *usage3 = "usage: %s %s %s\n\n%s\n";char *usgchk = "check [MAILBOX]";char *usgcre = "create MAILBOX";char *usgdel = "delete MAILBOX";char *usgren = "rename SOURCE DESTINATION";char *usgcpymov = "[-rw[copy]] [-kw[copy]] [-ig[nore]] SOURCE DESTINATION";char *usgappdel = "[-rw[copy]] [-kw[copy]] [-ig[nore]] SOURCE DESTINATION";char *usgprn = "prune mailbox SEARCH_CRITERIA";char *usgxfr = "transfer [-rw[copy]] [-kw[copy]] [-ig[nore]] [-m[erge] m] SOURCE DEST";#ifdef SYSCONFIGchar *stdsw = "Standard switches valid with any command:\n\t[-d[ebug]] [-v[erbose]] [-u[ser] userid] [--]";#elsechar *stdsw = "Standard switches valid with any command:\n\t[-d[ebug]] [-v[erbose]]";#endif/* Merge modes */#define mPROMPT 1#define mAPPEND 2#define mSUFFIX 3/* Function prototypes */void ms_init (STRING *s,void *data,unsigned long size);char ms_next (STRING *s);void ms_setpos (STRING *s,unsigned long i);int main (int argc,char *argv[]);SEARCHPGM *prune_criteria (char *criteria);int prune_criteria_number (unsigned long *number,char **r);int mbxcopy (MAILSTREAM *source,MAILSTREAM *dest,char *dst,int create,int del, int mode);long mm_append (MAILSTREAM *stream,void *data,char **flags,char **date, STRING **message);/* Append package */typedef struct append_package { MAILSTREAM *stream; /* source stream */ unsigned long msgno; /* current message number */ unsigned long msgmax; /* maximum message number */ char *flags; /* current flags */ char *date; /* message internal date */ STRING *message; /* stringstruct of message */} APPENDPACKAGE;/* Message string driver for message stringstructs */STRINGDRIVER mstring = { ms_init, /* initialize string structure */ ms_next, /* get next byte in string structure */ ms_setpos /* set position in string structure */};/* Initialize file string structure for file stringstruct * Accepts: string structure * pointer to message data structure * size of string */void ms_init (STRING *s,void *data,unsigned long size){ APPENDPACKAGE *md = (APPENDPACKAGE *) data; s->data = data; /* note stream/msgno and header length */ mail_fetch_header (md->stream,md->msgno,NIL,NIL,&s->data1, FT_PREFETCHTEXT|FT_PEEK);#if 0 s->size = size; /* message size */#else /* This kludge is necessary because of broken IMAP servers (sigh!) */ mail_fetch_text (md->stream,md->msgno,NIL,&s->size,FT_PEEK); s->size += s->data1; /* header + body size */#endif SETPOS (s,0);}/* Get next character from file stringstruct * Accepts: string structure * Returns: character, string structure chunk refreshed */char ms_next (STRING *s){ char c = *s->curpos++; /* get next byte */ SETPOS (s,GETPOS (s)); /* move to next chunk */ return c; /* return the byte */}/* Set string pointer position for file stringstruct * Accepts: string structure * new position */void ms_setpos (STRING *s,unsigned long i){ APPENDPACKAGE *md = (APPENDPACKAGE *) s->data; if (i < s->data1) { /* want header? */ s->chunk = mail_fetch_header (md->stream,md->msgno,NIL,NIL,NIL,FT_PEEK); s->chunksize = s->data1; /* header length */ s->offset = 0; /* offset is start of message */ } else if (i < s->size) { /* want body */ s->chunk = mail_fetch_text (md->stream,md->msgno,NIL,NIL,FT_PEEK); s->chunksize = s->size - s->data1; s->offset = s->data1; /* offset is end of header */ } else { /* off end of message */ s->chunk = NIL; /* make sure that we crack on this then */ s->chunksize = 1; /* make sure SNX cracks the right way... */ s->offset = i; } /* initial position and size */ s->curpos = s->chunk + (i -= s->offset); s->cursize = s->chunksize - i;}/* Main program */int main (int argc,char *argv[]){ MAILSTREAM *source = NIL; MAILSTREAM *dest = NIL; SEARCHPGM *criteria; char c,*s,*dp,*t,*t1,tmp[MAILTMPLEN],mbx[MAILTMPLEN]; unsigned long m,len,curlen,start,last; int i; int merge = NIL; int retcode = 1; int moreswitchp = T; char *cmd = NIL; char *src = NIL; char *dst = NIL; char *pgm = argc ? argv[0] : "mailutil";#include "linkage.c" for (i = 1; i < argc; i++) { s = argv[i]; /* pick up argument */ /* parse switches */ if (moreswitchp && (*s == '-')) { if (!strcmp (s,"-debug") || !strcmp (s,"-d")) debugp = T; else if (!strcmp (s,"-verbose") || !strcmp (s,"-v")) verbosep = T; else if (!strcmp (s,"-rwcopy") || !strcmp (s,"-rw")) rwcopyp = T; else if (!strcmp (s,"-kwcopy") || !strcmp (s,"-kw")) kwcopyp = T; else if (!strcmp (s,"-ignore") || !strcmp (s,"-ig")) ignorep = T; else if ((!strcmp (s,"-merge") || !strcmp (s,"-m")) && (++i < argc)) { if (!strcmp (s = argv[i],"prompt")) merge = mPROMPT; else if (!strcmp (s,"append")) merge = mAPPEND; else if (!strncmp (s,"suffix=",7) && s[7]) { merge = mSUFFIX; suffix = cpystr (s+7); } else { printf ("unknown merge option: %s\n",s); exit (retcode); } }#ifdef SYSCONFIG else if ((!strcmp (s,"-user") || !strcmp (s,"-u")) && (++i < argc)) { struct passwd *pw = getpwnam (s = argv[i]); if (!pw) { printf ("unknown user id: %s\n",argv[i]); exit (retcode); } else if (setuid (pw->pw_uid)) { perror ("unable to change user id"); exit (retcode); } }#endif /* -- means no more switches, so mailbox name can start with "-" */ else if ((s[1] == '-') && !s[2]) moreswitchp = NIL; else { printf ("unknown switch: %s\n",s); exit (retcode); } } else if (!cmd) cmd = s; /* first non-switch is command */ else if (!src) src = s; /* second non-switch is source */ else if (!dst) dst = s; /* third non-switch is destination */ else { printf ("unknown argument: %s\n",s); exit (retcode); } } if (kwcopyp && ignorep) { puts ("-kwcopy and -ignore are mutually exclusive"); exit (retcode); } if (!cmd) cmd = ""; /* prevent SEGV */ if (!strcmp (cmd,"check")) { /* check for new messages */ if (!src) src = "INBOX"; if (dst || merge || rwcopyp || kwcopyp || ignorep) printf (usage2,pgm,usgchk,stdsw); else if (mail_status (source = (*src == '{') ? mail_open (NIL,src,OP_HALFOPEN | (debugp ? OP_DEBUG : NIL)) : NIL, src,SA_MESSAGES | SA_RECENT | SA_UNSEEN)) retcode = 0; } else if (!strcmp (cmd,"create")) { if (!src || dst || merge || rwcopyp || kwcopyp || ignorep) printf (usage2,pgm,usgcre,stdsw); else if (mail_create (source = (*src == '{') ? mail_open (NIL,src,OP_HALFOPEN | (debugp ? OP_DEBUG : NIL)) : NIL,src)) retcode = 0; } else if (!strcmp (cmd,"delete")) { if (!src || dst || merge || rwcopyp || kwcopyp || ignorep) printf (usage2,pgm,usgdel,stdsw); else if (mail_delete (source = (*src == '{') ? mail_open (NIL,src,OP_HALFOPEN | (debugp ? OP_DEBUG : NIL)) : NIL,src)) retcode = 0; } else if (!strcmp (cmd,"rename")) { if (!src || !dst || merge || rwcopyp || kwcopyp || ignorep) printf (usage2,pgm,usgren,stdsw); else if (mail_rename (source = (*src == '{') ? mail_open (NIL,src,OP_HALFOPEN | (debugp ? OP_DEBUG : NIL)) : NIL,src,dst)) retcode = 0; } else if ((i = !strcmp (cmd,"move")) || !strcmp (cmd,"copy")) { if (!src || !dst || merge) printf (usage3,pgm,cmd,usgcpymov,stdsw); else if (source = mail_open (NIL,src,((i || rwcopyp) ? NIL : OP_READONLY) | (debugp ? OP_DEBUG : NIL))) { dest = NIL; /* open destination stream if network */ if ((*dst != '{') || (dest = mail_open (NIL,dst,OP_HALFOPEN | (debugp ? OP_DEBUG : NIL)))) { if (mbxcopy (source,dest,dst,T,i,merge)) retcode = 0; } } } else if ((i = !strcmp (cmd,"appenddelete")) || !strcmp (cmd,"append")) { if (!src || !dst || merge) printf (usage3,pgm,cmd,usgappdel,stdsw); else if (source = mail_open (NIL,src,((i || rwcopyp) ? NIL : OP_READONLY) | (debugp ? OP_DEBUG : NIL))) { dest = NIL; /* open destination stream if network */ if ((*dst != '{') || (dest = mail_open (NIL,dst,OP_HALFOPEN | (debugp ? OP_DEBUG : NIL)))) { if (mbxcopy (source,dest,dst,NIL,i,merge)) retcode = 0; } } } else if (!strcmp (cmd,"prune")) { if (!src || !dst || merge || rwcopyp || kwcopyp || ignorep || !(criteria = prune_criteria (dst))) printf (usage2,pgm,usgprn,stdsw); else if ((source = mail_open (NIL,src,(debugp ? OP_DEBUG : NIL))) && mail_search_full (source,NIL,criteria,SE_FREE)) { for (m = 1, s = t = NIL, len = start = last = 0; m <= source->nmsgs; m++) if (mail_elt (source,m)->searched) { if (s) { /* continuing a range? */ if (m == last + 1) last = m; else { /* no, end of previous range? */ if (last != start) sprintf (t,":%lu,%lu",last,m); /* no, just this message */ else sprintf (t,",%lu",m); start = last = m; /* either way, start new range */ /* running out of space? */ if ((len - (curlen = (t += strlen (t)) - s)) < 20) { fs_resize ((void **) &s,len += MAILTMPLEN); t = s + curlen; /* relocate current pointer */ } } } else { /* first time, start new buffer */ s = (char *) fs_get (len = MAILTMPLEN); sprintf (s,"%lu",start = last = m); t = s + strlen (s); /* end of buffer */ } } /* finish last range if necessary */ if (last != start) sprintf (t,":%lu",last); if (s) { /* delete/expunge any matching messages */ mail_flag (source,s,"\\Deleted",ST_SET); m = source->nmsgs; /* get number of messages before purge */ mail_expunge (source); printf ("%lu message(s) purged\n",m - source->nmsgs); fs_give ((void **) &s); /* flush buffer */ } else puts ("No matching messages, so nothing purged"); source = mail_close (source); } } else if (!strcmp (cmd,"transfer")) { if (!src || !dst) printf (usage2,pgm,usgxfr,stdsw); else if ((*src == '{') && /* open source mailbox */ !(source = mail_open (NIL,src,OP_HALFOPEN | (debugp ? OP_DEBUG : NIL)))); else if ((*dst == '{') && /* open destination server */ !(dest = mail_open (NIL,dst,OP_HALFOPEN | (debugp ? OP_DEBUG : NIL)))); else if (!(f = tmpfile ())) puts ("can't open temporary file"); else { if (verbosep) puts ("Listing mailboxes..."); if (dest) strcpy (strchr (strcpy (tmp,dest->mailbox),'}') + 1, dp = strchr (dst,'}') + 1); else { dp = dst; tmp[0] = '\0'; } mail_list (dest,tmp,""); rewind (f); /* list all mailboxes matching prefix */ if (ddelim < 0) { /* if server failed to give delimiter */ puts ("warning: unable to get destination hierarchy delimiter!"); ddelim = 0; /* default to none */ } if (source) strcpy (strchr (strcpy (tmp,source->mailbox),'}') + 1, strchr (src,'}') + 1); else strcpy (tmp,src); mail_list (source,tmp,"*"); rewind (f); /* read back mailbox names */ for (retcode = 0; !retcode && (fgets (tmp,MAILTMPLEN-1,f)); ) { if (t = strchr (tmp+1,'\n')) *t = '\0'; for (t = mbx,t1 = dest ? dest->mailbox : "",c = NIL; (c != '}') && *t1; *t++ = c= *t1++); for (t1 = dp; *t1; *t++ = *t1++); /* point to name without delim or netspec */ t1 = source ? (strchr (tmp+1,'}') + 1) : tmp + 1; /* src and mbx have different delimiters? */ if (ddelim && (ddelim != tmp[0])) while (c = *t1++) { /* swap delimiters then */ if (c == ddelim) c = tmp[0] ? tmp[0] : 'x'; else if (c == tmp[0]) c = ddelim; *t++ = c; } /* easy case */ else while (*t1) *t++ = *t1++; *t++ = '\0'; if (verbosep) { printf ("Copying %s\n => %s\n",tmp+1,mbx); fflush (stdout); } if (source = mail_open (source,tmp+1,(debugp ? OP_DEBUG : NIL) | (rwcopyp ? NIL : OP_READONLY))) { if (!mbxcopy (source,dest,mbx,T,NIL,merge)) retcode = 1; if (source->dtb->flags & DR_LOCAL) source = mail_close (source); } else printf ("can't open source mailbox %s\n",tmp+1); } } } else { printf ("%s version %s.%s\n\n",pgm,CCLIENTVERSION,version); printf (usage2,pgm,"command [switches] arguments",stdsw); printf ("\nCommands:\n %s\n",usgchk); puts (" ;; report number of messages and new messages"); printf (" %s\n",usgcre); puts (" ;; create new mailbox"); printf (" %s\n",usgdel); puts (" ;; delete existing mailbox"); printf (" %s\n",usgren); puts (" ;; rename mailbox to a new name"); printf (" copy %s\n",usgcpymov); printf (" move %s\n",usgcpymov); puts (" ;; create new mailbox and copy/move messages"); printf (" append %s\n",usgappdel); printf (" appenddelete %s\n",usgappdel); puts (" ;; copy/move messages to existing mailbox"); printf (" %s\n",usgprn); puts (" ;; prune mailbox of messages matching criteria"); printf (" %s\n",usgxfr); puts (" ;; copy source hierarchy to destination"); puts (" ;; -merge modes are prompt, append, or suffix=xxxx"); } /* close streams */ if (source) mail_close (source); if (dest) mail_close (dest); exit (retcode); return retcode; /* stupid compilers */}/* Pruning criteria, somewhat extended from mail_criteria() * Accepts: criteria * Returns: search program if parse successful, else NIL */SEARCHPGM *prune_criteria (char *criteria){ SEARCHPGM *pgm = NIL; char *criterion,*r,tmp[MAILTMPLEN]; int f; if (criteria) { /* only if criteria defined */ /* make writeable copy of criteria */ criteria = cpystr (criteria); /* for each criterion */ for (pgm = mail_newsearchpgm (), criterion = strtok_r (criteria," ",&r); criterion; (criterion = strtok_r (NIL," ",&r))) { f = NIL; /* init then scan the criterion */ switch (*ucase (criterion)) { case 'A': /* possible ALL, ANSWERED */ if (!strcmp (criterion+1,"LL")) f = T; else if (!strcmp (criterion+1,"NSWERED")) f = pgm->answered = T; break; case 'B': /* possible BCC, BEFORE, BODY */ if (!strcmp (criterion+1,"CC")) f = mail_criteria_string (&pgm->bcc,&r); else if (!strcmp (criterion+1,"EFORE")) f = mail_criteria_date (&pgm->before,&r); else if (!strcmp (criterion+1,"ODY")) f = mail_criteria_string (&pgm->body,&r); break; case 'C': /* possible CC */ if (!strcmp (criterion+1,"C")) f = mail_criteria_string (&pgm->cc,&r); break; case 'D': /* possible DELETED, DRAFT */ if (!strcmp (criterion+1,"ELETED")) f = pgm->deleted = T; else if (!strcmp (criterion+1,"RAFT")) f = pgm->draft = T; break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -