分类: LINUX
2012-06-15 16:21:23
蓝色键盘 回复于:2003-04-25 13:47:40 |
消息控制 [code:1:3e0cea3f47] #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #include #if HAVE_UNISTD_H #include #include #endif #if HAVE_FCNTL_H #include #endif #include "defs.h" #if !defined(isspace) #define isspace(ch) (((ch) > 0) && ((ch) <= ' ')) #endif /* putting globle variety here is not a good idea. But it's easy to use. * Before the implementation of any kind of thread, I think it's not real * harmful for the program */ static Head *head = NULL; static MsgObj *msgobj_extension(Mail *m); static Mail *fld_split(char *path, char *fldname, int fid, int *err, int beh); static char *glob_letter(char *, char *, char *, int , int ); static char *mail_body(Mail *m, FILE *fin, FILE *fout, char *buf, int len); static char *fill_mail_obj(Mail *m, FILE *fp, char *buf, int len); static int pine_start_cmp(char *buf); /* load specified folder and create a folder object. * path: the directory for storing these one-message-folders. e.g. /tmp * fldname: the matrix folder. Each child folder uses it as name prefix * fid: the identity allocate to the folder object. * pp: flag of postpone folder. * return: the Mail object chain or die with NULL. * Note: if the path existed, it should NOT end with path seperator, '/'. */ Folder *msg_loader(char *path, char *fldname, int fid, int pp, int beh) { Folder *fo; Mail *anchor; int rs, err; if (head == NULL) { head = head_register(HDPAGE, HDIDX); if (head == NULL) { dbgPrintf("Fail to create Head object.\n"); return NULL; } } anchor = fld_split(path, fldname, fid, &err, beh); /* Even the folder spliting failed, we still think it to available * due to null folder or zero size folder */ if ((err == PM_MSG_BADFILE) || (err == PM_MSG_BINARY)) return NULL; rs = sizeof(Folder) + strlen(fldname) + 4; if ((fo = (Folder*) malloc(rs)) == NULL) return NULL; memset(fo, 0, rs); fo->fid = fid; fo->name = fo->_namebuf; fo->cur = fo->lst = 1; fo->pp = pp; fo->mail = anchor; strcpy(fo->name, fldname); msg_statistics(fo); if (fo->num == 0) fo->cur = 0; return fo; } /* combine these seperate one-message-folders into one folder. * return: number of stored message. */ int msg_combine(Folder *fo) { FILE *fin, *fout; char buf[SVRBUF]; Mail *m; int cnt; if ((fout = fopen(fo->name, "w")) == NULL) { dbgPrintf("msg_combine: cannot write to [%s].\n", fo->name); return PM_MSG_BADFILE; } for (cnt = 0, m = fo->mail; m; m = m->next) { if (m->removed) continue; if ((fin = fopen(m->msg->name, "r")) == NULL) { dbgPrintf("msg_combine: open [%s] failed.\n", m->msg->name); continue; } if (!fo->pp && m->changed) { while (fgets(buf, SVRBUF, fin)) { if (!strncasecmp(buf, "status:", 7)) { fputs("Status: RO\n", fout); break; } else if (isblankline(buf)) { fputs("Status: RO\n\n", fout); break; } else fputs(buf, fout); } } /* large block tranfering */ dup_stream(fin, fout); /* if the message does not end with blank line ... */ fputs("\n", fout); fclose(fin); cnt++; } return cnt; } /* desconstruct the Mail object chain */ int msg_clean(Folder *fo) { Mail *tmp, *m; MsgObj *mo; m = fo->mail; while (m) { free(m->from); free(m->reply); free(m->to); free(m->cc); free(m->bcc); free(m->subject); free(m->c_type); /* free MsgObj chain and relative temprary folder. * Note that the last MsgObj is derived from Mail object, * so do not free it. */ while (m->msg->next) { mo = m->msg; if (unlink(mo->name) < 0) perror("unlink"); m->msg = m->msg->next; free(mo); } if (unlink(m->msg->name) < 0) perror("unlink"); tmp = m; m = m->next; free(tmp); } return PM_MSG_OK; } void msg_free_mailobj(Mail *m) { MsgObj *mo; free(m->from); free(m->reply); free(m->to); free(m->cc); free(m->bcc); free(m->subject); free(m->c_type); /* free MsgObj chain and relative temprary folder. * Note that the last MsgObj is derived from Mail object, * so do not free it. */ while (m->msg->next) { mo = m->msg; if (unlink(mo->name) < 0) perror("unlink"); m->msg = m->msg->next; free(mo); } if (unlink(m->msg->name) < 0) perror("unlink"); } /* search identified message. */ Mail *msg_search_id(Folder *fo, int id) { Mail *m; for (m = fo->mail; m; m = m->next) if (m->id == id) break; return m; } int msg_last_actived(Folder *fo) { Mail *m; int id; // if (fo == NULL) return 0; for (id = 0, m = fo->mail; m; m = m->next) { if (!m->removed) id = m->id; } return id; } /* dump specified message to screen * m: mail object * pager: external pager. * return: 0, success. 1, no message * Note that this function doest not check removed flag. */ int msg_dump(Mail *m, char *pager) { FILE *fp; char buf[SVRBUF]; time_t dc; #ifdef DEBUG if (!m) { dbgPrintf("msg_dump: No Mail object.\n"); return PM_MSG_INVALID; } #endif /* if (!m->oldmail) m->changed = 1; */ /* when there is no pager specified, we just display it */ if (pager == NULL) { if ((fp = fopen(m->msg->name, "r")) == NULL) return PM_MSG_BADFILE; while (fgets(buf, SVRBUF, fp)) printf("%s", buf); fclose(fp); return PM_MSG_OK; } /* or call a external pager. Note that the behavior between * more and less */ if (!strcmp(pager, "/bin/more") || !strcmp(pager, "/usr/bin/more")) { sprintf(buf, "%s %s", pager, m->msg->name); } else sprintf(buf, "cat %s | %s", m->msg->name, pager); system(buf); /* double check the time stamp of temp folder. If the pager edited * this temp folder, we should mark it as changed */ dc = filedate(m->msg->name, &m->msg->msize); if (dc > m->msg->mtime) { m->changed = 1; m->msg->mtime = dc; #ifdef DEBUG /* printf("message %d [%s] was changed.\n", m->id, m->msg->name); */ #endif } return PM_MSG_OK; } /* append a message' body to an external file */ int msg_appendto(Mail *m, char *fname) { FILE *fin, *fout; if ((fin = fopen(m->msg->name, "r")) == NULL) return PM_MSG_BADFILE; if ((fout = fopen(fname, "a")) == NULL) { dbgPrintf("msg_appendto: cannot open target file [%s]\n", fname); fclose(fin); return PM_MSG_BADFILE; } dup_stream(fin, fout); fclose(fout); fclose(fin); return PM_MSG_OK; } static MsgObj *msgobj_extension(Mail *m) { MsgObj *tmp, *tail; char buf[SVRBUF]; int len; union { void *p; unsigned short s[2]; } mixer; #ifdef DEBUG if (m == NULL) { printf("Fatal error at msgobj_extension()\n"); return NULL; } #endif mixer.p = m->msg; for (tail = m->msg; tail->next; tail = tail->next); sprintf(buf, "%s%04x", tail->name, mixer.s[0] ^ mixer.s[1]); len = sizeof(MsgObj) + strlen(buf) + 4; tmp = (MsgObj*) malloc(len); if (tmp == NULL) return NULL; memset(tmp, 0, len); tmp->name = tmp->_namebuf; strcpy(tmp->name, buf); //printf("new message folder: %s\n", tmp->name); return tmp; } int msg_edit(Mail *m, char *editor) { MsgObj *tmp; time_t dc; char buf[SVRBUF]; if (!m || !editor) return PM_MSG_INVALID; tmp = msgobj_extension(m); if (tmp == NULL) return PM_MSG_NOMEM; /* duplicate this message */ if (msg_duplicate(tmp->name, m->msg->name) <= 0) { free(tmp); return PM_MSG_BADFILE; } dc = filedate(tmp->name, &tmp->msize); sprintf(buf, "%s %s", editor, tmp->name); system(buf); tmp->mtime = filedate(tmp->name, &tmp->msize); if (tmp->mtime <= dc) { unlink(tmp->name); free(tmp); } else { m->changed = 1; tmp->next = m->msg; m->msg = tmp; } return PM_MSG_OK; } /**************************** pipe routines ***********************/ static int msg_pipe_disable(MsgObj *mo, FILE *fin, FILE *fout, char *buf, int len) { int ll = 0; while (fgets(buf, len, fin)) { if (isblankline(buf)) ll = 1; else ll = 0; fputs(buf, fout); mo->len += strlen(buf); mo->line++; } if (ll == 1) { fputs("\n", fout); mo->len++; mo->line++; } return mo->len; } static int msg_pipe_through(MsgObj *mo, FILE *fin, FILE *fout, char *sig, char *buf, int len) { char *p; int ll = 0; *buf = '>'; p = buf + 1; while (fgets(p, len - 1, fin)) { if (isblankline(buf)) ll = 1; else ll = 0; if (strncmp(p, "From ", 5)) { mo->len += strlen(p); fputs(p, fout); } else { mo->len += strlen(buf); fputs(buf, fout); } mo->line++; } if ( sig ) { mo->len += strlen(sig); fputs(sig, fout); ll = 1; } if (ll == 1) { fputs("\n", fout); mo->len++; mo->line++; } return mo->len; } static int msg_pipe_do(MsgObj *mo, FILE *fin, FILE *fout, char *piper, int ctl, char *sig, char *buf, int len) { int tsub[2], rs; char *args[128], *p; pid_t cpid; if (pipe(tsub)) return 1; if ((cpid = fork()) == -1) return 2; if (cpid == 0) { dup2(tsub[0], 0); dup2(fileno(fout), 1); close(2); open("/dev/null", O_RDWR); close(tsub[0]); close(tsub[1]); if (mkargs(piper, args, 128) < 0) exit(-1); execvp(args[0], args); exit(-2); } close(tsub[0]); *buf = '>'; p = buf + 1; while (fgets(p, len - 1, fin)) { if ( ctl && !strncmp(p, "From ", 5)) { rs = write(tsub[1], buf, strlen(buf)); } else { rs = write(tsub[1], p, strlen(p)); } if (rs < 0) { close(tsub[1]); return 2; } } if ( ctl && sig ) write(tsub[1], sig, strlen(sig)); close(tsub[1]); waitpid(cpid, NULL, 0); return 0; } static void msg_pipe_prohead(Mail *m, Head *head, char *buf, int len) { char *p; head_remove_all(head, HD_ACTION); head_remove_all(head, HD_BCC); if ((m->behave & ACT_EHEAD) != 0) { /* appending extra head */ for (p = rc_check(RCKEY_HEADER); p; p = rc_check_next()) { if (head_exist(head, p) == NULL) { /* printf("%s", p); */ sprintf(buf, "%s\n", p); head_append(head, buf); } } } if (!head_check(head, HD_MAILER)) { sprintf(buf, XMAILER, VERSION); head_append(head, buf); } } /* pipe message body through an external pipe. * The piped message will occupy a new MsgObj object, then insert it * to the top of the MsgObj chain. So the original message could be * reserved. Note that this function doesn't check removed flag. */ int msg_pipeto(Mail *m, char *piper, int ctl, char *sig) { MsgObj *tmp; FILE *fin, *fout; char buf[SVRBUF]; if (!m || !piper) return PM_MSG_INVALID; if (ctl == 1) { if (((m->behave & ACT_SUSP) != 0) || ((m->behave & ACT_NORM) == 0)) return PM_MSG_OK; } if ((m->behave & ACT_ASIG) == 0) sig = NULL; /* make up a piped folder name, then create a new MsgObj */ tmp = msgobj_extension(m); if (tmp == NULL) return PM_MSG_NOMEM; /* open the source message and the target, piped message */ if ((fin = fopen(m->msg->name, "r")) == NULL) { dbgPrintf("msg_pipeto: cannot open message folder, abort! [%s]\n", m->msg->name); free(tmp); return PM_MSG_BADFILE; } if ((fout = fopen(tmp->name, "w")) == NULL) { dbgPrintf("msg_pipeto: cannot open piped folder, abort! [%s]\n", tmp->name); free(tmp); fclose(fin); return PM_MSG_BADFILE; } /* pre-write the message head, they should not be piped to */ head_clean(head); head_of_file(head, fin, buf, SVRBUF); if ( ctl ) { msg_pipe_prohead(m, head, buf, SVRBUF); } head_dump(head, fout, 1); /* head_dump(head, stdout, 1); */ fprintf(fout, "\n"); tmp->boff = ftell(fout); fflush(fout); /* create pipe and pipe message body to it */ if (!piper || !(m->behave & ACT_PIPE)) { if ( ctl ) msg_pipe_through(tmp, fin, fout, sig, buf, SVRBUF); else msg_pipe_disable(tmp, fin, fout, buf, SVRBUF); } else { if (msg_pipe_do(tmp, fin, fout, piper, ctl, sig, buf, SVRBUF)) { dbgPrintf("msg_pipeto: pipe failed!\n"); free(tmp); fclose(fin); fclose(fout); return PM_MSG_BADPIPE; } } fclose(fin); fclose(fout); /* check the time stamp for the piped file */ if ((tmp->mtime = filedate(tmp->name, &tmp->msize)) < 0) tmp->mtime = 0; if (tmp->len == 0) tmp->len = tmp->msize - tmp->boff; /* insert piped message into message object chain */ tmp->next = m->msg; m->msg = tmp; m->changed = 1; m->piped = 1; return PM_MSG_OK; } #ifdef __NO_THAT_DEFINATION int msg_pipe2(Mail *m, char *piper, char *sig) { MsgObj *tmp; FILE *fin, *fout; char buf[SVRBUF], *p; pid_t cpid; if (!m) return PM_MSG_INVALID; if (((m->behave & ACT_SUSP) != 0) || ((m->behave & ACT_NORM) == 0)) return PM_MSG_OK; /* make up a piped folder name, then create a new MsgObj */ tmp = msgobj_extension(m); if (tmp == NULL) return PM_MSG_NOMEM; /* open the source message and the target, piped message */ if ((fin = fopen(m->msg->name, "r")) == NULL) { dbgPrintf("msg_pipe2: cannot open message folder, abort! [%s]\n", m->msg->name); free(tmp); return PM_MSG_BADFILE; } if ((fout = fopen(tmp->name, "w")) == NULL) { dbgPrintf("msg_pipe2: cannot open piped folder, abort! [%s]\n", tmp->name); free(tmp); fclose(fin); return PM_MSG_BADFILE; } /* pre-write the message head, they should not be piped to */ head_all_cache(fin, buf, SVRBUF); if (head_check(HD_ACTION) != NULL) head_remove(HD_ACTION); if (head_check(HD_BCC) != NULL) head_remove(HD_BCC); if ((m->behave & ACT_EHEAD) != 0) { /* appending extra head */ for (p = rc_check(RCKEY_HEADER); p; p = rc_check_next()) { if (head_exist(p) == NULL) head_append(p); } } if (!head_check(HD_MAILER)) { sprintf(buf, XMAILER, VERSION); head_append(buf); } head_dump(fout); head_clean_cache(); fprintf(fout, "\n"); tmp->boff = ftell(fout); fclose(fout); /* open external pipe or re-open output message folder */ if ((cpid = fork()) == -1) { perror("fork"); unlink(tmp->name); free(tmp); fclose(fin); return PM_MSG_BADPIPE; } if (cpid == 0) { /* child */ if (!piper || !(m->behave & ACT_PIPE)) { /* no pipe wanted */ fout = fopen(tmp->name, "a"); } else { /* create pipe */ sprintf(buf, "%s >> %s", piper, tmp->name); fout = popen(buf, "w"); } if (fout == NULL) { dbgPrintf("msg_pipe2: open external pipe failed.\n"); exit(-1); } *buf = '>'; p = buf + 1; while (fgets(p, SVRBUF - 1, fin)) { if (strncmp(p, "From ", 5)) tmp->len += fprintf(fout, "%s", p); else tmp->len += fprintf(fout, "%s", buf); tmp->line++; } if ((m->behave & ACT_ASIG) && sig) { tmp->len += fprintf(fout, "%s", sig); } if (!piper || !(m->behave & ACT_PIPE)) fclose(fout); else pclose(fout); exit(0); } waitpid(cpid, NULL, 0); fclose(fin); if ((tmp->mtime = filedate(tmp->name, &tmp->msize)) < 0) tmp->mtime = 0; /* insert piped message into message object chain */ tmp->next = m->msg; m->msg = tmp; m->changed = 1; m->piped = 1; return PM_MSG_OK; } #endif /* undo a pipe message chain. * pick out the toppest message from the MsgObj chain. If there is only * one MsgObj existed, do not touch it: it's original message. */ int msg_unpipe(Mail *m) { MsgObj *tmp; if (!m || !m->msg->next) return PM_MSG_INVALID; tmp = m->msg; m->msg = m->msg->next; if (unlink(tmp->name) < 0) perror("unlink"); free(tmp); if (m->msg->next == NULL) m->piped = 0; return PM_MSG_OK; } /* get message statistics data. Do not use this function often. It checks * file status by stat(2) system call. */ void msg_statistics(Folder *fo) { Mail *m; fo->num = fo->chg = fo->rm = fo->unrd = 0; for (m = fo->mail ; m; m = m->next) { if (m->removed) fo->rm++; if (!m->changed && !m->oldmail) fo->unrd++; if (m->changed || m->piped) fo->chg++; else if (m->msg->mtime < filedate(m->msg->name, &m->msg->msize)) { fo->chg++; } fo->num++; } } /* check if there is a chenged message in the message chain. This function do not check the time stamp of message folder. */ int msg_change_flag(Folder *fo) { Mail *m; for (m = fo->mail; m; m = m->next) { if (m->removed || m->changed || m->piped) return 1; } return 0; } /* pick out a specified Mail object from message chain. * This is useful when move a message from one chain to another. * The message will be absolutely removed, no chance to undo. * Note that the removed message cannot be picked up. */ Mail *msg_pickout(Folder *fo, int id) { Mail anchor, *m; #ifdef DEBUG if (fo == NULL) { printf("msg_pickout: invaild pointer.\n"); return NULL; } #endif anchor.id = id + 1; anchor.next = fo->mail; for (m = & m->next; m = m->next) { if (m->next->id == id) break; } if (!m->next || m->next->removed) return NULL; anchor.next = m->next; if (m->next == fo->mail) fo->mail = fo->mail->next; else m->next = m->next->next; #ifdef DEBUG if (anchor.next->id != id) { printf("!!!!!!!!!!!!!!!!!!!!!\n"); anchor.next = NULL; } #endif fo->fchg = 1; fo->num--; if (!anchor.next->oldmail) fo->unrd--; return anchor.next; } /* the opposite operation of msg_pickout(). * Insert a message object at the end of message chain. */ void msg_insert(Folder *fo, Mail *m) { Mail *k; int mid = 0; if (fo->mail == NULL) fo->mail = m; else { for (k = fo->mail; k->next; k = k->next); k->next = m; mid = k->id; } m->id = mid + 1; m->next = NULL; fo->fchg = 1; if (!m->oldmail) fo->unrd++; if (m->removed) fo->rm++; else fo->num++; } /* expand an element in the tail of the specified message chain. * It creates a null Mail object except the id and MsgObj with * relatively folder name, but no message created. * This function is used to reply or follow a message */ Mail *msg_expand(Folder *fo, char *path, Mail *ins) { Mail *m, *k; int len, mid = 0; #ifdef DEBUG if (fo == NULL) { printf("msg_expand\n"); return NULL; } #endif /* search for last message and its id number */ for (m = fo->mail; m && m->next; m = m->next); if (m) mid = m->id + 1; else mid = 1; /* create a new Mail object */ len = sizeof(Mail) + strlen(fo->name) + (sizeof(int) << 2) + 4; if (path) len += strlen(path); if ((k = (Mail*) malloc(len)) == NULL) return NULL; memset(k, 0, len); k->id = mid; k->msg = k->_msgbuf; k->msg->name = k->msg->_namebuf; glob_letter(k->msg->name, path, fo->name, fo->fid, k->id); /* insert it at the end of message chain */ if (m == NULL) fo->mail = k, fo->cur = 1; else m->next = k; if (ins) msg_dup_entry(k, ins); if (k->removed) fo->rm++; else fo->num++; if (!k->oldmail) fo->unrd++; fo->fchg = 1; return k; } /* duplicate a message entry to another Mail object These items are NOT duplicated: id, flags, link to next object, MsgObjs out of first one, and the name of folder in the MsgObj. */ void msg_dup_entry(Mail *dest, Mail *sour) { dest->removed = sour->removed; dest->changed = sour->changed; dest->oldmail = sour->oldmail; dest->replied = sour->replied; dest->from = dup_str(sour->from); dest->reply = dup_str(sour->reply); dest->to = dup_str(sour->to); dest->cc = dup_str(sour->cc); dest->bcc = dup_str(sour->bcc); dest->subject = dup_str(sour->subject); dest->c_type = dup_str(sour->c_type); dest->rtime = sour->rtime; dest->behave = sour->behave; /* I don't duplicate the folder, just make a hard link to it if (link(sour->msg->name, dest->msg->name) < 0) perror("link"); */ msg_duplicate(dest->msg->name, sour->msg->name); dest->msg->mtime = filedate(dest->msg->name, &dest->msg->msize); dest->msg->len = sour->msg->len; dest->msg->line = sour->msg->line; dest->msg->boff = sour->msg->boff; } long msg_duplicate(char *dest, char *sour) { FILE *fin, *fout; long len = 0; if ((fin = fopen(sour, "r")) == NULL) { dbgPrintf("Cannot open message folder! [%s]\n", sour); return -1; } if ((fout = fopen(dest, "w")) == NULL) { dbgPrintf("Cannot open target folder! [%s]\n", dest); fclose(fin); return -1; } len += dup_stream(fin, fout); fclose(fout); fclose(fin); return len; } /* BUGS: it modifies the original string that contains behavior line */ int msg_behave_bind(char *s) { char *idx[16]; int i, num, rs; num = ziptoken(s, idx, 16, DELIMS); for (rs = i = 0; i < num; i++) { if (!strcasecmp(idx[i], "default")) { rs = ACT_DEFT; break; } } for (i = 0; i < num; i++) { if (!strcasecmp(idx[i], "pipe")) rs |= ACT_PIPE; else if (!strcasecmp(idx[i], "sign")) rs |= ACT_ASIG; else if (!strcasecmp(idx[i], "exhd")) rs |= ACT_EHEAD; else if (!strcasecmp(idx[i], "dele")) rs |= ACT_DELE; else if (!strcasecmp(idx[i], "bkup")) rs |= ACT_BACK; else if (!strcasecmp(idx[i], "suspd")) rs |= ACT_SUSP; else if (!strcasecmp(idx[i], "pure")) rs &= ~ACT_NORM; else if (!strcasecmp(idx[i], "hold")) rs &= ~ACT_SMTP; else if (!strcasecmp(idx[i], "unpipe")) rs &= ~ACT_PIPE; else if (!strcasecmp(idx[i], "nopipe")) rs &= ~ACT_PIPE; else if (!strcasecmp(idx[i], "unsign")) rs &= ~ACT_ASIG; else if (!strcasecmp(idx[i], "nosign")) rs &= ~ACT_ASIG; else if (!strcasecmp(idx[i], "unexhd")) rs &= ~ACT_EHEAD; else if (!strcasecmp(idx[i], "noexhd")) rs &= ~ACT_EHEAD; } return rs; } /* split the message folder into a series of one-message-folder. * path: the directory for storing these one-message-folders. e.g. /tmp * fldname: the matrix folder. Each child folder uses it as name prefix * return: the Mail object chain or die with NULL. * Note: if the path existed, it should NOT end with path seperator, '/'. */ static Mail *fld_split(char *path, char *fldname, int fid, int *err, int beh) { FILE *fp; char buf[SVRBUF]; Mail *anchor, *tmp, *m; int i, rs, ch, id, len; if ((fp = fopen(fldname, "r")) == NULL) { if (errno == ENOENT) *err = PM_MSG_NOFILE; else *err = PM_MSG_BADFILE; return NULL; } /* double check is this a binary file */ if ((rs = fread(buf, 1, SVRBUF, fp)) < 0) { *err = PM_MSG_BADFILE; return NULL; } for (i = 0; i < rs; i++) { if (!isspace(buf[i]) && (buf[i] < ' ') && (buf[i] >= 0)) { // printf("%c %d\n", buf[i], buf[i]); *err = PM_MSG_BINARY; return NULL; } } rewind(fp); buf[0] = 0; id = ch = 0; anchor = NULL; while (!feof(fp)) { while (!ismailstart(buf)) { if (!isblankline(buf)) ch++; /* counte non-message line */ if (!fgets(buf, SVRBUF, fp)) goto load_ok; } /* create a Mail object */ /* the size of Mail object should be larger than it used to * due to the filename in the MsgObj */ len = sizeof(Mail) + strlen(fldname) + (sizeof(int) << 2) + 4; if (path) len += strlen(path); if ((tmp = (Mail*) malloc(len)) == NULL) break; memset(tmp, 0, len); tmp->id = ++id; tmp->msg = tmp->_msgbuf; tmp->behave = beh; tmp->msg->name = tmp->msg->_namebuf; glob_letter(tmp->msg->name, path, fldname, fid, tmp->id); /* If this is anchor message of Pine, mark it as SUSPENDED */ if (!pine_start_cmp(buf)) tmp->behave = ACT_SUSP; /* insert it into Mail object chain */ if (anchor == NULL) anchor = tmp; else { for (m = anchor; m->next; m = (Mail*) m->next); m->next = (void*) tmp; } fill_mail_obj(tmp, fp, buf, SVRBUF); } load_ok: fclose(fp); if ((id == 0) && (ch > 0)) { /* it's not a message folder */ *err = PM_MSG_BADFILE; return NULL; } *err = PM_MSG_OK; return anchor; } /* create a uniqe message folder name according to mailbox name. * path: target temprary directory for storing messages * fldname: folder name * fid: the uniqe folder identity * id: the message series number */ static char *glob_letter(char *buf, char *path, char *fldname, int fid, int id) { int i; char *p; p = fldname; for (i = strlen(fldname); i >= 0; i--) { if (fldname[i] == PATHSEP) { p = &fldname[i] + 1; break; } } if (path) { sprintf(buf, "%s%c%s%03d_%04x", path, PATHSEP, p, fid, id); } else { sprintf(buf, "%s%03d_%04x", p, fid, id); } // printf("glob: %s\n", buf); return buf; } /* duplicate the message body. * The stream pointer shoud have been on the right position. * This routine do some extra works: skip blank lines between message * head and message body, and appand one blank line on the end of message * body while there is not. */ static char *mail_body(Mail *m, FILE *fin, FILE *fout, char *buf, int len) { int bflag = 0; /* skip leading blank lines */ while (!feof(fin)) { if (ismailstart(buf)) break; if (!isblankline(buf)) break; fgets(buf, len, fin); } /* duplicate message body */ while (!feof(fin)) { if (ismailstart(buf)) break; if (isblankline(buf)) bflag = 1; else bflag = 0; m->msg->len += fprintf(fout, "%s", buf); fgets(buf, len, fin); m->msg->line++; } /* appand a blank line while there is not; for some MUA will mess up * when the message body hit the head of next message */ if (bflag == 0) fprintf(fout, "\n"); return buf; } /* accomplish the message object and create its relatively * temporary folder. Note that there is the last line it read in 'buf' * when it returns. */ static char *fill_mail_obj(Mail *m, FILE *fp, char *buf, int len) { FILE *fout; HLin *hl; char *p; if ((fout = fopen(m->msg->name, "w")) == NULL) { /* when failed by creating temporary folder, it cleans * the FromSps line from caller for avoiding dead loop */ buf[0] = 0; return NULL; } /* process the FromSps line. We just take care of date segment */ for (p = buf + 4; isspace(*p); p++); /* move to date segment */ p = strchr(p, ' '); for (p++; isspace(*p); p++); /* printf("date: %s\n", p);*/ if ((m->rtime = strtimet(p)) < 0) m->rtime = 0; /* to cache the heads */ head_clean(head); head_to_cache(head, fp, buf, len); /* fill up the mail object */ if (!m->from) { hl = head_check(head, HD_FROM); if (hl == NULL) hl = head_check(head, HD_SENDER); if (hl == NULL) hl = head_check(head, HD_RPLTO); if (hl == NULL) m->from = dup_str("<>"); else { m->from = head_fetch_body(hl); decode_head(m->from, 2); } } if (!m->reply) { hl = head_check(head, HD_RPLTO); if (hl == NULL) m->reply = dup_str(m->from); else { m->reply = head_fetch_body(hl); decode_head(m->reply, 2); } } if (!m->to && (hl = head_check(head, HD_TO)) != NULL) { m->to = head_fetch_body(hl); decode_head(m->to, 2); } if (!m->cc && (hl = head_check(head, HD_CC)) != NULL) { m->cc = head_fetch_body(hl); } if (!m->bcc && (hl = head_check(head, HD_BCC)) != NULL) { m->bcc = head_fetch_body(hl); } if (!m->subject && (hl = head_check(head, HD_SUBJECT)) != NULL) { m->subject = head_fetch_body(hl); decode_head(m->subject, 2); compress_space(m->subject); } if (!m->c_type && (hl = head_check(head, HD_CTTYPE)) != NULL) { m->c_type = head_fetch_body(hl); } if ((hl = head_check(head, HD_CTENCODE)) != NULL) { for (p = hl->body; isspace(*p); p++); if (*p == '"') p++; if (!strncasecmp(p, "7bit", 4)) m->c_encode = CTE_7BIT; else if (!strncasecmp(p, "quoted-printable", 16)) m->c_encode = CTE_QP; else if (!strncasecmp(p, "base64", 6)) m->c_encode = CTE_BASE64; else if (!strncasecmp(p, "8bit", 4)) m->c_encode = CTE_8BIT; else if (!strncasecmp(p, "binary", 6)) m->c_encode = CTE_BINARY; } if (!m->rtime && (hl = head_check(head, HD_DATE)) != NULL) { if ((m->rtime = strtimet(hl->body)) < 0) m->rtime = 0; } if ((hl = head_check(head, HD_STATUS)) != NULL) { if ((*hl->body == 'O') || (*hl->body == 'R')) m->oldmail = 1; } if ((hl = head_check(head, HD_ACTION)) != NULL) { m->behave = msg_behave_bind(hl->body); head_remove_all(head, HD_ACTION); } head_dump(head, fout, 1); /* set body offset */ fprintf(fout, "\n"); m->msg->boff = ftell(fout); /* duplicate mail body */ mail_body(m, fp, fout, buf, len); fclose(fout); /* record the last modification time of temporary folder */ if ((m->msg->mtime = filedate(m->msg->name, &m->msg->msize)) < 0) m->msg->mtime = 0; // printf("id: %d\n", m->id); // printf("letter: %s\n", m->msg->name); // printf("from: %s\n", m->from); // printf("cc: %s\n", m->cc); // printf("bcc: %s\n", m->bcc); // printf("To: %s\n", m->to); // printf("reply: %s\n", m->reply); // printf("subject: %s\n", m->subject); // printf("c_type: %s\n", m->c_type); // printf("date: %s\n", ctime(&m->rtime)); // printf("lines: %d\n", m->msg->line); // printf("bodyoff: %ld\n", m->msg->boff); // printf("length: %d\n\n", m->msg->len); #ifdef DEBUG /* printf("message %s loaded (%d bytes): %s\n", m->msg->name, m->msg->line, m->from);*/ #endif return buf; } static int pine_start_cmp(char *buf) { char *pinemark = "MAILER-DAEMON"; return strncmp(buf + 5, pinemark, strlen(pinemark)); } [/code:1:3e0cea3f47] |
蓝色键盘 回复于:2003-04-25 14:02:57 |
gmail.c [code:1:2e2f71b2d0] #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #if HAVE_UNISTD_H #include #include #endif #if HAVE_SYS_IOCTL_H #include #endif #include "defs.h" #include "gmail.h" static GMAIL *gmail; static struct gm_att *attr; static GMAIL *gmail_create(char *s); static int gmail_set_protocal(char *s); static Slnk *gmail_set_spam(char *mark); #ifdef DEBUG static void gmail_dump_att(); static void gmail_dump(GMAIL *gm); #endif static Slnk *slnk_alloc(); static Slnk *spam_link_append(Slnk *anch, int id); static int sk_id(Spam *sc, char *p); static int sk_size(Spam *sc, char *p); static int sk_from(Spam *sc, char *p); static int sk_subject(Spam *sc, char *p); static int sk_action(Spam *sc, char *p); int gmail_single(GMAIL *gm, Head *head) { int rs = 0; switch (gm->protl) { case GP_POP3: case GP_APOP: rs = pop3_main(gm, head); break; } return rs; } int gmail_main(GMAIL *gm, Head *head) { //gmail_dump_att(); while (gm) { //gmail_dump(gm); gmail_single(gm, head); gm = gm->next; } return OK; } /* This function is used to create all necessary server objects for accessing * these servers. The server objects should be chained and start with 'gmail'. * Because there is a common structure gm_attr, it fills up this structure * first, then creates echo server object according to the 'fetch' option in * the configure file. All server objects will be chained at last with the * order of first-appear-first-in. */ GMAIL *gmail_open() { GMAIL *gm, *gtmp; struct winsize ws; char *p, *idx[3], buf[SVRBUF]; int i, rs; /* if no default mailbox specified, we use 'mbox' in the current dir */ if ((p = rc_check(RCKEY_MBOX)) == NULL) strcpy(buf, HOMEBOX); else fullpath(p, buf); /* There are three items which need extra space: cmd_auth, defbox and * headmask. The plan is to combine the defbox and cmd_auth, then to * append the headmask buffer at the tail of the combination. Therefore * these is a pointer, named hdbuf, that points to the start position of * the headmask buffer. */ if (cmd_auth) rs = strlen(cmd_auth) + strlen(buf); else rs = strlen(buf); if ((p = rc_check(RCKEY_HEADMASK)) == NULL) rs += strlen(HMDEF); else rs += strlen(p); rs += sizeof(struct gm_att) + 5; if ((attr = malloc(rs)) == NULL) return NULL; memset(attr, 0, rs); /* the extra space starts with 'buf' in the gm_att structure. we * concatenate defbox and cmd_auth first and then split them */ strcpy(attr->buf, buf); if (cmd_auth) { strcat(attr->buf, ":"); strcat(attr->buf, cmd_auth); } attr->hdbuf = attr->buf + strlen(attr->buf) + 1; if (p == NULL) strcpy(attr->hdbuf, HMDEF); else strcpy(attr->hdbuf, p); ziptoken(attr->hdbuf, attr->hdmsk, HMMAX, ":"); rs = fixtoken(attr->buf, idx, 3, ":"); for (i = 0; i < rs; i++) { if (!strcmp(idx[i], "*")) idx[i] = NULL; else if (!strcmp(idx[i], "\\*")) idx[i]++; } attr->defbox = idx[0]; attr->user = idx[1]; attr->pass = idx[2]; attr->act = cmd_action; attr->cp_set = cmd_cp_set; attr->mbox = cmd_mbox; if ((p = rc_check(RCKEY_TOPSLY)) != NULL) { StrnCpy(buf, p, SVRBUF); ziptoken(buf, idx, 2, DELIMS); if (idx[0]) { if (!strcmp(idx[0], "smart")) attr->tops = TOP_SMART; else if (!strcmp(idx[0], "all")) attr->tops = TOP_ALL; else if (!strcmp(idx[0], "brief")) attr->tops = TOP_BRIEF; } if (idx[1]) attr->topl = atonum(idx[1]); else attr->topl = 0; } if ((p = rc_check(RCKEY_LDELAY)) != NULL) attr->delay = atoi(p); if (ioctl(1, TIOCGWINSZ, (char *) &ws) >= 0) attr->cols = ws.ws_col; else { attr->cols = atoi(getenv("COLUMNS")); if (attr->cols == 0) attr->cols = 80; } spam_queue_open(); /* now creates the chain of server objects according to the relative * options in the configure file */ for (p = rc_check(RCKEY_FETCH); p; p = rc_check_next()) { gm = gmail_create(p); if (gmail == NULL) gmail = gm; else { for (gtmp = gmail; gtmp->next; gtmp = gtmp->next); gtmp->next = gm; } } return gmail; } /* This function is used to insert an extra server object into the server * object chain. The argument, arg, comes from command line, usually by * -h option. Although it has the same form as the 'fetch' option in the * configure file, the 'arg' often appears just a server address. * NOTE that, if it is given with the form of "@number", such as "@2", * it does not mean to create and insert a server object but to choose a * server object that has been created already in the chain with the series * number of 'number', in this case it's 2. */ GMAIL *gmail_cmdarg(char *arg) { GMAIL *gm; int i, rs; if (*arg == '@') { rs = atoi(arg + 1); for (i = 1, gm = gmail; gm; i++, gm = gm->next) { if (i == rs) return gm; } } else { gm = gmail_create(arg); if (gm != NULL) { gm->next = gmail; gmail = gm; } } return gm; } void gmail_close() { GMAIL *gm, *tmp; for (gm = gmail; gm; ) { free(gm->time_stamp); free(gm->mlist); if (gm->socket) close(gm->socket); if (gm->fp) fclose(gm->fp); tmp = gm; gm = gm->next; free(tmp); } spam_queue_free(); if (attr) free(attr); attr = NULL; gmail = NULL; } void gmail_host_list() { GMAIL *gm; char buf[SVRBUF]; int i; conPrintf("Post offices list:\n"); for (i = 1, gm = gmail; gm; gm = gm->next, i++) { ssprintf(buf, SVRBUF, "%4d %-25s %-25s %s:%s\n", i, gm->host, gm->mbox, gm->lid, gm->pass); conPrintf(buf); } conPrintf("\n"); } int gmail_set_action(char *s) { int rs = 0; switch (*s) { case 'c': break; case 't': /* for TOP */ case 'l': rs |= GMAIL_LIST; break; case 'd': rs |= GMAIL_FETCH | GMAIL_DELE; break; case 'f': rs |= GMAIL_FETCH; break; case 'r': rs |= GMAIL_DELE; break; } return rs; } /* host.name:protocol:operation:spam:mailbox:id:passwd */ static GMAIL *gmail_create(char *s) { GMAIL *gm; char *idx[16]; int i, rs; if (s == NULL) return NULL; /* becase the mailbox item is expanding to absolute path, I have to * increase another space about 256 bytes for it */ rs = strlen(s) + sizeof(GMAIL) + PATHMAX + 2; if ((gm = malloc(rs)) == NULL) return NULL; memset(gm, 0, rs); gm->attr = attr; gm->mbox = gm->buf; strcpy(gm->buf + PATHMAX + 1, s); rs = fixtoken(gm->buf + PATHMAX + 1, idx, 16, ":"); for (i = 0; i < rs; i++) { if (!strcmp(idx[i], "*")) idx[i] = NULL; else if (!strcmp(idx[i], "\\*")) idx[i]++; } if (cmd_host && *cmd_host != '@' && !isblankline(cmd_host)) gm->host = cmd_host; else if (idx[0] && !isblankline(idx[0])) gm->host = idx[0]; else { free(gm); return NULL; } gm->host = idx[0]; /* specified the protocal to access server, POP3 is default */ if (idx[1]) gm->protl = gmail_set_protocal(idx[1]); if (gm->protl == 0) gm->protl = GP_POP3; /* command line specified action could override the predefined one */ if (idx[2]) gm->act = gmail_set_action(idx[2]); if (attr->act != ID_NULL) gm->act = attr->act; if (idx[3]) gm->slnk = gmail_set_spam(idx[3]); gm->topspam = spam_need_top(gm->slnk); /* mailbox: command line specified > predefined > default */ if (attr->mbox) gm->mbox = attr->mbox; /* should be expanded */ else if (idx[4] && !isblankline(idx[4])) fullpath(idx[4], gm->mbox); else gm->mbox = attr->defbox; if (attr->user) gm->lid = attr->user; else gm->lid = idx[5]; if (attr->pass) gm->pass = attr->pass; else gm->pass = idx[6]; return gm; } static int gmail_set_protocal(char *s) { if (!strcasecmp(s, "pop3")) return GP_POP3; else if (!strcasecmp(s, "apop")) return GP_APOP; return 0; } static Slnk *gmail_set_spam(char *mark) { Slnk *anch = NULL; char buf[128], *idx[32]; /* this buffer might be overflow attacked */ int i, id; if ((*mark == 'y') || (*mark == 'Y')) { anch = spam_link_append(anch, 0); } else if ((*mark != 'n') && (*mark != 'N')) { StrnCpy(buf, mark, sizeof(buf)); ziptoken(buf, idx, 32, ","); for (i = 0; idx[i]; i++) { id = atoi(idx[i]); anch = spam_link_append(anch, id); } } return anch; } /********************** process spam routine ********************/ static Spam *spam; static Slnk slnk[SLPOOL]; static int slidx = 0; static Slnk *slnk_alloc() { if (slidx >= SLPOOL) return NULL; slidx++; return &slnk[slidx - 1]; } /* static char *strcasestr(const char *haystack, const char *needle) { char *p; int nlen; if (!needle || !haystack) return (char*) haystack; nlen = strlen(needle); for (p = (char*) haystack; *p; p++) { if (!strncasecmp(p, (char *) needle, nlen)) return p; } return NULL; } */ static Slnk *spam_link_append(Slnk *anch, int id) { Spam *sc; Slnk *sl; for (sc = spam; sc; sc = sc->next) { if (sc->id == id) { if ((sl = slnk_alloc()) == NULL) break; sl->sc = sc; sl->next = anch; anch = sl; } } return anch; } /***************************************************************** * spam_check_xxxx() and spam_regex_xxxx() * return: * 0: nothing matched; * 1: matched something **/ static char *allfrom[] = { "from", "reply", "sender", NULL }; /* static int spam_check_from(Head *head, char *from) { struct head_chain *hc; HLin *hl; int i, rs; for (i = rs = 0; allfrom[i]; i++) { if ((hl = head_check(head, allfrom[i])) != NULL) { if (strcasestr(hl->body, from)) rs++; for (hc = hl->hc; !rs && hc; hc = hc->next) { if (strcasestr(hc->str, from)) rs++; } } if (rs) break; } return rs; } static int spam_check_subject(Head *head, char *subject) { struct head_chain *hc; HLin *hl; int rs = 0; if ((hl = head_check(head, "subject")) != NULL) { if (strcasestr(hl->body, subject)) rs++; for (hc = hl->hc; !rs && hc; hc = hc->next) { if (strcasestr(hc->str, subject)) rs++; } } return rs; } */ static int spam_regex_from(Head *head, regex_t *from) { regmatch_t pmatch[1]; struct head_chain *hc; HLin *hl; int i, rs; for (i = rs = 0; allfrom[i]; i++) { if ((hl = head_check(head, allfrom[i])) != NULL) { if (!regexec(from, hl->body, 1, pmatch, 0)) rs++; for (hc = hl->hc; !rs && hc; hc = hc->next) { if (!regexec(from, hc->str, 1, pmatch, 0)) rs++; } } if (rs) break; } return rs; } static int spam_regex_subject(Head *head, regex_t *subject) { regmatch_t pmatch[1]; struct head_chain *hc; HLin *hl; int rs = 0; if ((hl = head_check(head, "subject")) != NULL) { if (!regexec(subject, hl->body, 1, pmatch, 0)) rs++; for (hc = hl->hc; !rs && hc; hc = hc->next) { if (!regexec(subject, hc->str, 1, pmatch, 0)) rs++; } } return rs; } /* 1 spam message, 0 good message */ static int spam_cmp(Spam *sc, Head *head, int msize) { if (!sc || !head) return 0; if (sc->quota && (msize < sc->quota)) goto trigr; if (sc->from_reg) { if (spam_regex_from(head, sc->from_reg) == 0) goto trigr; } if (sc->sub_reg) { if (spam_regex_subject(head, sc->sub_reg) == 0) goto trigr; } /* if acknowleged all tests ... */ if (sc->logic == 0) return 1; else return 0; trigr: /* any one unmatch */ return sc->logic; } Spam *spam_match_chain(Slnk *sl, Head *head, int msize) { while (sl) { if (spam_cmp(sl->sc, head, msize)) return sl->sc; sl = sl->next; } return NULL; } /* this funtion is used to check spam mails by their size only */ Spam *spam_match_size(Slnk *sl, int size) { Spam *sc; while (sl) { sc = sl->sc; if (!sc->quota || sc->from_reg || sc->sub_reg) continue; if (size > sc->quota) { if (sc->logic == 0) return sc; } else { if (sc->logic != 0) return sc; } sl = sl->next; } return NULL; } int spam_need_top(Slnk *sl) { int rs = 0; while (sl) { if (sl->sc->from_reg || sl->sc->sub_reg) rs++; sl = sl->next; } return rs; } /**********************************************************************/ static int sk_id(Spam *sc, char *p) { sc->id = atoi(p); return 0; /* this is identity, not an entry. so count free */ } static int sk_size(Spam *sc, char *p) { sc->quota = atonum(p); return 1; } static int sk_from(Spam *sc, char *p) { if (isblankline(p)) return 0; sc->from = dup_str(p); sc->from_reg = &sc->preg[sc->ireg]; if (regcomp(sc->from_reg, p, REG_EXTENDED | REG_ICASE)) { dbgPrintf("sk_from: cannot compile filter pattern.\n"); sc->from_reg = NULL; } else sc->ireg++; return 1; } static int sk_subject(Spam *sc, char *p) { if (isblankline(p)) return 0; sc->subject = dup_str(p); sc->sub_reg = &sc->preg[sc->ireg]; if (regcomp(sc->sub_reg, p, REG_EXTENDED | REG_ICASE)) { dbgPrintf("sk_subject: cannot compile filter pattern.\n"); sc->sub_reg = NULL; } else sc->ireg++; return 1; } static int sk_action(Spam *sc, char *p) { sc->logic = 0; if (!strcasecmp(p, SA_YES_DELE)) sc->action = SPAM_DELE; else if (!strcasecmp(p, SA_YES_KEEP)) sc->action = SPAM_KEEP; else if (!strcasecmp(p, SA_YES_ASK)) sc->action = SPAM_ASK; else if (!strcasecmp(p, SA_NO_DELE)) sc->action = SPAM_DELE, sc->logic = 1; else if (!strcasecmp(p, SA_NO_KEEP)) sc->action = SPAM_KEEP, sc->logic = 1; else if (!strcasecmp(p, SA_NO_ASK)) sc->action = SPAM_ASK, sc->logic = 1; return 0; /* action is count free either */ } static struct spam_func { char *key; int (*func)(Spam *sc, char *p); /* successed: 1, fail: 0 */ } sf[] = { { SK_ID, sk_id }, { SK_SIZE, sk_size }, { SK_FROM, sk_from }, { SK_SUBJECT, sk_subject }, { SK_ACTION, sk_action }, { NULL, NULL } }; Spam *spam_queue_open() { Spam *sc; char *p, *s, *tmp = NULL, *idx[16]; int rs, i, k, cnt; #ifdef DEBUG if (spam) { printf("spam queue has existed.\n"); return NULL; } #endif for (p = rc_check(RCKEY_SPAM); p; p = rc_check_next()) { p += strlen(p) + 1; /* move to extension part */ //puts(p); tmp = dup_str(p); if (tmp == NULL) break; rs = ziptoken(tmp, idx, 16, "#"); if ((sc = malloc(sizeof(Spam))) == NULL) { free(tmp); break; } memset(sc, 0, sizeof(Spam)); for (cnt = 0, i = 1; i < rs - 1; i++) { for (k = 0; sf[k].key; k++) { if (!strncasecmp(idx[i], sf[k].key, strlen(sf[k].key))) { s = skip_space(idx[i] + strlen(sf[k].key)); cnt += sf[k].func(sc, s); break; } } } if (cnt == 0) free(sc); else if (spam == NULL) spam = sc; else { sc->next = spam; spam = sc; } free(tmp); } return spam; } void spam_queue_free() { Spam *tmp, *sc; sc = spam; while (sc) { tmp = sc; sc = sc->next; if (tmp->from_reg) regfree(tmp->from_reg); if (tmp->sub_reg) regfree(tmp->sub_reg); free(tmp->from); free(tmp->subject); free(tmp); } } #ifdef DEBUG static void gmail_dump_att() { int i = 0; printf("Top lines: %d\n", attr->topl); printf("Top style: %d\n", attr->tops); // printf("quota: %d\n", attr->quota); printf("login delay: %d\n", attr->delay); printf("screen cols: %d\n", attr->cols); printf("deft action: %d\n", attr->act); printf("set mbox: %s\n", attr->mbox); printf("deft mbox: %s\n", attr->defbox); printf("set user: %s\n", attr->user); printf("set pass: %s\n", attr->pass); printf("cp_set: "); for (i = 0; attr->cp_set && attr->cp_set[i]; i++) printf("%d,", attr->cp_set[i]); printf("\n"); printf("headmask: "); for (i = 0; attr->hdmsk[i]; i++) printf("%s ", attr->hdmsk[i]); printf("\n\n"); } static void gmail_dump(GMAIL *gm) { Slnk *sl; printf("GMAIL object %p\n", gm); printf("Remote host: %s\n", gm->host); printf("login id: %s\n", gm->lid); printf("login pass: %s\n", gm->pass); printf("set mbox: %s\n", gm->mbox); printf("set action: %d\n", gm->act); printf("protocol: %d\n", gm->protl); printf("topspam: %d\n", gm->topspam); for (sl = gm->slnk; sl; sl = sl->next) { printf("spam id: %d\n", sl->sc->id); printf(" quota: %d\n", sl->sc->quota); printf(" from: %s\n", sl->sc->from); printf(" subject: %s\n", sl->sc->subject); printf(" logic: %d\n", sl->sc->logic); printf(" action: %d\n", sl->sc->action); } printf("\n"); } int spam_test(char *file) { GMAIL *gm; Head *head; FILE *fp; char buf[SVRBUF]; Spam *sp; gmail_dump_att(); for (gm = gmail; gm; gm = gm->next) gmail_dump(gm); file = line_refine(file, '#'); fp = fopen(file, "r"); if (fp == NULL) return 1; head = head_register(HDPAGE, HDIDX); while (!feof(fp)) { head_clean(head); if (head_of_file(head, fp, buf, SVRBUF) == -1) break; printf("-> %s\n", head->fmsp); for (gm = gmail; gm; gm = gm->next) { sp = spam_match_chain(gm->slnk, head, 0); if (sp == NULL) printf("test OK!\n"); else { printf("triggered! (%s)(%s)(%d)\n", sp->from, sp->subject, sp->quota); } } } head_destruct(head); fclose(fp); return 0; } #endif [/code:1:2e2f71b2d0] main.c [code:1:2e2f71b2d0] #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #if HAVE_UNISTD_H #include #include #endif #if HAVE_GETOPT_H #include #else #include "getopt.h" #endif #if HAVE_FCNTL_H #include #endif #include "defs.h" #include "gmail.h" /* these variables are set against command line arguments */ char *cmd_auth = NULL; /* authorization pair */ char *cmd_host = NULL; char *cmd_mbox = NULL; int *cmd_cp_set = NULL; /* download set */ int cmd_action = 0; static char *cmd_subject = NULL; static char *cmd_cc = NULL; static char *cmd_bcc = NULL; /* blind carbon copy */ /* these variables are set against option file */ int timeout = 90; int verbose = 0; static int defbeh = ACT_DEFT; /* index use default behave */ static int parse_command_line(int argc, char **argv, char *abuf, int alen); static int *set_download_set(char *s); static int set_default(char *s, int *tasks, int tlen); static int open_quota_log(char *s); static void signal_quit(int sig); static void append_template(); static void usage(int flag); static char *rcpath[] = { NULL, "/etc/pmailrc", "/usr/lib/pmailrc", "/usr/local/etc/pmailrc", "/usr/local/lib/pmailrc", NULL }; int main(int argc, char **argv) { Folder *fo = NULL; SMTP *sm; GMAIL *gm; Head *head; int i, rs, tasks[TASK_NR]; char *abuf, *p; umask(077); signal(SIGHUP, signal_quit); signal(SIGINT, signal_quit); signal(SIGQUIT, signal_quit); signal(SIGTERM, signal_quit); signal(SIGPIPE, signal_quit); signal(SIGALRM, signal_quit); //progress_test(); progress_init(0); /* create a buffer for gathering command line arguments */ abuf = malloc(BLKBUF); if (abuf == NULL) return -1; /* get the home directory, then open default RC file. */ sprintf(abuf, "%s/.pmailrc", get_home()); rcpath[0] = abuf; /* if DEBUG is on, Pmail should search in the current directory first * for the configuration file. It makes debugging life easier since we can * test options in working directory. * A distribution version should disable it. */ for (i = 0; rcpath[i] != NULL; i++) { if (rc_open(rcpath[i]) >= 0) break; } if ((p = rc_check(RCKEY_TIMEOUT)) != NULL) timeout = atoi(p); if ((p = rc_check(RCKEY_VERBOSE)) != NULL) verbose = 1; if ((p = rc_check(RCKEY_SMBEHV)) != NULL) defbeh = msg_behave_bind(p); if ((p = rc_check(RCKEY_DEBUG)) != NULL) open_quota_log(p); /* now parsing command line arguments. * It is supposed that you can list a series of tasks in the config file, * in the 'default' option. You can also overwhelm this task queue by an * alternative instruction in the command line. In that case, the task * queue is fixed to one element, the instruction. */ rs = parse_command_line(argc, argv, abuf, BLKBUF); if (rs != ID_NULL) { tasks[0] = rs, rs = 1; } else if ((p = rc_check(RCKEY_DEFAULT)) != NULL) { rs = set_default(p, tasks, TASK_NR); } else rs = 0; /* process the task queue */ for (i = 0; i < rs; i++) { /* printf("Task %d/%d: %d\n", i, rs, tasks[i]); */ switch(tasks[i]) { case ID_HELP: usage(ID_HELP); break; case ID_VERSION: usage(ID_VERSION); break; case ID_TEMPLATE: append_template(); break; case ID_GMAIL: //progress_init(0); head = head_register(HDPAGE, HDIDX); if (head == NULL) break; gm = gmail_open(); if (cmd_host) { gm = gmail_cmdarg(cmd_host); if (gm) gmail_single(gm, head); } else gmail_main(gm, head); gmail_close(); head_destruct(head); break; case ID_SMTP: if (*abuf) { fo = folder_open(abuf, defbeh); } if (cmd_mbox) { fo = folder_open(cmd_mbox, defbeh); } if (fo == NULL) { p = rc_check(RCKEY_OUTBOX); if (p != NULL) { fo = folder_open(p, defbeh); } } rs = folder_number(); if (rs < 0) { conPrintf("Warning: No postpone message folder specified.\n"); } else if (rs == 0) { conPrintf("No message is ready for sending.\n"); } else { conPrintf("%d %s ready for sending.\n", rs, rs < 2 ? "message is" : "messages are"); sm = smtp_host_chain(cmd_host, cmd_auth); smtp_main(fo, sm); smtp_host_clean(); } folder_close(rc_check(RCKEY_BACKUP), defbeh); break; case ID_STREAM: fo = folder_online(abuf, cmd_cc, cmd_bcc, cmd_subject, defbeh); if (fo == NULL) break; sm = smtp_host_chain(cmd_host, cmd_auth); smtp_main(fo, sm); smtp_host_clean(); folder_close_online(rc_check(RCKEY_BACKUP), defbeh); break; case ID_HOSTLIST: gmail_open(); gmail_host_list(); gmail_close(); sm = smtp_host_chain(cmd_host, cmd_auth); smtp_host_list(); smtp_host_clean(); break; case ID_DUMPTMP: if (*abuf) { fo = folder_open(abuf, defbeh); } if (cmd_mbox) { fo = folder_open(cmd_mbox, defbeh); } if (fo == NULL) { p = rc_check(RCKEY_OUTBOX); if (p != NULL) { fo = folder_open(p, defbeh); } } folder_dump(fo); /* getchar(); */ folder_close(NULL, ACT_HOLD); break; case ID_DUMPINFO: if (*abuf) { fo = folder_open(abuf, defbeh); } if (cmd_mbox) { fo = folder_open(cmd_mbox, defbeh); } if (fo == NULL) { p = rc_check(RCKEY_OUTBOX); if (p != NULL) { fo = folder_open(p, defbeh); } } folder_list(fo); folder_close(NULL, ACT_HOLD); break; #ifdef DEBUG case ID_SPAMTEST: gm = gmail_open(); if (cmd_host) gm = gmail_cmdarg(cmd_host); spam_test(abuf); gmail_close(); break; #endif } } free(abuf); ReleaseResource(); return 0; } static int parse_command_line(int argc, char **argv, char *abuf, int alen) { int oidx, c, rs; char *sopt="pPvotf:h:d:s:c:b:l:e:u:"; struct option lopt[] = { { "verbose", 0, NULL, 'v' }, { "behave", 1, NULL, 'e' }, { "host", 1, NULL, 'h' }, { "download", 1, NULL, 'd' }, { "list", 1, NULL, 'l' }, { "auth", 1, NULL, 'u' }, { "template", 0, NULL, 't' }, { "help", 0, NULL, ID_HELP }, { "version", 0, NULL, ID_VERSION }, { "spamtest", 0, NULL, ID_SPAMTEST }, { "server", 0, NULL, ID_HOSTLIST }, { "progress", 1, NULL, ID_PROGRESS }, { 0, 0, 0, 0 } }; rs = ID_NULL; while (1) { c = getopt_long(argc, argv, sopt, lopt, &oidx); if (c == -1) break; switch (c) { case ID_HELP: return ID_HELP; case ID_VERSION: return ID_VERSION; case ID_HOSTLIST: rs = ID_HOSTLIST; break; #ifdef DEBUG case ID_SPAMTEST: rs = ID_SPAMTEST; break; #endif case ID_PROGRESS: progress_init(atoi(optarg)); break; case 'v': verbose = YES; break; case 'a': defbeh = msg_behave_bind(optarg); break; case 't': rs = ID_TEMPLATE; break; case 'P': rs = ID_DUMPTMP; break; case 'p': rs = ID_DUMPINFO; break; case 'o': rs = ID_SMTP; break; case 'h': if (cmd_host == NULL) cmd_host = dup_str(optarg); break; case 'f': if (cmd_mbox == NULL) cmd_mbox = dup_str(optarg); break; case 's': if (cmd_subject == NULL) cmd_subject = dup_str(optarg); break; case 'c': if (cmd_cc == NULL) cmd_cc = dup_str(optarg); break; case 'b': if (cmd_bcc == NULL) cmd_bcc = dup_str(optarg); break; case 'u': if (cmd_auth == NULL) cmd_auth = dup_str(optarg); break; case 'd': rs = ID_GMAIL; cmd_action = gmail_set_action(optarg); break; case 'l': cmd_cp_set = set_download_set(optarg); break; default: return ID_HELP; } } *abuf = '\0'; if (optind < argc) { for (c = optind; c < argc; c++) { if (strlen(abuf) + strlen(argv[c]) + 1 < alen) { strcat(abuf, argv[c]); strcat(abuf, " "); } } if (rs == ID_NULL) rs = ID_STREAM; } return rs; } /* store and adjust the mail download/handle set of which starts with 1. e.g. sour: 1,2,4-9,10,12 --> download set: [1,1], [2,2], [4,9], [10,10], [12,12], [-1,-1] (int array) */ static int *set_download_set(char *s) { char *idx[PARMAX], *p; int *dl, max, i; /* first it acknowleges the number of ',' */ for (max = 0, p = s; (p = strchr(p, ',')) != NULL; p++, max++); max = ((max + 2) * sizeof(int)) << 1; if ((dl = malloc(max)) == NULL) return NULL; max = ziptoken(s, idx, PARMAX, ","); for (i = 0; i < max; i++) { dl[i*2] = atoi(idx[i]); if ((p = strchr(idx[i], '-')) == NULL) dl[i*2+1] = dl[i*2]; else dl[i*2+1] = atoi(p+1); } dl[i*2] = dl[i*2+1] = EOF; /* -1, end flag */ return dl; } static int set_default(char *s, int *tasks, int tlen) { char *idx[TASK_NR]; int i, num; /* this function read a option, 'default xxx,xxx,...', from RC file. If there were another action specified by command line arguments, the 'default' option should be ignored. */ num = ziptoken(s, idx, TASK_NR, DELIMS); for (i = 0; (i < num) && (i < tlen); i++) { if (!strcasecmp(idx[i], "get")) tasks[i] = ID_GMAIL; else if (!strcasecmp(idx[i], "sent")) tasks[i] = ID_SMTP; else if (!strcasecmp(idx[i], "template")) tasks[i] = ID_TEMPLATE; else if (!strcasecmp(idx[i], "dump")) tasks[i] = ID_DUMPTMP; else if (!strcasecmp(idx[i], "info")) tasks[i] = ID_DUMPINFO; else if (!strcasecmp(idx[i], "version")) tasks[i] = ID_VERSION; else if (!strcasecmp(idx[i], "help")) tasks[i] = ID_HELP; else i--; /* printf("default: %s = %d\n", idx[i], tasks[i]); */ } return i; } static int open_quota_log(char *s) { char *idx[2]; char buf[SVRBUF]; int rs, quota; quota = 0; rs = ziptoken(s, idx, 2, DELIMS); if (idx[1] && *idx[1]) { quota = atoi(idx[1]); switch (idx[1][strlen(idx[1]) - 1]) { case 'k': case 'K': quota *= 1024; break; case 'm': case 'M': quota *= 1024 * 1024; break; } } fullpath(idx[0], buf); //printf("open log: %s %d\n", buf, quota); return log_open(buf, quota); } static void signal_quit(int sig) { ReleaseResource(); switch(sig) { case SIGHUP: printf("\nEncountered signal SIGHUP (%d)\n", sig); break; case SIGINT: printf("\nEncountered signal SIGINT (%d)\n", sig); break; case SIGQUIT: printf("\nEncountered signal SIGQUIT (%d)\n", sig); break; case SIGTERM: printf("\nEncountered signal SIGTERM (%d)\n", sig); break; case SIGALRM: printf("\nEncountered timeout signal (%d)\n", sig); break; case SIGPIPE: printf("\nEncountered signal SIGPIPE (%d)\n", sig); break; } exit(sig); } static void append_template() { FILE *fp = NULL; char obox[SVRBUF], *tmp; if ((tmp = cmd_mbox) == NULL) { tmp = rc_check(RCKEY_OUTBOX); } if (tmp != NULL) { fullpath(tmp, obox); fp = fopen(obox, "a"); } if (fp == NULL) fp = stdout; tmp = rc_check(RCKEY_REPLY); if (tmp == NULL) { fprintf(fp, "\nFrom - %s\n", timenow()); fprintf(fp, "From:\n"); } else { fprintf(fp, "\nFrom %s %s\n", email_pure(tmp), timenow()); fprintf(fp, "From: %s\n", tmp); } fprintf(fp, "To: \n"); fprintf(fp, "X-behave: pipe,sign,exhd\n"); fprintf(fp, "Subject: \n\n"); if (fp != stdout) fclose(fp); printf("Simple template is appended into %s.\n", obox ? obox : "stdout"); } /**************************************************************/ static void usage(int flag) { char *ver="pmail %s, by Xuming char *msg = "\ Usage:\n\ pmail [-v] [-e smtp-beh] [-u auth-pair] [-f mailbox] [-h host] [-l ...]\n\ \n\ pmail -dd [...] download mails and remove them in the server\n\ pmail -df [...] fetch mails and reserve them in the server\n\ pmail -dc [...] check mailbox status in the server\n\ pmail -dl [...] list message heads or other informations\n\ pmail -dr [...] remove mails in the server end\n\ You can instruct more than one POP3 server in [...]\n\ \n\ pmail -o [...] send mails stored in the postpone folder\n\ pmail -p [...] preview the&npmsages'''' head in the postpone folder\n\ pmail -P [...] dump the postpone folder to screen\n\ You can instruct more than one postpone folder in [...]\n\ \n\ pmail [-s subject] [-c cc-addr] [-b bcc-addr] to-addr [...]\n\ You can instruct more than one receiver in [...]\n\ \n\ pmail -t appends a template to the postpone mailbox (obsolete)\n\ \n\ "; if (flag == ID_VERSION) printf(ver, VERSION); else printf(msg); } /**********************************************************/ /* this procedure used to release all of the source which pmail ever occured. It also is looked on the last defend line as signal encountered or other urgent affair occured */ void ReleaseResource() { log_close(); rc_close(); folder_close(NULL, ACT_HOLD); // clear_gmail(); xfree(cmd_host); xfree(cmd_mbox); xfree(cmd_subject); xfree(cmd_cc); xfree(cmd_bcc); xfree(cmd_cp_set); } [/code:1:2e2f71b2d0] |
蓝色键盘 回复于:2003-04-25 14:18:58 |
folder.c [code:1:0568ea60bc] #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #if HAVE_UNISTD_H #include #include #endif #if HAVE_SYS_IOCTL_H #include #endif #include "defs.h" static Folder *rootfld; static char gdir[] = PMTMP; static int fid = 1; static char *signature = NULL; static void folder_insert(Folder *tar) { Folder *fo; if (rootfld == NULL) { rootfld = tar; rootfld->next = NULL; rootfld->prev = NULL; } else { for (fo = rootfld; fo->next; fo = fo->next); fo->next = tar; tar->next = NULL; tar->prev = fo; } } static Folder *check_loaded(char *fname) { Folder *fo; for (fo = rootfld; fo; fo = fo->next) { if (!strcmp(fo->name, fname)) break; } return fo; } static void load_signature(char *s) { FILE *fsig; char buf[SVRBUF], *sig; int len; if (signature) return; fullpath(s, buf); if ((fsig = fopen(buf, "r")) == NULL) { logPrintf(LOG_WARN, "can not open signature file. [%s]\n", buf); return; } fseek(fsig, 0, SEEK_END); if ((len = ftell(fsig)) > MAX_SIG) { logPrintf(LOG_WARN, "Too large the signature file is. [%d]\n", len); fclose(fsig); return; } /*fprintf(stderr, "%s [%d]\n", buf, len);*/ rewind(fsig); if ((signature = (char*) malloc(len + len / 5)) == NULL) { fclose(fsig); logPrintf(LOG_WARN, "Insufficent memory for signature built. [%d]\n", len); return; } &b;b =ns;''''>''''; sig = buf + 1; *iar&nbp=nsp;''''\0''''; while (fgets(sig, SVRBUF - 1, fsig)) { if (!strncmp(sig, "From ", 5)) strcat(signature, buf); else strcat(signature, sig); } fclose(fsig); } int folder_number() { Folder *fo; int num; if (rootfld == NULL) return -1; for (num = 0, fo = rootfld; fo; fo = fo->next) { num += fo->num; } return num; } Folder *folder_open(char *mailbox, int beh) { Folder *fo; Mail *m; char buf[SVRBUF], *idx[PARMAX], *pipeto; int i, rs; if (rootfld == NULL) { umask(0077); if (mktmpdir(gdir) == NULL) return NULL; } if (mailbox == NULL) return NULL; if ((pipeto = rc_check(RCKEY_SIG)) != NULL) { load_signature(pipeto); } pipeto = rc_check(RCKEY_PIPE); rs = ziptoken(mailbox, idx, PARMAX, DELIMS); for (i = 0; i < rs; i++) { fullpath(idx[i], buf); // printf("folder: %s\n", buf); if (check_loaded(buf)) continue; /* message folder loaded already */ if ((fo = msg_loader(gdir, buf, fid, 1, beh)) != NULL) { logPrintf(LOG_INFO, "[%s] loaded, %d messagesd\n", buf, fo->num); folder_insert(fo); fid++; for (m = fo->mail; m; m = m->next) { //printf("pipe message: %s (%X)\n", pipeto, m->behave); msg_pipeto(m, pipeto, 1, signature); } } } return rootfld; } static char blkbuf[BLKBUF]; static int folder_backup(char *backup) { Folder *fo; Mail *m; FILE *fin, *fout; int cnt, rs; if (!backup) return -1; fullpath(backup, blkbuf); fout = fopen(blkbuf, "a"); if (fout == NULL) { logPrintf(LOG_WARN, "folder_backup: open [%s] failed.\n", blkbuf); return -2; } for (cnt = 0, fo = rootfld; fo; fo = fo->next) { for (m = fo->mail; m; m = m->next) { if (m->removed == 0) continue; /* pick up removed messages, then backup them */ if ((fin = fopen(m->msg->name, "r")) == NULL) { logPrintf(LOG_WARN, "folder_backup: open [%s] failed.\n", m->msg->name); continue; } while ((rs = fread(blkbuf, 1, BLKBUF, fin)) > 0) fwrite(blkbuf, 1, rs, fout); fputs("\n", fout); fclose(fin); cnt++; } } logPrintf(LOG_INFO, "folder_backup: %d messages backuped.\n", cnt); return cnt; } static int folder_compress() { Folder *fo; Mail *m; int cnt; for (cnt = 0, fo = rootfld; fo; fo = fo->next) { /* unpipe undelivered messages */ for (m = fo->mail; m; m = m->next) { if (m->removed == 0) { msg_unpipe(m); cnt++; } } msg_combine(fo); } logPrintf(LOG_INFO, "folder_compress: %d messages undelivered.\n", cnt); return cnt; } int folder_close(char *backup, int beh) { Folder *fo, *tmp; if (backup && (beh & ACT_BACK)) folder_backup(backup); if (beh & ACT_DELE) folder_compress(); fo = rootfld; while (fo) { msg_clean(fo); tmp = fo; fo = fo->next; free(tmp); } rmdir(gdir); rootfld = NULL; return OK; } static char *ddmsg = "dead.letter"; Folder *folder_online(char *to, char *cc, char *bcc, char *sub, int beh) { Folder *fo; Mail *m; FILE *fp; char buf[SVRBUF], *p; //int rs; if (rootfld == NULL) { umask(0077); if (mktmpdir(gdir) == NULL) return NULL; } if ((fo = msg_loader(gdir, ddmsg, fid, 1, beh)) == NULL) return NULL; folder_insert(fo); m = msg_expand(fo, gdir, NULL); p = rc_check(RCKEY_REPLY); if (p == NULL) { sprintf(buf, "%s@%s", get_user(), get_hostname()); p = buf; logPrintf(LOG_WARN, "folder_online: system address %s\n", p); } m->from = dup_str(p); m->reply = dup_str(p); m->to = dup_str(to); m->cc = dup_str(cc); m->bcc = dup_str(bcc); m->subject = dup_str(sub); m->behave = beh; fp = fopen(m->msg->name, "w"); if (fp == NULL) { msg_free_mailobj(m); msg_clean(fo); rmdir(gdir); rootfld = NULL; return NULL; } fprintf(fp, "From %s %s\n", email_pure(m->from), timenow()); if (isatty(0)) { if (sub == NULL) { fprintf(stderr, "Subject: "); fgets(buf, SVRBUF, stdin); chop(buf); if (!isblankline(buf)) m->subject = dup_str(buf); } fprintf(stderr, "Use CTRL-D to terminate letter\n"); } fprintf(fp, "From: %s\n", m->reply); if (m->to) fprintf(fp, "To: %s\n", m->to); if (m->cc) fprintf(fp, "Cc: %s\n", m->cc); if (m->subject) fprintf(fp, "Subject: %s\n", m->subject); /*if ((m->behave & ACT_EHEAD) != 0) { rs = 0; for (p = rc_check(RCKEY_HEADER); p; p = rc_check_next()) { if (head_cmp(p, HD_MAILER)) rs++; fprintf(fp, "%s\n", p); } if (rs == 0) fprintf(fp, XMAILER, VERSION); }*/ fprintf(fp, "\n"); m->msg->boff = ftell(fp); while (fgets(buf, SVRBUF, stdin)) { if (!strncmp(buf, "From ", 5)) { m->msg->len += fprintf(fp, ">%s", buf); } else { m->msg->len += fprintf(fp, "%s", buf); } m->msg->line++; } if ((m->behave & ACT_ASIG) && signature) { m->msg->len += fprintf(fp, "%s", signature); } fclose(fp); m->msg->mtime = filedate(m->msg->name, &m->msg->msize); if ((p = rc_check(RCKEY_PIPE)) != NULL) msg_pipeto(m, p, 1, signature); /*if (p && (m->behave & ACT_PIPE)) msg_pipe2(m, p, signature);*/ return fo; } int folder_close_online(char *backup, int beh) { int rs = rootfld->num; if (backup && (beh & ACT_BACK)) folder_backup(backup); if (beh & ACT_DELE) rs = folder_compress(); msg_clean(rootfld); free(rootfld); rootfld = NULL; rmdir(gdir); if (rs == 0) unlink(ddmsg); return OK; } void folder_dump(Folder *fld) { Folder *fo; Mail *m; FILE *fp; char buf[SVRBUF]; for (fo = fld; fo; fo = fo->next) { for (m = fo->mail; m; m = m->next) { fp = fopen(m->msg->name, "r"); if (fp == NULL) continue; while (fgets(buf, SVRBUF, fp)) { fputs(buf, stdout); } fclose(fp); printf("\n"); } } } void folder_list(Folder *fld) { struct winsize ws; Folder *fo; Mail *m; char buf[SVRBUF], ad[80]; int i, addr; if (ioctl(1, TIOCGWINSZ, (char *) &ws) < 0) { ws.ws_col = atoi(getenv("COLUMNS")); ws.ws_row = atoi(getenv("LINES")); if (ws.ws_col == 0) ws.ws_col = 80; } addr = ws.ws_col / 3; /* 1/3 column for target address */ for (fo = fld; fo; fo = fo->next) { printf("[%s]: %d messages.\n", fo->name, fo->num); for (m = fo->mail; m; m = m->next) { i = sprintf(ad, "%s", m->to ? m->to : ""); for ( ; i < addr; i++) ad&9;&bsp;=ns;'''' ''''; ad[addr] = 0; i = sprintf(buf, "%5d# %-s %6d \"%s\"", m->id, ad, m->msg->len, m->subject ? m->subject : ""); if (i >= ws.ws_col) { buf[ws.ws_col -&nbp&9;&bsp;=ns;''''"''''; buf[ws.ws_col - 1] = 0; } printf("%s\n", buf); } } } [/code:1:0568ea60bc] memo.c [code:1:0568ea60bc] #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include "defs.h" #include "memo.h" Memo *memo_open(char *memo) { Memo *mm; char buf[SVRBUF]; #ifdef DEBUG if (!memo) return NULL; #endif if ((mm = malloc(sizeof(Memo))) == NULL) { dbgPrintf("memo_open: out of memory.\n"); return NULL; } mm->num = 0; if ((mm->fp = fopen(memo, "a+")) == NULL) { dbgPrintf("memo_open: Cannot open address memo. [%s]\n", memo); free(mm); return NULL; } if ((mm->pm = pm_handler(PGIDX, PGSIZE)) == NULL) { dbgPrintf("memo_open: No PMAL handle allocated.\n"); fclose(mm->fp); free(mm); return NULL; } rewind(mm->fp); while (fgets(buf, SVRBUF, mm->fp)) { lineri&40bf&bsp;''''#''''); if (isblankline(buf)) continue; if (mm->num >= MMIDX) break; mm->idx[mm->num] = pm_dup_str(mm->pm, buf); if (mm->idx[mm->num]) mm->num++; } return mm; } void memo_close(Memo *mm) { #ifdef DEBUG if (!mm) return; #endif fclose(mm->fp); pm_close(mm->pm); free(mm); } int memo_add_addr(Memo *mm, char *addr) { int i; #ifdef DEBUG if (!mm || !addr) return 1; #endif if (isblankline(addr)) return 0; for (i = 0; i < mm->num; i++) { if (!email_cmp(mm->idx[i], addr)) return 0; /* existed already */ } if (mm->num >= MMIDX) return 0; mm->idx[mm->num] = pm_dup_str(mm->pm, addr); if (mm->idx[mm->num]) mm->num++; fseek(mm->fp, 0, SEEK_END); fprintf(mm->fp, "%s\n", addr); fflush(mm->fp); return 1; } char *memo_choose(Memo *mm, int col, int line) { char buf[SVRBUF]; int i, k, len; #ifdef DEBUG if (!mm) return NULL; #endif i = 0; line--; while(1) { for (k = 0; (i < mm->num) && (k < line); i++, k++) { len = sprintf(buf, "%4d- ", i + 1); StrnCpy(buf + len, mm->idx[i], SVRBUF - len); len = strlen(buf); if (len > col) { buf[col -&nbp&3&ns;&bsp;''''-''''; buf[col -&nbp&3&nbp=nsp;''''\0''''; } printf("%s\n", buf); } b it&4;quot;'''''''bp;ak&bsp;''''f''''b;owr,nbsp;'''''''bp;ut&bsp;''''a'''' abort, choose: "); fgets(buf, SVRBUF, stdin); lineri&40bf&bsp;''''#''''); if (!strcasecmp(buf, "q")) return NULL; else if (!strcasecmp(buf, "a")) return (char*) memo_choose; else if (!strcasecmp(buf, "b")) { i -= line; if (i < 0) i = 0; } else if (isdigit(buf[0])) { i = atoi(buf) - 1; if (i < 0) return NULL; else return mm->idx[i]; } else if (i == mm->num) { i -= line; if (i < 0) i = 0; } } return NULL; } [/code:1:0568ea60bc] strdate.c [code:1:0568ea60bc] #include #include #include #if TIME_WITH_SYS_TIME #include #include #else #if HAVE_SYS_TIME_H #include #else #include #endif #endif extern int ziptoken(char *sour, char **idx, int ids, char *delim); static char *week[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; static char *mon[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; static int get_week(char *s) { int i; for (i = 0; i < 7; i++) if (!strncmp(week[i], s, 3)) break; if (i == 7) return -1; return i; } static int get_month(char *s) { int i; for (i = 0; i < 12; i++) if (!strncmp(mon[i], s, 3)) break; if (i == 12) return -1; return i; } static int get_mday(char *s) { int i; i = atoi(s); if ((i < 1) || (i > 31)) return -1; return i; } static int get_year(char *s) { int i; /* The number of years since 1900 */ i = atoi(s); #ifdef Y2K_FORCED if ((i >= 0) && (i < 70)) i += 2000; /* for Y2K problem */ else if ((i > 70) && (i < 100)) i+= 1900; else if (i > 1900) i -= 1900; #else if (i > 1900) i -= 1900; #endif return i; } /* Time zone may be indicated in several ways. "UT" is Universal Time (formerly called "Greenwich Mean Time"); "GMT" is permitted as a reference to Universal Time. The military standard uses a single character for each zone. "Z" is Universal Time. "A" indicates one hour earlier, and "M" indicates 12 hours earlier; "N" is one hour later, and "Y" is 12 hours later. The letter "J" is not used. The other remaining two forms are taken from ANSI standard X3.51-1975. One allows explicit indication of the amount of offset from UT; the other uses common 3-character strings for indicating time zones in North America. */ static int get_zone(char *s) { int z; if (!strcmp(s, "UT") || !strcmp(s, "GMT") || !strcmp(s, "Z")) z = 0; else if (!strcmp(s, "EST")) z = 500; else if (!strcmp(s, "EDT")) z = 400; else if (!strcmp(s, "CST")) z = 600; else if (!strcmp(s, "CDT")) z = 500; else if (!strcmp(s, "MST")) z = 700; else if (!strcmp(s, "MDT")) z = 600; else if (!strcmp(s, "PST")) z = 800; else if (!strcmp(s, "PDT")) z = 700; else if (!strcmp(s, "A")) z = -100; else if (!strcmp(s, "M")) z = -1200; else if (!strcmp(s, "N")) z = 100; else if (!strcmp(s, "Y")) z = 1200; else if (&0snbp=&bsp;''''+'''') || &0snbp=&bsp;''''-'''')) z = atoi(s); else z = 10000; /* mark as parse error */ return z; } static int get_time(char *s, struct tm *t) { char *idx[3]; if (ziptoken(s, idx, 3, ":") < 2) return -1; if (idx[0]) t->tm_hour = atoi(idx[0]); if (idx[1]) t->tm_min = atoi(idx[1]); if (idx[2]) t->tm_sec = atoi(idx[2]); return 0; } static int get_mday_rfc850(char *s, struct tm *t) { char *idx[3]; ziptoken(s, idx, 3, "-"); if (idx[0]) t->tm_mday = atoi(idx[0]); if (idx[2]) t->tm_year = atoi(idx[2]); if ((t->tm_mon = get_month(idx[1])) == -1) return -1; return 0; } int strdate(char *s, struct tm *t) { char *idx[10], buf[80]; int zone, rs = 0; strncpy(buf, s, 80); buf &3&nbp=nsp;''''\0''''; memset(t, 0, sizeof(struct tm)); rs = ziptoken(buf, idx, 10, ", "); if �th�s&bsp;''''-'''') && (rs == 4)) { /* rfc850 date style */ /* Weekday, DD-Mon-YY HH:MM:SS TIMEZONE */ /* Is this style Y2K compalient ? */ rs = 0; if ((t->tm_wday = get_week(idx[0])) == -1) rs++; if (get_mday_rfc850(idx[1], t) == -1) rs++; if (get_time(idx[2], t) == -1) rs++; if ((zone = get_zone(idx[3])) == 10000) rs++; } else if (s #;nbp=&bsp;'''','''') { /* rfc822 date style */ /* [WDY,] DD Mon YY HH:MM[:SS] TIMEZONE */ rs = 0; if ((t->tm_wday = get_week(idx[0])) == -1) rs++; if ((t->tm_mday = get_mday(idx[1])) == -1) rs++; if ((t->tm_mon = get_month(idx[2])) == -1) rs++; if ((t->tm_year = get_year(idx[3])) == -1) rs++; if (get_time(idx[4], t) == -1) rs++; if ((zone = get_zone(idx[5])) == 10000) rs++; } else if (*idx[0#;bp;l;&bsp;''''9'''') { /* rfc822 date style */ /* [WDY,] DD Mon YY HH:MM[:SS] TIMEZONE */ rs = 0; if ((t->tm_mday = get_mday(idx[0])) == -1) rs++; if ((t->tm_mon = get_month(idx[1])) == -1) rs++; if ((t->tm_year = get_year(idx[2])) == -1) rs++; if (get_time(idx[3], t) == -1) rs++; if ((zone = get_zone(idx[4])) == 10000) rs++; } else if ((rs == 5) || (rs == 6)) { /* ctime date style */ /* Note in particular that ctime format: Wdy Mon DD HH:MM:SS [TIMEZONE] YYYY is not acceptable because it is not a valid ARPANET date. However, since older software still generates this format, news implementations are encouraged to accept this format and translate it into an acceptable format. */ rs = 0; if ((t->tm_wday = get_week(idx[0])) == -1) rs++; if ((t->tm_mon = get_month(idx[1])) == -1) rs++; if ((t->tm_mday = get_mday(idx[2])) == -1) rs++; if (get_time(idx[3], t) == -1) rs++; if (*idx[&3nsp&t&bsp;''''9'''') { if ((zone = get_zone(idx[4])) == 10000) rs++; if ((t->tm_year = get_year(idx[5])) == -1) rs++; } else if ((t->tm_year = get_year(idx[4])) == -1) rs++; } return rs; } time_t strtimet(char *s) { struct tm t; strdate(s, &t); return mktime(&t); } #ifdef EXECUTABLE int main(int argc, char **argv) { struct tm t; int rs = 0; if (argc < 2) { printf("usage: %s \"date string\"\n", argv[0]); return 0; } if ((rs = strdate(argv[1], &t)) > 0) { printf("parse error\n"); } else { printf("%s\n", asctime(&t)); } return rs; } #endif [/code:1:0568ea60bc] mime.c [code:1:0568ea60bc] #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #if HAVE_UNISTD_H #include #include #endif #include "defs.h" /* For example: ------=_NextPart_000_008A_01C0B63E.41DCF080 Content-Type: text/plain; charset="gb2312" Content-Disposition: attachment; filename="E:\dirhtml2m.txt" Content-Transfer-Encoding: base64 */ typedef struct { char *name; /* filename="E:\dirhtml2m.txt" */ char *bndry; /* ------=_NextPart_000_008A_01C0B63E.41DCF080 */ int type; /* text/plain 1:text; 0:saving file */ int encode; /* base64 */ int chset; /* "gb2312" 0:ignore; 1: HZ encoded */ char buff[256]; } MMARK; #define MAXMK 12 static char *get_boundary(char *sour, char *bndry, int len) { char *p; p = th#0;or&bsp;''''=''''); if (p == NULL) return NULL; for (p++; isspace(*p); p++); if &0*&nsp;==ns;''''"'''') p++; *d+&ns;&bsp;''''-''''; *d+&ns;&bsp;''''-''''; StrnCpy(bndry, p, len); for (p = bndry + strlen(bndry) - 1; p > bndry; p--) { if (isspace(*p) || &0*&nsp;==ns;''''"'''')) *p = 0; else break; } /* printf("BOUNDARY EXTRACT: %s\n", bndry - 2); */ return bndry - 2; } static void parse_ctype(MMARK *mm, char *ctype) { char *idx[32], *p; int i, rs; rs = ziptoken(ctype, idx, 32, ";"); for (i = 0; i < rs; i++) { p = skip_space(idx[i]); if (!strncasecmp(p, "text/", 5)) mm->type = 1; else if (!strncasecmp(p, "charset", 7)) { p += 7; if (isalpha(*p)) continue; while (*p && !isalpha(*p)) p++; if (!strncasecmp(p, "hz-gb-2312", 10)) mm->chset = 1; } else if (!strncasecmp(p, "boundary", 8)) { p += 8; if (isalpha(*p)) continue; mm->bndry = &mm->buff[128]; get_boundary(p, mm->bndry, 120); } else if (!strncasecmp(p, "name", 4)) { p += 4; if ((p =&nbpth�p&bsp;''''='''')) == NULL) continue; p++; p = skip_space(p); if &0*&nsp;==ns;''''"'''') p++; /* conPrintf(p); */ mm->name = mm->buff; strncpy(mm->name, p, 128); for (p = mm->name + strlen(mm->name) - 1; p >= mm->name; p--) { if (!isspace(*p) && &0*&nsp;!=ns;''''"'''')) break; else *p = 0; } } } } static void parse_disposit(MMARK *mm, char *disp) { char *idx[32], *p; int i, rs; rs = ziptoken(disp, idx, 32, ";"); for (i = 0; i < rs; i++) { p = skip_space(idx[i]); if (!strncasecmp(p, "filename", 8)) { p += 8; if ((p =&nbpth�p&bsp;''''='''')) == NULL) continue; p++; p = skip_space(p); if &0*&nsp;==ns;''''"'''') p++; /* conPrintf(p); */ mm->name = mm->buff; strncpy(mm->name, p, 128); for (p = mm->name + strlen(mm->name) - 1; p >= mm->name; p--) { if (!isspace(*p) && &0*&nsp;!=ns;''''"'''')) break; else *p = 0; } } } } static void get_mime_mark(FILE *fp, FILE *fout, MMARK *mm, char *buf, int len) { char *p; int status; status = 0; memset(mm, 0, sizeof(MMARK)); while (fgets(buf, len, fp)) { fputs(buf, fout); if (isblankline(buf)) break; p = buf; if (!isspace(buf[0])) { status = 0; if (!strncasecmp(buf, "Content-Type:", 13)) { status = 1; p = buf + 13; } else if (!strncasecmp(buf, "Content-Transfer-Encoding:", 26)) { status = 2; p = buf + 26; } else if (!strncasecmp(buf, "Content-Disposition:", 20)) { status = 3; p = buf + 20; } } p = skip_space(p); /* printf("--COntent:> %s", p); */ switch (status) { case 1: parse_ctype(mm, p); break; case 2: if (!strncasecmp(p, "7bit", 4)) mm->encode = CTE_7BIT; else if (!strncasecmp(p, "quoted-printable", 16)) mm->encode = CTE_QP; else if (!strncasecmp(p, "base64", 6)) mm->encode = CTE_BASE64; else if (!strncasecmp(p, "8bit", 4)) mm->encode = CTE_8BIT; else if (!strncasecmp(p, "binary", 6)) mm->encode = CTE_BINARY; break; case 3: parse_disposit(mm, p); break; default: break; } } } static void mime_extract(FILE *fin, FILE *fout, char *bndry, int ctl, char *buf, int len) { MMARK mm; FILE *ftmp; char *p; while (!feof(fin)) { fputs(buf, fout); chop(buf); if (strncmp(buf, bndry, strlen(bndry))) { fgets(buf, len, fin); } else { get_mime_mark(fin, fout, &mm, buf, len); /*printf("mime type: %d\n", mm.type); printf("mime name: %s\n", mm.name); printf("mime bndry: %s\n", mm.bndry); printf("mime encode: %d\n", mm.encode); printf("mime chset: %d\n", mm.encode);*/ if (mm.bndry && *mm.bndry) { fgets(buf, len, fin); mime_extract(fin, fout, mm.bndry, ctl, buf, len); } else if (mm.type == 1) { if (mm.encode == CTE_BASE64) { npnsp;pt&40;''''\n'''', fout); debase64_bndry(fin, fout, bndry, buf, len); npnsp;pt&40;''''\n'''', fout); } else if (mm.encode == CTE_QP) { npnsp;pt&40;''''\n'''', fout); deqp_bndry(fin, fout, bndry, buf, len); npnsp;pt&40;''''\n'''', fout); } else { fgets(buf, len, fin); } } else if (mm.name) { conPrintf("Extract file [%s]? (Yes/No/Rename) ", mm.name); tcflush(0, TCIFLUSH); read(0, buf, len); p = skip_space(buf); switch (*p) &1;b> cs&bsp;''''y''''#;b> cs&bsp;''''Y'''': strcpy(buf, mm.name); break;<>b> cs&bsp;''''r''''#;b> cs&bsp;''''R'''': conPrintf("Input filename: "); tcflush(0, TCIFLUSH); read(0, buf, len); chop(buf); if (isblankline(buf)) strcpy(buf, mm.name); break; default#;b> cs&bsp;''''n''''#;b> cs&bsp;''''N'''': fgets(buf, len, fin); continue; } if ((ftmp = fopen(buf, "w")) == NULL) { fgets(buf, len, fin); continue; } if (mm.encode == CTE_BASE64) { debase64_bndry(fin, ftmp, bndry, buf, len); } else if (mm.encode == CTE_QP) { deqp_bndry(fin, ftmp, bndry, buf, len); } else { while (fgets(buf, len, fin)) { if (!strncmp(buf, bndry, strlen(buf) - 1)) break; fputs(buf, ftmp); } } fclose(ftmp); } else fgets(buf, len, fin); } } conPrintf("Mime message extracted.\n"); } static int mime_multi(char *file, char *bndry, int ctl, char *buf, int len) { FILE *fin, *fout; if ((fin = fopen(file, "r")) == NULL) return -1; unlink(file); if ((fout = fopen(file, "w")) == NULL) { fclose(fin); return -1; } fgets(buf, len, fin); mime_extract(fin, fout, bndry, ctl, buf, len); fclose(fin); fclose(fout); return 0; } static int decode_hzgb(char *file) { FILE *fin, *fout; if ((fin = fopen(file, "r")) == NULL) return -1; unlink(file); if ((fout = fopen(file, "w")) == NULL) { fclose(fin); return -1; } dehz_file(fin, fout); fclose(fin); fclose(fout); return 0; } /* ctl=0: decode attached file; ctl=1: decode text only */ int mime_body(Mail *m, FILE *fin, char *outfile, int ctl) { FILE *fout; char buf[SVRBUF], bndry[128], *idx[32], *p; int i, rs; /* if (fin == NULL) { fin = fopen(m->msg->name, "r"); if (fin == NULL) { dbgPrintf("mime_body: cannot open input file\n"); return -1; } fseek(fin, m->msg->boff, SEEK_SET); }*/ if ((fout = fopen(outfile, "w")) == NULL) { dbgPrintf("mime_body: cannot open output file. [%s]\n", outfile); return -1; } if (m->c_encode == CTE_QP) deqp_file(fin, fout); else if (m->c_encode == CTE_BASE64) debase64_file(fin, fout); else dup_stream(fin, fout); fclose(fout); if (m->c_type) { StrnCpy(buf, m->c_type, SVRBUF); rs = ziptoken(buf, idx, 32, ";"); /* printf("Type: "); for (i = 0; i < rs; i++) printf("@ %s ", idx[i]); printf("\n"); */ for (i = 0; i < rs; i++) { p = skip_space(idx[i]); /* skip leading white spaces */ if (!strncasecmp(p, "charset", 7)) { p += 7; if (isalpha(*p)) continue; /* avoid of "charsetxxx" */ while (!isalpha(*p)) p++; if (!strncasecmp(p, "hz-gb-2312", 10)) { decode_hzgb(outfile); break; } } else if (!strncasecmp(p, "boundary", 8)) { p += 8; if (isalpha(*p)) continue; p = get_boundary(p, bndry, 128); /* no code now */ mime_multi(outfile, p, 0, buf, SVRBUF); break; } } } return 0; } /******************************************************************/ /* abc =?gb2312?B?xxxxxxx?= hello | | | | | | | | | | | +--- tail | | | | +----- bodyend | | | +--- body | | +----- encode | +--- codepage +----- start point */ struct code_mark { char *codepage; char *encode; char *body; char *bodyend; char *tail; }; #define ISSPACE(p) ((#;nbs;=nsp;''''\n'''') || (#;nbs;=nsp;''''\r'''') || (#;nbs;=nsp;''''\f'''')) static struct code_mark *check_code_mark(char *sour) { static struct code_mark cm; char *p = sour; if (&0pnbp!&bsp;''''='''') || (*(+#;nbp!&bsp;''''?'''')) return NULL; cm.codepage = p + 2; for (p += 2; *p && &0pnbp!&bsp;''''?''''); p++) { if (ISSPACE(*p)) &s;p&bsp;=ns;'''' ''''; } if (*p == 0) return NULL; cm.encode = p + 1; for (p++; *p && &0pnbp!&bsp;''''?''''); p++) { if (ISSPACE(*p)) &s;p&bsp;=ns;'''' ''''; } if (*p == 0) return NULL; cm.body = p + 1; for (p++; *p; p++) { if (&0pnbp=&bsp;''''?'''') && (*(+#;nbp=&bsp;''''='''')) break; if (ISSPACE(*p)) &s;p&bsp;=ns;'''' ''''; } if (*p == 0) cm.tail = cm.bodyend = p; else { cm.bodyend = p; cm.tail = p + 2; } return & } /* de-code all kinds format if I know in just a single comment * and keep newline char out. Such as "abc =?gb2312?B?xxxxxxx?= hello" * There are 3 control style in the variety ctl: * 0: No decode, just pass though the original head and keep the newline out * 1: decode and remain the leading char like "=?gb2312?B?" * 2: decode and get rid of the leading char * Note: the result will replace the original string */ char *decode_head(char *sour, int ctl) { struct code_mark *cm; char *p, *k, tmp; int cnt, i, hzflag; p = k = sour; hzflag = 0; while (*k) { if (ctl && ((cm = check_code_mark(k)) != NULL)) { if (ctl == 1) { for ( ; k < cm->body; *p++ = *k++); k = cm->bodyend; } else k = cm->tail; tmp = *cm->bodyend; *cm->bodyend = 0; if (!strncasecmp(cm->codepage, "hz-gb-2312", 10)) hzflag++; switch (*cm->encode) { npnspcs&bsp;''''b'''': npnspcs&bsp;''''B'''': /* puts(cm->body); */ cnt = debase64_str(cm->body, p); for (i = 0; i < cnt; i++, p++) { if (ISSPACE(*p)) b p&bsp;=ns;'''' ''''; } break; npnspcs&bsp;''''q'''': npnspcs&bsp;''''Q'''': cnt = deqp_str(cm->body, p); for (i = 0; i < cnt; i++, p++) { if (ISSPACE(*p)) b p&bsp;=ns;'''' ''''; } break; default: p = k; } *cm->bodyend = tmp; } else if (ISSPACE(*k)) &b;p+&bsp;=ns;'''' '''', k++; else *p++ = *k++; } *p = 0; /* specially encode: HZ-GB code */ if (hzflag) { /* printf("Sub: %s\n", sour); */ dehz_str(sour, sour); } return sour; } [/code:1:0568ea60bc] |
蓝色键盘 回复于:2003-04-25 14:46:40 |
defs.h [code:1:bd1926abc9] #ifndef DEFS_PMAIL_H #define DEFS_PMAIL_H #include #include "message.h" #include "mhead.h" #include "libsupp.h" #define HOMEBOX "mbox" #define OUTFOLDER "postpone" #define PAGER "/bin/more" #define EDITOR "/bin/vi" #define TMPPATH "/usr/tmp/mailzXXXXXX" #define PMTMP "/usr/tmp/pmailXXXXXX" #define DEFQUOTA "Last time you wrote:\n" #define DELIMS ",:; " /* delimiters for parsing RC file */ #define RCKEY_DEBUG "log" /* define log file */ #define RCKEY_DEFAULT "default" /* default operation */ #define RCKEY_VERBOSE "verbose" #define RCKEY_TIMEOUT "timeout" #define RCKEY_SPAM "spam" /* incoming mail filter */ #define RCKEY_FETCH "fetch" /* fetch mail from incoming server */ #define RCKEY_TOPSLY "topstyle" //#define RCKEY_SIZELMT "quota" /* download message size quota */ #define RCKEY_LDELAY "popdelay" /* pop3 server login delay */ #define RCKEY_SMTP "smtp" #define RCKEY_SMBEHV "smtpbeh" /* default behavior of outgoing mail */ #define RCKEY_MBOX "mbox" /* default folder */ #define RCKEY_OUTBOX "postpone" #define RCKEY_BACKUP "bakbox" //#define RCKEY_SENDER "sender" /* act as ISP message sender */ #define RCKEY_REPLY "reply-to" /* act as From: */ #define RCKEY_SIG "signature" #define RCKEY_PIPE "pipeto" /* external pipe */ #define RCKEY_HEADER "header" #define RCKEY_PAGER "pager" #define RCKEY_EDITOR "editor" //#define RCKEY_DISHEAD "showhead" /* specify heads for displaying */ #define RCKEY_ADMEMO "memo" /* address memo file */ #define RCKEY_HEADMASK "headmask" /* Note 64 head classes limited */ #ennspCMDLIM ''''#'''' /* start mark of commentory */ #ennspPTDLIM ''''/'''' /* delimiter of directory */ #define MAX_DBG 16 /* specify the maximum debug and log device */ #define MAX_SIG 65535 /* the maximun size of signature file */ #define QUOTA_DBG 10240 /* default log file quota */ #define PATHDEP 32 /* maximum depth of relative file */ #define TASK_NR 32 /* maximum work classes limitation */ #define SVRBUF 256 #define EX_HEAD 128 #define MAXFOLDS 256 #define PARMAX 100 /* maximum parameters in a command */ #define BLKBUF 4096 #define HMMAX 64 /* head mask limitation */ #define HMDEF "From:To:Cc:Bcc:Subject:Date:Sender:Reply-To:X-Mailer" #define YES 1 #define NO 0 #define OK 0 #define WARNING -1 #define FAILURE -2 #define NOSMTPHOST -3 #define LOWMEMORY -6 #define OPENFILERR -7 #define CREATEFAIL -8 #define MISANSWER -9 #define LOGIN_FAIL -10 #define SPAM_MSG -20 #define SPAM_FETCH -21 #define LOG_ERR 9 #define LOG_INFO 2 #define LOG_WARN 1 #define LOG_ALL 0 #define ID_NULL 0 #define ID_GMAIL 1 #define ID_STREAM 2 #define ID_HELP 3 #define ID_VERSION 4 #define ID_TEMPLATE 5 #define ID_DUMPTMP 6 #define ID_DUMPINFO 7 #define ID_SMTP 8 #define ID_HOSTLIST 9 #define ID_SPAMTEST 10 #define ID_PROGRESS 11 #define SMTP_PORT 25 #define POP3_PORT 110 /* this structure should be filled up acdnnbsp;ons;''''smtp'''' option in the * config file. There are 4 entries&b;nbsp;tens;''''smtp'''' option: * host:reply_address:id:passwd * Pmail read the config file and chains all smtp structures. But only * the first one, or the specified one, will be available. If there is * another smtp server specified in the command line, it should be the * first item inserted to the chain. */ typedef struct _SMTP { char *host; char *reply; char *id; char *passwd; struct _SMTP *next; char buf[1]; } SMTP; #define pfclose(ptr) { \ if ((ptr) != NULL) fclose(ptr); \ (ptr) = NULL; \ } #define xfree(ptr) {\ free(ptr); \ (ptr) = NULL; \ } #define chop(buf) ((buf)[strlen(u#;1&bp;= ''''\0'''') #if !defined(isspace) #define isspace(ch) (((ch) > 0) && (&4c&41 &t=nbsp;'''' '''')) #endif /* stupid strncpy cannot null-terminate oversized string, so I do it */ #define StrnCpy(d,s,l) (strncpy((d),(s),(l)), (d)[(l)-1] = 0) /* see main.c */ extern int timeout; extern int verbose; extern char *cmd_auth; extern char *cmd_host; extern char *cmd_mbox; extern int *cmd_cp_set; extern int cmd_action; extern int cmd_protocol; int act_bind(char *s); void ReleaseResource(); /* see smtp.c */ int smtp_main(Folder *rootfld, SMTP *sm); SMTP *smtp_host_chain(char *host, char *auth); void smtp_host_list(); void smtp_host_clean(); /* see folder.c */ Folder *folder_open(char *mailbox, int beh); Folder *folder_online(char *to, char *cc, char *bcc, char *sub, int beh); int folder_close(char *backup, int beh); int folder_close_online(char *backup, int beh); int folder_number(); void folder_dump(Folder *fld); void folder_list(Folder *fld); /* mime.c */ char *decode_head(char *sour, int ctl); int mime_body(Mail *m, FILE *fin, char *outfile, int ctl); /* see strdate.c */ time_t strtimet(char *s); int strdate(char *s, struct tm *t); #endif [/code:1:bd1926abc9] mhead.h [code:1:bd1926abc9] #ifndef _MHEAD_H #define _MHEAD_H #include "pmalloc.h" #define HDPAGE 4096 /* for PMAL buffer */ #define HDIDX 64 struct head_chain { char *str; void *next; }; typedef struct { int len; /* length of the entire head line */ int rm; /* removed marking */ char *key; /* duplication of the head key */ char *body; /* head body, no key started with. Note */ struct head_chain *hc; /* the remain parts of this head */ void *next; } HLin; typedef struct { int len; /* length of entire head part */ int num; /* number of head title */ char *fmsp; /* the copy of FromSps line */ HLin *hlin; /* start of head line chain */ HLin *last; /* last item in the head line chain */ PMAL *pm; void *this; /* point to current Head object itself */ char *skey; /* use fro searching next head title */ HLin *scur; } Head; Head *head_register(int page, int idx); void head_destruct(Head *hdo); char *head_loading(Head *hdo, char *s); void head_clean(Head *hdo); int head_to_cache(Head *hdo, FILE *fin, char *buf, int len); int head_of_file(Head *hdo, FILE *fin, char *buf, int len); char *head_append(Head *hdo, char *head); void head_remove_first(Head *hdo, char *key); void head_remove_all(Head *hdo, char *key); void head_mask(Head *hdo, char *mask, int rm); HLin *head_check(Head *hdo, char *key); HLin *head_check_next(Head *hdo); char *head_fetch(HLin *h); char *head_fetch_body(HLin *h); HLin *head_exist(Head *hdo, char *head); void head_dump(Head *hdo, FILE *fout, int fmsp); char *head_index(char *headline, char *buf, int len); int head_cmp(char *s, char *d); #endif [/code:1:bd1926abc9] message.h [code:1:bd1926abc9] #ifndef _MESSAGE_H #define _MESSAGE_H #include #define HD_FROM "from" #define HD_RPLTO "reply-to" #define HD_SENDER "sender" #define HD_TO "to" #define HD_CC "cc" #define HD_BCC "bcc" #define HD_SUBJECT "subject" #define HD_DATE "date" #define HD_STATUS "status" #define HD_ACTION "X-behave" #define HD_MAILER "X-Mailer" #define HD_CTENCODE "Content-Transfer-Encoding" #define HD_CTTYPE "Content-Type" #define PM_MSG_OK 0 #define PM_MSG_NOFILE 1 #define PM_MSG_BADFILE 2 #define PM_MSG_BINARY 3 #define PM_MSG_INVALID 4 #define PM_MSG_NOMEM 5 #define PM_MSG_BADPIPE 6 /* encoding mechanism in the Content-Transfer-Encoding field */ #define CTE_7BIT 0 #define CTE_QP 1 #define CTE_BASE64 2 #define CTE_8BIT 3 #define CTE_BINARY 4 #define XMAILER \ "X-Mailer: pmail %s (Linux). Report bugs to /* instruct the operation of individual letters in the postpone folder */ #define ACT_PIPE 1 /* use external pipe */ #define ACT_ASIG 2 /* append signature from file */ #define ACT_EHEAD 4 /* enable extra header line */ #define ACT_SUSP 0x80 &s;nsp; /* don''''t touch this letter! for pine only */ #define ACT_STDIN 0x100 /* The letter comes from standard input. */ #define ACT_HOLD 0x1000 /* do not touch original message folder */ #define ACT_DELE 0x2000 /* delete successfully sent message */ #define ACT_BACK 0x4000 /* backup successfully sent message */ #define ACT_NORM (ACT_PIPE | ACT_ASIG | ACT_EHEAD) #define ACT_SMTP (ACT_DELE | ACT_BACK) #define ACT_DEFT (ACT_PIPE | ACT_ASIG | ACT_EHEAD | ACT_DELE | ACT_BACK) typedef struct _MsgObj { char *name; /* filename of temperary folder */ int len; /* mail length of body */ int line; /* mail lines of body */ long boff; /* body offset in the temporary letter */ int msize; /* size of entire message, include head */ time_t mtime; /* time of last modification */ struct _MsgObj *next; char _namebuf[1]; /* room for temperary folder name */ } MsgObj; /* Note about "from" field and "reply" field: According to RFC822, The "From:" field contains the identity of the person(s) who wished this message to be sent. If this is not done, the "Sender:" field must be present and act as the redundant with the "From:" field. The "Reply-To" field is added by the message originator and is intended to direct replies. */ typedef struct _Mail { int id; int removed : 1; /* marked as been removed */ int changed : 1; /* be dumped, edited */ int piped : 1; int oldmail : 1; /* false means unread yet */ int replied : 1; /* has been replyed */ char *from; /* From: Sender: Reply-To: */ char *reply; /* Reply-To: From: Sender: */ char *to; char *cc; char *bcc; char *subject; char *c_type; /* Content-Type: */ int c_encode; /* Content-Transfer-Encoding: */ time_t rtime; /* time of message reception */ int behave; /* from "x-action:" head item */ MsgObj *msg; struct _Mail *next; MsgObj _msgbuf[1]; /* it must be the last item. */ } Mail; typedef struct _Folder { int fid; /* folder identity */ int lst; /* start point from last lists */ int num; /* number of active letter in this folder */ int chg; /* changed letters */ int rm; /* removed letters */ int unrd; /* unread letters */ int pp : 1; /* used for postpone folder */ int fchg : 1; /* the change status of the folder */ Mail *mail; struct _Folder *next; struct _Folder *prev; char _namebuf[1]; } Folder; /* see message.c */ Folder *msg_loader(char *path, char *fldname, int fid, int pp, int beh); int msg_combine(Folder *fo); int msg_clean(Folder *fo); void msg_free_mailobj(Mail *m); int msg_block_dup(FILE *fin, FILE *fout); Mail *msg_search_id(Folder *fo, int id); int msg_last_actived(Folder *fo); int msg_dump(Mail *m, char *pager); int msg_appendto(Mail *m, char *fname); int msg_edit(Mail *m, char *editor); int msg_pipeto(Mail *m, char *piper, int ctl, char *sig); int msg_unpipe(Mail *m); void msg_statistics(Folder *fo); int msg_change_flag(Folder *fo); Mail *msg_pickout(Folder *fo, int id); void msg_insert(Folder *fo, Mail *m); Mail *msg_expand(Folder *fo, char *path, Mail *ins); void msg_dup_entry(Mail *dest, Mail *sour); long msg_duplicate(char *dest, char *sour); int msg_behave_bind(char *p); #endif [/code:1:bd1926abc9] gmail.h [code:1:bd1926abc9] #ifndef _GETMAIL_H #define _GETMAIL_H #if HAVE_REGEX_H #include #else #include "regex.h" #endif #define SPAM_IGNORE 0 #define SPAM_DELE 1 #define SPAM_KEEP 2 #define SPAM_ASK 3 #define SA_YES_DELE "true-delete" #define SA_YES_KEEP "true-keep" #define SA_YES_ASK "true_ask" #define SA_NO_DELE "false_delete" #define SA_NO_KEEP "false_keep" #define SA_NO_ASK "false_ask" #define SK_ID "id:" #define SK_SIZE "quota:" #define SK_FROM "from:" #define SK_SUBJECT "subject:" #define SK_ACTION "action:" #define SLPOOL 256 /* pool for Slnk structure */ #define PATHMAX 256 /* maximem length of path */ typedef struct _Spam { struct _Spam *next; int id; /* 0 is general identity */ int quota; /* message size quota */ char *from; char *subject; int logic; /* 0: normal logic, 1: minus logic */ int action; /* procession of matcher */ /* private structure area */ regex_t *from_reg; regex_t *sub_reg; int ireg; /* index of "preg" buffer */ regex_t preg[2]; /* by now for "from" and "subject" */ } Spam; typedef struct { Spam *sc; void *next; } Slnk; #define GP_POP3 1 #define GP_APOP 2 #define GMAIL_CHECK 1 #define GMAIL_FETCH 2 #define GMAIL_LIST 4 #define GMAIL_DELE 8 #define TOP_SMART 0 #define TOP_ALL 1 #define TOP_BRIEF 2 /* when operating on remote, this structure owns high priority that GMAIL */ struct gm_att { int topl; /* lines of mailbody for TOP check */ int tops; /* style of mailhead, 0 smart, 1 all */ //int quota; /* maximum mail size when retrieving it */ int delay; /* a short delay after logging in */ int cols; /* current columns in the screen */ /* in below come from command line */ int *cp_set; /* current processing set */ char *mbox; /* message box from command line */ int act; /* download action from command line */ char *user; char *pass; char *defbox; /* default mailbox if no mailbox specified */ char *hdmsk[HMMAX]; char *hdbuf; /* point to headmask&b;uer&ns;nide ''''buf'''' */ char buf[1]; }; typedef struct _GMAIL { /* read only part, looks on as attribution of POP3 connection Note that if there are same entries between this structure and attribution structure, use the attribution entries. They are mbox, act, user and pass. */ struct _GMAIL *next; char *host; char *lid; /* login id */ char &nbs&bp*pass; /* user''''s password */ char *mbox; /* mailbox for saving retrieved mails */ int act; /* operation in this session */ int protl; Slnk *slnk; /* spam filter chain */ int topspam; /* set if anti-spam need TOP command */ struct gm_att *attr; /* working varible */ int socket; /* put these here for close-convenient */ FILE *fp; /* against signal */ int *mlist; /* structure list of mails */ char *time_stamp; int msgs; /* number of messages */ int volm; /* volumn of messages */ int distop; /* 1: disable all TOP commmand relative */ char buf[1]; } GMAIL; #include "mhead.h" int gmail_main(GMAIL *gm, Head *head); int gmail_single(GMAIL *gm, Head *head); GMAIL *gmail_open(); GMAIL *gmail_cmdarg(char *arg); void gmail_close(); void gmail_host_list(); int gmail_set_action(char *s); Spam *spam_match_chain(Slnk *sl, Head *, int); Spam *spam_match_size(Slnk *sl, int size); int spam_need_top(Slnk *sl); Spam *spam_queue_open(); void spam_queue_free(); #ifdef DEBUG int spam_test(char *file); #endif /* see pop3.h */ int pop3_main(GMAIL *gm, Head *head); #endif [/code:1:bd1926abc9] Makefile.in [code:1:bd1926abc9] #export DEBUG = -g -DDEBUG VERSION = -DVERSION=\"0.9.16\" PREFIX = @prefix@ BINDIR = @prefix@/bin MANDIR = @prefix@/man/man1 CC = @CC@ INSTALL = install #DEFINES = -DOS_@OS_TYPE@ -DARCH_@ARCH_TYPE@ -D__USE_READLINE__ -DHAVE_CONFIG_H DEFINES = -DHAVE_CONFIG_H ${VERSION} CFLAGS = @CFLAGS@ -Ilib ${DEBUG} ${DEFINES} LDFLAGS = @LDFLAGS@ LIBS = -Llib -lsupp @LIBS@ OBJMZ = mailz.o mhead.o message.o memo.o mime.o strdate.o @LIBOBJS@ OBJPL = main.o mhead.o message.o folder.o smtp.o gmail.o pop3.o mime.o \ strdate.o @LIBOBJS@ DEBEXE = header strdate all: libsupp.a mailz pmail libsupp.a: (cd lib; make all) debug: $(DEBEXE) mailz: $(OBJMZ) $(CC) $(CFLAGS) -o $@ $(OBJMZ) $(LIBS) pmail: $(OBJPL) $(CC) $(CFLAGS) -o $@ $(OBJPL) $(LIBS) header: mhead.c $(CC) $(CFLAGS) -DEXECUTABLE -o $@ $< $(LIBS) strdate: strdate.c $(CC) $(CFLAGS) -DEXECUTABLE -o $@ $< $(LIBS) install: $(INSTALL) -s -o root -g root -m 0755 mailz $(BINDIR) $(INSTALL) -s -o root -g root -m 0755 pmail $(BINDIR) $(INSTALL) -o root -g root -m 0644 pmail.1 $(MANDIR) .PHONY: clean clean: rm -f *.o mailz pmail $(DEBEXE) core (cd lib; make clean) folder.o: folder.c defs.h getopt.o: getopt.c getopt1.o: getopt1.c gmail.o: gmail.c defs.h gmail.h mailz.o: mailz.c defs.h message.h main.o: main.c defs.h memo.o: memo.c defs.h message.o: message.c message.h defs.h mhead.o: mhead.c defs.h mime.o: mime.c defs.h smtp.o: smtp.c defs.h strdate.o: strdate.c |