📄 imap4r1.c
字号:
/* IMAP authenticate * Accepts: stream to authenticate * parsed network mailbox structure * scratch buffer * place to return user name * Returns: T on success, NIL on failure */long imap_auth (MAILSTREAM *stream,NETMBX *mb,char *tmp,char *usr){ unsigned long trial,ua; int ok; char tag[16]; char *lsterr = NIL; AUTHENTICATOR *at; IMAPPARSEDREPLY *reply; for (ua = LOCAL->cap.auth, LOCAL->saslcancel = NIL; LOCAL->netstream && ua && (at = mail_lookup_auth (find_rightmost_bit (&ua) + 1));) { if (lsterr) { /* previous authenticator failed? */ sprintf (tmp,"Retrying using %s authentication after %.80s", at->name,lsterr); mm_log (tmp,NIL); fs_give ((void **) &lsterr); } trial = 0; /* initial trial count */ tmp[0] = '\0'; /* no error */ do { /* gensym a new tag */ if (lsterr) { /* previous attempt with this one failed? */ sprintf (tmp,"Retrying %s authentication after %.80s",at->name,lsterr); mm_log (tmp,WARN); fs_give ((void **) &lsterr); } LOCAL->saslcancel = NIL; sprintf (tag,"%08lx",0xffffffff & (stream->gensym++)); /* build command */ sprintf (tmp,"%s AUTHENTICATE %s",tag,at->name); if (imap_soutr (stream,tmp)) { /* hide client authentication responses */ if (!(at->flags & AU_SECURE)) LOCAL->sensitive = T; ok = (*at->client) (imap_challenge,imap_response,"imap",mb,stream, &trial,usr); LOCAL->sensitive = NIL; /* unhide */ /* make sure have a response */ if (!(reply = &LOCAL->reply)->tag) reply = imap_fake (stream,tag, "[CLOSED] IMAP connection broken (authenticate)"); else if (compare_cstring (reply->tag,tag)) while (compare_cstring ((reply = imap_reply (stream,tag))->tag,tag)) imap_soutr (stream,"*"); /* good if SASL ok and success response */ if (ok && imap_OK (stream,reply)) return T; if (!trial) { /* if main program requested cancellation */ mm_log ("IMAP Authentication cancelled",ERROR); return NIL; } /* no error if protocol-initiated cancel */ lsterr = cpystr (reply->text); } } while (LOCAL->netstream && !LOCAL->byeseen && trial && (trial < imap_maxlogintrials)); } if (lsterr) { /* previous authenticator failed? */ if (!LOCAL->saslcancel) { /* don't do this if a cancel */ sprintf (tmp,"Can not authenticate to IMAP server: %.80s",lsterr); mm_log (tmp,ERROR); } fs_give ((void **) &lsterr); } return NIL; /* ran out of authenticators */}/* IMAP login * Accepts: stream to login * parsed network mailbox structure * scratch buffer of length MAILTMPLEN * place to return user name * Returns: T on success, NIL on failure */long imap_login (MAILSTREAM *stream,NETMBX *mb,char *pwd,char *usr){ unsigned long trial = 0; IMAPPARSEDREPLY *reply; IMAPARG *args[3]; IMAPARG ausr,apwd; long ret = NIL; if (stream->secure) /* never do LOGIN if want security */ mm_log ("Can't do secure authentication with this server",ERROR); /* never do LOGIN if server disabled it */ else if (LOCAL->cap.logindisabled) mm_log ("Server disables LOGIN, no recognized SASL authenticator",ERROR); else if (mb->authuser[0]) /* never do LOGIN with /authuser */ mm_log ("Can't do /authuser with this server",ERROR); else { /* OK to try login */ ausr.type = apwd.type = ASTRING; ausr.text = (void *) usr; apwd.text = (void *) pwd; args[0] = &ausr; args[1] = &apwd; args[2] = NIL; do { pwd[0] = 0; /* prompt user for password */ mm_login (mb,usr,pwd,trial++); if (pwd[0]) { /* send login command if have password */ LOCAL->sensitive = T; /* hide this command */ /* send "LOGIN usr pwd" */ if (imap_OK (stream,reply = imap_send (stream,"LOGIN",args))) ret = LONGT; /* success */ else { mm_log (reply->text,WARN); if (!LOCAL->referral && (trial == imap_maxlogintrials)) mm_log ("Too many login failures",ERROR); } LOCAL->sensitive = NIL; /* unhide */ } /* user refused to give password */ else mm_log ("Login aborted",ERROR); } while (!ret && pwd[0] && (trial < imap_maxlogintrials) && LOCAL->netstream && !LOCAL->byeseen && !LOCAL->referral); } memset (pwd,0,MAILTMPLEN); /* erase password */ return ret;}/* Get challenge to authenticator in binary * Accepts: stream * pointer to returned size * Returns: challenge or NIL if not challenge */void *imap_challenge (void *s,unsigned long *len){ char tmp[MAILTMPLEN]; void *ret = NIL; MAILSTREAM *stream = (MAILSTREAM *) s; IMAPPARSEDREPLY *reply = NIL; /* get tagged response or challenge */ while (stream && LOCAL->netstream && (reply = imap_parse_reply (stream,net_getline (LOCAL->netstream))) && !strcmp (reply->tag,"*")) imap_parse_unsolicited (stream,reply); /* parse challenge if have one */ if (stream && LOCAL->netstream && reply && reply->tag && (*reply->tag == '+') && !reply->tag[1] && reply->text && !(ret = rfc822_base64 ((unsigned char *) reply->text, strlen (reply->text),len))) { sprintf (tmp,"IMAP SERVER BUG (invalid challenge): %.80s", (char *) reply->text); mm_log (tmp,ERROR); } return ret;}/* Send authenticator response in BASE64 * Accepts: MAIL stream * string to send * length of string * Returns: T if successful, else NIL */long imap_response (void *s,char *response,unsigned long size){ MAILSTREAM *stream = (MAILSTREAM *) s; unsigned long i,j,ret; char *t,*u; if (response) { /* make CRLFless BASE64 string */ if (size) { for (t = (char *) rfc822_binary ((void *) response,size,&i),u = t,j = 0; j < i; j++) if (t[j] > ' ') *u++ = t[j]; *u = '\0'; /* tie off string for mm_dlog() */ if (stream->debug) mail_dlog (t,LOCAL->sensitive); /* append CRLF */ *u++ = '\015'; *u++ = '\012'; ret = net_sout (LOCAL->netstream,t,u - t); fs_give ((void **) &t); } else ret = imap_soutr (stream,""); } else { /* abort requested */ ret = imap_soutr (stream,"*"); LOCAL->saslcancel = T; /* mark protocol-requested SASL cancel */ } return ret;}/* IMAP close * Accepts: MAIL stream * option flags */void imap_close (MAILSTREAM *stream,long options){ THREADER *thr,*t; IMAPPARSEDREPLY *reply; if (stream && LOCAL) { /* send "LOGOUT" */ if (!LOCAL->byeseen) { /* don't even think of doing it if saw a BYE */ /* expunge silently if requested */ if (options & CL_EXPUNGE) imap_send (stream,LEVELIMAP4 (stream) ? "CLOSE" : "EXPUNGE",NIL); if (LOCAL->netstream && !imap_OK (stream,reply = imap_send (stream,"LOGOUT",NIL))) mm_log (reply->text,WARN); } /* close NET connection if still open */ if (LOCAL->netstream) net_close (LOCAL->netstream); LOCAL->netstream = NIL; /* free up memory */ if (LOCAL->sortdata) fs_give ((void **) &LOCAL->sortdata); if (LOCAL->namespace) { mail_free_namespace (&LOCAL->namespace[0]); mail_free_namespace (&LOCAL->namespace[1]); mail_free_namespace (&LOCAL->namespace[2]); fs_give ((void **) &LOCAL->namespace); } if (LOCAL->threaddata) mail_free_threadnode (&LOCAL->threaddata); /* flush threaders */ if (thr = LOCAL->cap.threader) while (t = thr) { fs_give ((void **) &t->name); thr = t->next; fs_give ((void **) &t); } if (LOCAL->referral) fs_give ((void **) &LOCAL->referral); if (LOCAL->user) fs_give ((void **) &LOCAL->user); if (LOCAL->reply.line) fs_give ((void **) &LOCAL->reply.line); if (LOCAL->reform) fs_give ((void **) &LOCAL->reform); /* nuke the local data */ fs_give ((void **) &stream->local); }}/* IMAP fetch fast information * Accepts: MAIL stream * sequence * option flags * * Generally, imap_structure is preferred */void imap_fast (MAILSTREAM *stream,char *sequence,long flags){ IMAPPARSEDREPLY *reply = imap_fetch (stream,sequence,flags & FT_UID); if (!imap_OK (stream,reply)) mm_log (reply->text,ERROR);}/* IMAP fetch flags * Accepts: MAIL stream * sequence * option flags */void imap_flags (MAILSTREAM *stream,char *sequence,long flags){ /* send "FETCH sequence FLAGS" */ char *cmd = (LEVELIMAP4 (stream) && (flags & FT_UID)) ? "UID FETCH":"FETCH"; IMAPPARSEDREPLY *reply; IMAPARG *args[3],aseq,aatt; if (LOCAL->loser) sequence = imap_reform_sequence (stream,sequence, flags & FT_UID); aseq.type = SEQUENCE; aseq.text = (void *) sequence; aatt.type = ATOM; aatt.text = (void *) "FLAGS"; args[0] = &aseq; args[1] = &aatt; args[2] = NIL; if (!imap_OK (stream,reply = imap_send (stream,cmd,args))) mm_log (reply->text,ERROR);}/* IMAP fetch overview * Accepts: MAIL stream, sequence bits set * pointer to overview return function * Returns: T if successful, NIL otherwise */long imap_overview (MAILSTREAM *stream,overview_t ofn){ MESSAGECACHE *elt; ENVELOPE *env; OVERVIEW ov; char *s,*t; unsigned long i,start,last,len,slen; if (!LOCAL->netstream) return NIL; /* build overview sequence */ for (i = 1,len = start = last = 0,s = t = NIL; i <= stream->nmsgs; ++i) if ((elt = mail_elt (stream,i))->sequence) { if (!elt->private.msg.env) { if (s) { /* continuing a sequence */ if (i == last + 1) last = i; else { /* end of range */ if (last != start) sprintf (t,":%lu,%lu",last,i); else sprintf (t,",%lu",i); if ((len - (slen = (t += strlen (t)) - s)) < 20) { fs_resize ((void **) &s,len += MAILTMPLEN); t = s + slen; /* relocate current pointer */ } start = last = i; /* begin a new range */ } } else { /* first time, start new buffer */ s = (char *) fs_get (len = MAILTMPLEN); sprintf (s,"%lu",start = last = i); t = s + strlen (s); /* end of buffer */ } } } /* last sequence */ if (last != start) sprintf (t,":%lu",last); if (s) { /* prefetch as needed */ imap_fetch (stream,s,FT_NEEDENV); fs_give ((void **) &s); } ov.optional.lines = 0; /* now overview each message */ ov.optional.xref = NIL; if (ofn) for (i = 1; i <= stream->nmsgs; i++) if (((elt = mail_elt (stream,i))->sequence) && (env = mail_fetch_structure (stream,i,NIL,NIL)) && ofn) { ov.subject = env->subject; ov.from = env->from; ov.date = env->date; ov.message_id = env->message_id; ov.references = env->references; ov.optional.octets = elt->rfc822_size; (*ofn) (stream,mail_uid (stream,i),&ov,i); } return LONGT;}/* IMAP fetch structure * Accepts: MAIL stream * message # to fetch * pointer to return body * option flags * Returns: envelope of this message, body returned in body value * * Fetches the "fast" information as well */ENVELOPE *imap_structure (MAILSTREAM *stream,unsigned long msgno,BODY **body, long flags){ unsigned long i,j,k,x; char *s,seq[MAILTMPLEN],tmp[MAILTMPLEN]; MESSAGECACHE *elt; ENVELOPE **env; BODY **b; IMAPPARSEDREPLY *reply = NIL; IMAPARG *args[3],aseq,aatt; SEARCHSET *set = LOCAL->lookahead; LOCAL->lookahead = NIL; args[0] = &aseq; args[1] = &aatt; args[2] = NIL; aseq.type = SEQUENCE; aseq.text = (void *) seq; aatt.type = ATOM; aatt.text = NIL; if (flags & FT_UID) /* see if can find msgno from UID */ for (i = 1; i <= stream->nmsgs; i++) if ((elt = mail_elt (stream,i))->private.uid == msgno) { msgno = i; /* found msgno, use it from now on */ flags &= ~FT_UID; /* no longer a UID fetch */ } sprintf (s = seq,"%lu",msgno);/* initial sequence */ if (LEVELIMAP4 (stream) && (flags & FT_UID)) { /* UID fetching is requested and we can't map the UID to a message sequence * number. Assume that the message isn't cached at all. */ if (!imap_OK (stream,reply = imap_fetch (stream,seq,FT_NEEDENV + (body ? FT_NEEDBODY : NIL) + (flags & (FT_UID + FT_NOHDRS))))) mm_log (reply->text,ERROR); /* now hunt for this UID */ for (i = 1; i <= stream->nmsgs; i++) if ((elt = mail_elt (stream,i))->private.uid == msgno) { if (body) *body = elt->private.msg.body;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -