📄 imapd.c
字号:
} *v = '\0'; /* tie off string */ *size = v - s; /* return size */ break; case '{': /* literal string */ s = *arg + 1; /* get size */ if (!isdigit (*s)) return NIL; if ((*size = i = strtoul (s,&t,10)) > MAXCLIENTLIT) { mm_notify (NIL,"Absurdly long client literal",ERROR); syslog (LOG_INFO,"Absurdly long client literal user=%.80s host=%.80s", user ? user : "???",tcp_clienthost ()); return NIL; } /* validate end of literal */ if (!t || (*t != '}') || t[1]) return NIL; if (litsp >= LITSTKLEN) { /* make sure don't overflow stack */ mm_notify (NIL,"Too many literals in command",ERROR); return NIL; } PSOUT (argrdy); /* tell client ready for argument */ PFLUSH; /* dump output buffer */ /* get a literal buffer */ s = v = litstk[litsp++] = (char *) fs_get (i+1); /* get literal under timeout */ alarm ((state != LOGIN) ? TIMEOUT : LOGINTIMEOUT); while (i--) *v++ = inchar (); alarm (0); /* stop timeout */ *v++ = NIL; /* make sure string tied off */ /* get new command tail */ slurp ((*arg = v = t),TMPLEN - (t - cmdbuf)); if (!strchr (t,'\012')) return flush (); /* reset strtok mechanism, tie off if done */ if (!strtok (t,"\015\012")) *t = '\0'; break; } if (*del = *t) { /* have a delimiter? */ *t++ = '\0'; /* yes, stomp on it */ *arg = t; /* update argument pointer */ } else *arg = NIL; /* no more arguments */ return s;}/* Snarf a command argument (simple jacket into parse_astring()) * Accepts: pointer to argument text pointer * Returns: argument */char *snarf (char **arg){ unsigned long i; char c; char *s = parse_astring (arg,&i,&c); return ((c == ' ') || !c) ? s : NIL;}/* Snarf a list command argument (simple jacket into parse_astring()) * Accepts: pointer to argument text pointer * Returns: argument */char *snarf_list (char **arg){ unsigned long i; char c; char *s,*t; if (!*arg) return NIL; /* better be an argument */ switch (**arg) { default: /* atom and/or wildcard chars */ for (s = t = *arg, i = 0; (*t > ' ') && (*t != '(') && (*t != ')') && (*t != '{') && (*t != '"') && (*t != '\\'); ++t,++i); if (c = *t) { /* have a delimiter? */ *t++ = '\0'; /* stomp on it */ *arg = t; /* update argument pointer */ } else *arg = NIL; break; case ')': case '\\': case '\0': case ' ': return NIL; /* empty name is bogus */ case '"': /* quoted string? */ case '{': /* or literal? */ s = parse_astring (arg,&i,&c); break; } return ((c == ' ') || !c) ? s : NIL;}/* Get a list of header lines * Accepts: pointer to string pointer * pointer to list flag * Returns: string list */STRINGLIST *parse_stringlist (char **s,int *list){ char c = ' ',*t; unsigned long i; STRINGLIST *ret = NIL,*cur = NIL; if (*s && **s == '(') { /* proper list? */ ++*s; /* for each item in list */ while ((c == ' ') && (t = parse_astring (s,&i,&c))) { /* get new block */ if (cur) cur = cur->next = mail_newstringlist (); else cur = ret = mail_newstringlist (); /* note text */ cur->text.data = (unsigned char *) fs_get (i + 1); memcpy (cur->text.data,t,i); cur->text.size = i; /* and size */ } /* must be end of list */ if (c != ')') mail_free_stringlist (&ret); } if (t = *s) { /* need to reload strtok() state? */ /* end of a list? */ if (*list && (*t == ')') && !t[1]) *list = NIL; else { *--t = ' '; /* patch a space back in */ *--t = 'x'; /* and a hokey character before that */ t = strtok (t," "); /* reset to *s */ } } return ret;}/* Parse search criteria * Accepts: search program to write criteria into * pointer to argument text pointer * maximum message number * maximum UID * logical nesting depth * Returns: T if success, NIL if error */long parse_criteria (SEARCHPGM *pgm,char **arg,unsigned long maxmsg, unsigned long maxuid,unsigned long depth){ if (arg && *arg) { /* must be an argument */ /* parse criteria */ do if (!parse_criterion (pgm,arg,maxmsg,maxuid,depth)) return NIL; /* as long as a space delimiter */ while (**arg == ' ' && (*arg)++); /* failed if not end of criteria */ if (**arg && **arg != ')') return NIL; } return T; /* success */}/* Parse a search criterion * Accepts: search program to write criterion into * pointer to argument text pointer * maximum message number * maximum UID * logical nesting depth * Returns: T if success, NIL if error */long parse_criterion (SEARCHPGM *pgm,char **arg,unsigned long maxmsg, unsigned long maxuid,unsigned long depth){ unsigned long i; char c = NIL,*s,*t,*v,*tail,*del; SEARCHSET **set; SEARCHPGMLIST **not; SEARCHOR **or; SEARCHHEADER **hdr; long ret = NIL; /* better be an argument */ if ((depth > 50) || !(arg && *arg)); else if (**arg == '(') { /* list of criteria? */ (*arg)++; /* yes, parse the criteria */ if (parse_criteria (pgm,arg,maxmsg,maxuid,depth+1) && **arg == ')') { (*arg)++; /* skip closing paren */ ret = T; /* successful parse of list */ } } else { /* find end of criterion */ if (!(tail = strpbrk ((s = *arg)," )"))) tail = *arg + strlen (*arg); c = *(del = tail); /* remember the delimiter */ *del = '\0'; /* tie off criterion */ switch (*ucase (s)) { /* dispatch based on character */ case '*': /* sequence */ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if (*(set = &pgm->msgno)){/* already a sequence? */ /* silly, but not as silly as the client! */ for (not = &pgm->search_not; *not; not = &(*not)->next); *not = mail_newsearchpgmlist (); set = &((*not)->pgm->search_not = mail_newsearchpgmlist ())->pgm->msgno; } ret = crit_set (set,&s,maxmsg) && (tail == s); break; case 'A': /* possible ALL, ANSWERED */ if (!strcmp (s+1,"LL")) ret = T; else if (!strcmp (s+1,"NSWERED")) ret = pgm->answered = T; break; case 'B': /* possible BCC, BEFORE, BODY */ if (!strcmp (s+1,"CC") && c == ' ' && *++tail) ret = crit_string (&pgm->bcc,&tail); else if (!strcmp (s+1,"EFORE") && c == ' ' && *++tail) ret = crit_date (&pgm->before,&tail); else if (!strcmp (s+1,"ODY") && c == ' ' && *++tail) ret = crit_string (&pgm->body,&tail); break; case 'C': /* possible CC */ if (!strcmp (s+1,"C") && c == ' ' && *++tail) ret = crit_string (&pgm->cc,&tail); break; case 'D': /* possible DELETED */ if (!strcmp (s+1,"ELETED")) ret = pgm->deleted = T; if (!strcmp (s+1,"RAFT")) ret = pgm->draft = T; break; case 'F': /* possible FLAGGED, FROM */ if (!strcmp (s+1,"LAGGED")) ret = pgm->flagged = T; else if (!strcmp (s+1,"ROM") && c == ' ' && *++tail) ret = crit_string (&pgm->from,&tail); break; case 'H': /* possible HEADER */ if (!strcmp (s+1,"EADER") && c == ' ' && *(v = tail + 1) && (s = parse_astring (&v,&i,&c)) && i && c == ' ' && (t = parse_astring (&v,&i,&c))) { for (hdr = &pgm->header; *hdr; hdr = &(*hdr)->next); *hdr = mail_newsearchheader (s,t); /* update tail, restore delimiter */ *(tail = v ? v - 1 : t + i) = c; ret = T; /* success */ } break; case 'K': /* possible KEYWORD */ if (!strcmp (s+1,"EYWORD") && c == ' ' && *++tail) ret = crit_string (&pgm->keyword,&tail); break; case 'L': if (!strcmp (s+1,"ARGER") && c == ' ' && *++tail) ret = crit_number (&pgm->larger,&tail); break; case 'N': /* possible NEW, NOT */ if (!strcmp (s+1,"EW")) ret = pgm->recent = pgm->unseen = T; else if (!strcmp (s+1,"OT") && c == ' ' && *++tail) { for (not = &pgm->search_not; *not; not = &(*not)->next); *not = mail_newsearchpgmlist (); ret = parse_criterion ((*not)->pgm,&tail,maxmsg,maxuid,depth+1); } break; case 'O': /* possible OLD, ON */ if (!strcmp (s+1,"LD")) ret = pgm->old = T; else if (!strcmp (s+1,"N") && c == ' ' && *++tail) ret = crit_date (&pgm->on,&tail); else if (!strcmp (s+1,"R") && c == ' ') { for (or = &pgm->search_or; *or; or = &(*or)->next); *or = mail_newsearchor (); ret = *++tail && parse_criterion((*or)->first,&tail,maxmsg,maxuid, depth+1) && *tail == ' ' && *++tail && parse_criterion ((*or)->second,&tail,maxmsg,maxuid,depth+1); } break; case 'R': /* possible RECENT */ if (!strcmp (s+1,"ECENT")) ret = pgm->recent = T; break; case 'S': /* possible SEEN, SINCE, SUBJECT */ if (!strcmp (s+1,"EEN")) ret = pgm->seen = T; else if (!strcmp (s+1,"ENTBEFORE") && c == ' ' && *++tail) ret = crit_date (&pgm->sentbefore,&tail); else if (!strcmp (s+1,"ENTON") && c == ' ' && *++tail) ret = crit_date (&pgm->senton,&tail); else if (!strcmp (s+1,"ENTSINCE") && c == ' ' && *++tail) ret = crit_date (&pgm->sentsince,&tail); else if (!strcmp (s+1,"INCE") && c == ' ' && *++tail) ret = crit_date (&pgm->since,&tail); else if (!strcmp (s+1,"MALLER") && c == ' ' && *++tail) ret = crit_number (&pgm->smaller,&tail); else if (!strcmp (s+1,"UBJECT") && c == ' ' && *++tail) ret = crit_string (&pgm->subject,&tail); break; case 'T': /* possible TEXT, TO */ if (!strcmp (s+1,"EXT") && c == ' ' && *++tail) ret = crit_string (&pgm->text,&tail); else if (!strcmp (s+1,"O") && c == ' ' && *++tail) ret = crit_string (&pgm->to,&tail); break; case 'U': /* possible UID, UN* */ if (!strcmp (s+1,"ID") && c== ' ' && *++tail) { if (*(set = &pgm->uid)){/* already a sequence? */ /* silly, but not as silly as the client! */ for (not = &pgm->search_not; *not; not = &(*not)->next); *not = mail_newsearchpgmlist (); set = &((*not)->pgm->search_not = mail_newsearchpgmlist ())->pgm->uid; } ret = crit_set (set,&tail,maxuid); } else if (!strcmp (s+1,"NANSWERED")) ret = pgm->unanswered = T; else if (!strcmp (s+1,"NDELETED")) ret = pgm->undeleted = T; else if (!strcmp (s+1,"NDRAFT")) ret = pgm->undraft = T; else if (!strcmp (s+1,"NFLAGGED")) ret = pgm->unflagged = T; else if (!strcmp (s+1,"NKEYWORD") && c == ' ' && *++tail) ret = crit_string (&pgm->unkeyword,&tail); else if (!strcmp (s+1,"NSEEN")) ret = pgm->unseen = T; break; default: /* oh dear */ break; } if (ret) { /* only bother if success */ *del = c; /* restore delimiter */ *arg = tail; /* update argument pointer */ } } return ret; /* return more to come */}/* Parse a search date criterion * Accepts: date to write into * pointer to argument text pointer * Returns: T if success, NIL if error */long crit_date (unsigned short *date,char **arg){ /* handle quoted form */ if (**arg != '"') return crit_date_work (date,arg); (*arg)++; /* skip past opening quote */ if (!(crit_date_work (date,arg) && (**arg == '"'))) return NIL; (*arg)++; /* skip closing quote */ return T;}/* Worker routine to parse a search date criterion * Accepts: date to write into * pointer to argument text pointer * Returns: T if success, NIL if error */long crit_date_work (unsigned short *date,char **arg){ int d,m,y; /* day */ if (isdigit (d = *(*arg)++) || ((d == ' ') && isdigit (**arg))) { if (d == ' ') d = 0; /* leading space */ else d -= '0'; /* first digit */ if (isdigit (**arg)) { /* if a second digit */ d *= 10; /* slide over first digit */ d += *(*arg)++ - '0'; /* second digit */ } if ((**arg == '-') && (y = *++(*arg))) { m = (y >= 'a' ? y - 'a' : y - 'A') * 1024; if ((y = *++(*arg))) { m += (y >= 'a' ? y - 'a' : y - 'A') * 32; if ((y = *++(*arg))) { m += (y >= 'a' ? y - 'a' : y - 'A'); switch (m) { /* determine the month */ case (('J'-'A') * 1024) + (('A'-'A') * 32) + ('N'-'A'): m = 1; break; case (('F'-'A') * 1024) + (('E'-'A') * 32) + ('B'-'A'): m = 2; break; case (('M'-'A') * 1024) + (('A'-'A') * 32) + ('R'-'A'): m = 3; break; case (('A'-'A') * 1024) + (('P'-'A') * 32) + ('R'-'A'): m = 4; break; case (('M'-'A') * 1024) + (('A'-'A') * 32) + ('Y'-'A'): m = 5; break; case (('J'-'A') * 1024) + (('U'-'A') * 32) + ('N'-'A'): m = 6; break; case (('J'-'A') * 1024) + (('U'-'A') * 32) + ('L'-'A'): m = 7; break; case (('A'-'A') * 1024) + (('U'-'A') * 32) + ('G'-'A'): m = 8; break; case (('S'-'A') * 1024) + (('E'-'A') * 32) + ('P'-'A'): m = 9; break; case (('O'-'A') * 1024) + (('C'-'A') * 32) + ('T'-'A'): m = 10;break; case (('N'-'A') * 1024) + (('O'-'A') * 32) + ('V'-'A'): m = 11;break; case (('D'-'A') * 1024) + (('E'-'A') * 32) + ('C'-'A'): m = 12;break; default: return NIL; } if ((*++(*arg) == '-') && isdigit (*++(*arg))) { y = 0; /* init year */ do { y *= 10; /* add this number */ y += *(*arg)++ - '0'; } while (isdigit (**arg)); /* minimal validity check of date */ if (d < 1 || d > 31 || m < 1 || m > 12 || y < 0) return NIL; /* Tenex/ARPAnet began in 1969 */ if (y
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -