📄 pop3.c
字号:
status.uidnext = tstream->uid_last + 1; status.uidvalidity = tstream->uid_validity; /* pass status to main program */ mm_status (tstream,mbx,&status); if (stream != tstream) mail_close (tstream); ret = LONGT; } return ret; /* success */}/* POP3 mail open * Accepts: stream to open * Returns: stream on success, NIL on failure */MAILSTREAM *pop3_open (MAILSTREAM *stream){ unsigned long i,j; char *s,*t,tmp[MAILTMPLEN],usr[MAILTMPLEN]; NETMBX mb; MESSAGECACHE *elt; /* return prototype for OP_PROTOTYPE call */ if (!stream) return &pop3proto; mail_valid_net_parse (stream->mailbox,&mb); usr[0] = '\0'; /* initially no user name */ if (stream->local) fatal ("pop3 recycle stream"); /* /anonymous not supported */ if (mb.anoflag || stream->anonymous) { mm_log ("Anonymous POP3 login not available",ERROR); return NIL; } /* /readonly not supported either */ if (mb.readonlyflag || stream->rdonly) { mm_log ("Read-only POP3 access not available",ERROR); return NIL; } /* copy other switches */ if (mb.dbgflag) stream->debug = T; if (mb.secflag) stream->secure = T; mb.trysslflag = stream->tryssl = (mb.trysslflag || stream->tryssl) ? T : NIL; stream->local = /* instantiate localdata */ (void *) memset (fs_get (sizeof (POP3LOCAL)),0,sizeof (POP3LOCAL)); stream->sequence++; /* bump sequence number */ stream->perm_deleted = T; /* deleted is only valid flag */ if ((LOCAL->netstream = /* try to open connection */ net_open (&mb,NIL,pop3_port ? pop3_port : POP3TCPPORT, (NETDRIVER *) mail_parameters (NIL,GET_SSLDRIVER,NIL), "*pop3s",pop3_sslport ? pop3_sslport : POP3SSLPORT)) && pop3_reply (stream)) { mm_log (LOCAL->reply,NIL); /* give greeting */ if (!pop3_auth (stream,&mb,tmp,usr)) pop3_close (stream,NIL); else if (pop3_send (stream,"STAT",NIL)) { int silent = stream->silent; stream->silent = T; sprintf (tmp,"{%.200s:%lu/pop3", (long) mail_parameters (NIL,GET_TRUSTDNS,NIL) ? net_host (LOCAL->netstream) : mb.host, net_port (LOCAL->netstream)); if (mb.tlsflag) strcat (tmp,"/tls"); if (mb.tlssslv23) strcat (tmp,"/tls-sslv23"); if (mb.notlsflag) strcat (tmp,"/notls"); if (mb.sslflag) strcat (tmp,"/ssl"); if (mb.novalidate) strcat (tmp,"/novalidate-cert"); if (LOCAL->loser = mb.loser) strcat (tmp,"/loser"); if (stream->secure) strcat (tmp,"/secure"); sprintf (tmp + strlen (tmp),"/user=\"%s\"}%s",usr,mb.mailbox); stream->inbox = T; /* always INBOX */ fs_give ((void **) &stream->mailbox); stream->mailbox = cpystr (tmp); /* notify upper level */ mail_exists (stream,stream->uid_last = strtoul (LOCAL->reply,NIL,10)); mail_recent (stream,stream->nmsgs); /* instantiate elt */ for (i = 0; i < stream->nmsgs;) { elt = mail_elt (stream,++i); elt->valid = elt->recent = T; elt->private.uid = i; } /* trust LIST output if new server */ if (!LOCAL->loser && LOCAL->cap.capa && pop3_send (stream,"LIST",NIL)) { while ((s = net_getline (LOCAL->netstream)) && (*s != '.')) { if ((i = strtoul (s,&t,10)) && (i <= stream->nmsgs) && (j = strtoul (t,NIL,10))) mail_elt (stream,i)->rfc822_size = j; fs_give ((void **) &s); } /* flush final dot */ if (s) fs_give ((void **) &s); else { /* lost connection */ mm_log ("POP3 connection broken while itemizing messages",ERROR); pop3_close (stream,NIL); return NIL; } } stream->silent = silent; /* notify main program */ mail_exists (stream,stream->nmsgs); /* notify if empty */ if (!(stream->nmsgs || stream->silent)) mm_log ("Mailbox is empty",WARN); } else { /* error in STAT */ mm_log (LOCAL->reply,ERROR); pop3_close (stream,NIL); /* too bad */ } } else { /* connection failed */ if (LOCAL->reply) mm_log (LOCAL->reply,ERROR); pop3_close (stream,NIL); /* failed, clean up */ } return LOCAL ? stream : NIL; /* if stream is alive, return to caller */}/* POP3 capabilities * Accepts: stream * authenticator flags * Returns: T on success, NIL on failure */long pop3_capa (MAILSTREAM *stream,long flags){ unsigned long i; char *s,*t,*r,*args; if (LOCAL->cap.implementation)/* zap all old capabilities */ fs_give ((void **) &LOCAL->cap.implementation); memset (&LOCAL->cap,0,sizeof (LOCAL->cap)); /* get server capabilities */ if (pop3_send (stream,"CAPA",NIL)) LOCAL->cap.capa = T; else { LOCAL->cap.user = T; /* guess worst-case old server */ return NIL; /* no CAPA on this server */ } while ((t = net_getline (LOCAL->netstream)) && (t[1] || (*t != '.'))) { if (stream->debug) mm_dlog (t); /* get optional capability arguments */ if (args = strchr (t,' ')) *args++ = '\0'; if (!compare_cstring (t,"STLS")) LOCAL->cap.stls = T; else if (!compare_cstring (t,"PIPELINING")) LOCAL->cap.pipelining = T; else if (!compare_cstring (t,"RESP-CODES")) LOCAL->cap.respcodes = T; else if (!compare_cstring (t,"TOP")) LOCAL->cap.top = T; else if (!compare_cstring (t,"UIDL")) LOCAL->cap.uidl = T; else if (!compare_cstring (t,"USER")) LOCAL->cap.user = T; else if (!compare_cstring (t,"IMPLEMENTATION") && args) LOCAL->cap.implementation = cpystr (args); else if (!compare_cstring (t,"EXPIRE") && args) { LOCAL->cap.expire = T; /* note that it is present */ if (s = strchr(args,' ')){/* separate time from possible USER */ *s++ = '\0'; /* in case they add something after USER */ if ((strlen (s) > 4) && (s[4] == ' ')) s[4] = '\0'; } LOCAL->cap.expire = /* get expiration time */ (!compare_cstring (args,"NEVER")) ? 65535 : ((s && !compare_cstring (s,"USER")) ? -atoi (args) : atoi (args)); } else if (!compare_cstring (t,"LOGIN-DELAY") && args) { LOCAL->cap.logindelay = T;/* note that it is present */ if (s = strchr(args,' ')){/* separate time from possible USER */ *s++ = '\0'; /* in case they add something after USER */ if ((strlen (s) > 4) && (s[4] == ' ')) s[4] = '\0'; } /* get delay time */ LOCAL->cap.delaysecs = (s && !compare_cstring (s,"USER")) ? -atoi (args) : atoi (args); } else if (!compare_cstring (t,"SASL") && args) for (args = strtok_r (args," ",&r); args; args = strtok_r (NIL," ",&r)) if ((i = mail_lookup_auth_name (args,flags)) && (--i < MAXAUTHENTICATORS)) LOCAL->cap.sasl |= (1 << i); fs_give ((void **) &t); } if (t) { /* flush end of text indicator */ if (stream->debug) mm_dlog (t); fs_give ((void **) &t); } return LONGT;}/* POP3 authenticate * 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 pop3_auth (MAILSTREAM *stream,NETMBX *mb,char *pwd,char *usr){ unsigned long i,trial,auths = 0; char *t; AUTHENTICATOR *at; long ret = NIL; long flags = (stream->secure ? AU_SECURE : NIL) | (mb->authuser[0] ? AU_AUTHUSER : NIL); long capaok = pop3_capa (stream,flags); NETDRIVER *ssld = (NETDRIVER *) mail_parameters (NIL,GET_SSLDRIVER,NIL); sslstart_t stls = (sslstart_t) mail_parameters (NIL,GET_SSLSTART,NIL); /* server has TLS? */ if (stls && LOCAL->cap.stls && !mb->sslflag && !mb->notlsflag && pop3_send (stream,"STLS",NIL)) { mb->tlsflag = T; /* TLS OK, get into TLS at this end */ LOCAL->netstream->dtb = ssld; if (!(LOCAL->netstream->stream = (*stls) (LOCAL->netstream->stream,mb->host, (mb->tlssslv23 ? NIL : NET_TLSCLIENT) | (mb->novalidate ? NET_NOVALIDATECERT : NIL)))) { /* drat, drop this connection */ if (LOCAL->netstream) net_close (LOCAL->netstream); LOCAL->netstream= NIL; return NIL; /* TLS negotiation failed */ } pop3_capa (stream,flags); /* get capabilities now that TLS in effect */ } else if (mb->tlsflag) { /* user specified /tls but can't do it */ mm_log ("Unable to negotiate TLS with this server",ERROR); return NIL; } /* get authenticators from capabilities */ if (capaok) auths = LOCAL->cap.sasl; /* get list of authenticators */ else if (pop3_send (stream,"AUTH",NIL)) { while ((t = net_getline (LOCAL->netstream)) && (t[1] || (*t != '.'))) { if (stream->debug) mm_dlog (t); if ((i = mail_lookup_auth_name (t,flags)) && (--i < MAXAUTHENTICATORS)) auths |= (1 << i); fs_give ((void **) &t); } if (t) { /* flush end of text indicator */ if (stream->debug) mm_dlog (t); fs_give ((void **) &t); } } /* disable LOGIN if PLAIN also advertised */ if ((i = mail_lookup_auth_name ("PLAIN",NIL)) && (--i < MAXAUTHENTICATORS) && (auths & (1 << i)) && (i = mail_lookup_auth_name ("LOGIN",NIL)) && (--i < MAXAUTHENTICATORS)) auths &= ~(1 << i); if (auths) { /* got any authenticators? */ if ((long) mail_parameters (NIL,GET_TRUSTDNS,NIL)) { /* remote name for authentication */ strncpy (mb->host,(long) mail_parameters (NIL,GET_SASLUSESPTRNAME,NIL) ? net_remotehost (LOCAL->netstream) : net_host (LOCAL->netstream), NETMAXHOST-1); mb->host[NETMAXHOST-1] = '\0'; } for (t = NIL, LOCAL->saslcancel = NIL; !ret && LOCAL->netstream && auths && (at = mail_lookup_auth (find_rightmost_bit (&auths)+1)); ) { if (t) { /* previous authenticator failed? */ sprintf (pwd,"Retrying using %.80s authentication after %.80s", at->name,t); mm_log (pwd,NIL); fs_give ((void **) &t); } trial = 0; /* initial trial count */ do { if (t) { sprintf (pwd,"Retrying %s authentication after %.80s",at->name,t); mm_log (pwd,WARN); fs_give ((void **) &t); } LOCAL->saslcancel = NIL; if (pop3_send (stream,"AUTH",at->name)) { /* hide client authentication responses */ if (!(at->flags & AU_SECURE)) LOCAL->sensitive = T; if ((*at->client) (pop3_challenge,pop3_response,"pop",mb,stream, &trial,usr) && LOCAL->response) { if (*LOCAL->response == '+') ret = LONGT; /* if main program requested cancellation */ else if (!trial) mm_log ("POP3 Authentication cancelled",ERROR); } LOCAL->sensitive=NIL; /* unhide */ } /* remember response if error and no cancel */ if (!ret && trial) t = cpystr (LOCAL->reply); } while (!ret && trial && (trial < pop3_maxlogintrials) && LOCAL->netstream); } if (t) { /* previous authenticator failed? */ if (!LOCAL->saslcancel) { /* don't do this if a cancel */ sprintf (pwd,"Can not authenticate to POP3 server: %.80s",t); mm_log (pwd,ERROR); } fs_give ((void **) &t); } } else if (stream->secure) mm_log ("Can't do secure authentication with this server",ERROR); else if (mb->authuser[0]) mm_log ("Can't do /authuser with this server",ERROR); else if (!LOCAL->cap.user) mm_log ("Can't login to this server",ERROR); else { /* traditional login */ trial = 0; /* initial trial count */ do { pwd[0] = 0; /* prompt user for password */ mm_login (mb,usr,pwd,trial++); if (pwd[0]) { /* send login sequence if have password */ if (pop3_send (stream,"USER",usr)) { LOCAL->sensitive = T; /* hide this command */ if (pop3_send (stream,"PASS",pwd)) ret = LONGT; LOCAL->sensitive=NIL; /* unhide */ } if (!ret) { /* failure */ mm_log (LOCAL->reply,WARN); if (trial == pop3_maxlogintrials) mm_log ("Too many login failures",ERROR); } } /* user refused to give password */ else mm_log ("Login aborted",ERROR); } while (!ret && pwd[0] && (trial < pop3_maxlogintrials) && LOCAL->netstream); } memset (pwd,0,MAILTMPLEN); /* erase password */ /* get capabilities if logged in */ if (ret && capaok) pop3_capa (stream,flags); return ret;}/* Get challenge to authenticator in binary * Accepts: stream * pointer to returned size * Returns: challenge or NIL if not challenge */void *pop3_challenge (void *s,unsigned long *len){ char tmp[MAILTMPLEN]; void *ret = NIL; MAILSTREAM *stream = (MAILSTREAM *) s; if (stream && LOCAL->response && (*LOCAL->response == '+') && (LOCAL->response[1] == ' ') && !(ret = rfc822_base64 ((unsigned char *) LOCAL->reply, strlen (LOCAL->reply),len))) { sprintf (tmp,"POP3 SERVER BUG (invalid challenge): %.80s",LOCAL->reply); 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 pop3_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'; *u = '\0'; ret = net_sout (LOCAL->netstream,t,u - t);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -