📄 imap4r1.c
字号:
imapreferral_t ir; aflg.type = FLAGS; aflg.text = (void *) tmp; args[1] = &aflg; args[2] = NIL; tmp[0] = tmp[1] = '\0'; /* build flag list */ if (flags & SA_MESSAGES) strcat (tmp," MESSAGES"); if (flags & SA_RECENT) strcat (tmp," RECENT"); if (flags & SA_UNSEEN) strcat (tmp," UNSEEN"); if (flags & SA_UIDNEXT) strcat (tmp," UIDNEXT"); if (flags & SA_UIDVALIDITY) strcat (tmp," UIDVALIDITY"); tmp[0] = '('; strcat (tmp,")"); /* send "STATUS mailbox flag" */ if (imap_OK (stream,imap_send (stream,"STATUS",args))) ret = T; else if ((ir = (imapreferral_t) mail_parameters (stream,GET_IMAPREFERRAL,NIL)) && LOCAL->referral && (mbx = (*ir) (stream,LOCAL->referral,REFSTATUS))) ret = imap_status (NIL,mbx,flags | (stream->debug ? SA_DEBUG : NIL)); } /* IMAP2 way */ else if (imap_OK (stream,imap_send (stream,"EXAMINE",args))) { MAILSTATUS status; status.flags = flags & ~ (SA_UIDNEXT | SA_UIDVALIDITY); status.messages = stream->nmsgs; status.recent = stream->recent; status.unseen = 0; if (flags & SA_UNSEEN) { /* must search to get unseen messages */ /* clear search vector */ for (i = 1; i <= stream->nmsgs; ++i) mail_elt (stream,i)->searched = NIL; if (imap_OK (stream,imap_send (stream,"SEARCH UNSEEN",NIL))) for (i = 1,status.unseen = 0; i <= stream->nmsgs; i++) if (mail_elt (stream,i)->searched) status.unseen++; } strcpy (strchr (strcpy (tmp,stream->mailbox),'}') + 1,mb.mailbox); /* pass status to main program */ mm_status (stream,tmp,&status); ret = T; /* note success */ } if (tstream) mail_close (tstream); return ret; /* success */}/* IMAP open * Accepts: stream to open * Returns: stream to use on success, NIL on failure */MAILSTREAM *imap_open (MAILSTREAM *stream){ unsigned long i,j; char *s,tmp[MAILTMPLEN],usr[MAILTMPLEN]; NETMBX mb; IMAPPARSEDREPLY *reply = NIL; imapreferral_t ir = (imapreferral_t) mail_parameters (stream,GET_IMAPREFERRAL,NIL); /* return prototype for OP_PROTOTYPE call */ if (!stream) return &imapproto; mail_valid_net_parse (stream->mailbox,&mb); usr[0] = '\0'; /* initially no user name */ if (LOCAL) { /* if stream opened earlier by us */ /* recycle if still alive */ if (LOCAL->netstream && (!stream->halfopen || LOCAL->cap.unselect)) { i = stream->silent; /* temporarily mark silent */ stream->silent = T; /* don't give mm_exists() events */ j = imap_ping (stream); /* learn if stream still alive */ stream->silent = i; /* restore prior state */ if (j) { /* was stream still alive? */ sprintf (tmp,"Reusing connection to %s",net_host (LOCAL->netstream)); if (LOCAL->user) sprintf (tmp + strlen (tmp),"/user=\"%s\"", LOCAL->user); if (!stream->silent) mm_log (tmp,(long) NIL); /* unselect if now want halfopen */ if (stream->halfopen) imap_send (stream,"UNSELECT",NIL); } else imap_close (stream,NIL); } else imap_close (stream,NIL); } /* copy flags from name */ if (mb.dbgflag) stream->debug = T; if (mb.readonlyflag) stream->rdonly = T; if (mb.anoflag) stream->anonymous = T; if (mb.secflag) stream->secure = T; if (mb.trysslflag || imap_tryssl) stream->tryssl = T; if (!LOCAL) { /* open new connection if no recycle */ NETDRIVER *ssld = (NETDRIVER *) mail_parameters (NIL,GET_SSLDRIVER,NIL); unsigned long defprt = imap_defaultport ? imap_defaultport : IMAPTCPPORT; unsigned long sslport = imap_sslport ? imap_sslport : IMAPSSLPORT; stream->local = /* instantiate localdata */ (void *) memset (fs_get (sizeof (IMAPLOCAL)),0,sizeof (IMAPLOCAL)); /* assume IMAP2bis server */ LOCAL->cap.imap2bis = LOCAL->cap.rfc1176 = T; /* in case server is a loser */ if (mb.loser) LOCAL->loser = T; /* desirable authenticators */ LOCAL->authflags = (stream->secure ? AU_SECURE : NIL) | (mb.authuser[0] ? AU_AUTHUSER : NIL); /* IMAP connection open logic is more complex than net_open() normally * deals with, because of the simap and rimap hacks. * If the session is anonymous, a specific port is given, or if /ssl or * /tls is set, do net_open() since those conditions override everything * else. */ if (stream->anonymous || mb.port || mb.sslflag || mb.tlsflag) reply = (LOCAL->netstream = net_open (&mb,NIL,defprt,ssld,"*imaps", sslport)) ? imap_reply (stream,NIL) : NIL; /* * No overriding conditions, so get the best connection that we can. In * order, attempt to open via simap, tryssl, rimap, and finally TCP. */ /* try simap */ else if (reply = imap_rimap (stream,"*imap",&mb,usr,tmp)); else if (ssld && /* try tryssl if enabled */ (stream->tryssl || mail_parameters (NIL,GET_TRYSSLFIRST,NIL)) && (LOCAL->netstream = net_open_work (ssld,mb.host,"*imaps",sslport,mb.port, (mb.novalidate ? NET_NOVALIDATECERT : 0) | NET_SILENT | NET_TRYSSL))) { if (net_sout (LOCAL->netstream,"",0)) { mb.sslflag = T; reply = imap_reply (stream,NIL); } else { /* flush fake SSL stream */ net_close (LOCAL->netstream); LOCAL->netstream = NIL; } } /* try rimap first, then TCP */ else if (!(reply = imap_rimap (stream,"imap",&mb,usr,tmp)) && (LOCAL->netstream = net_open (&mb,NIL,defprt,NIL,NIL,NIL))) reply = imap_reply (stream,NIL); /* make sure greeting is good */ if (!reply || strcmp (reply->tag,"*") || (strcmp (reply->key,"OK") && strcmp (reply->key,"PREAUTH"))) { if (reply) mm_log (reply->text,ERROR); return NIL; /* lost during greeting */ } /* if connected and not preauthenticated */ if (LOCAL->netstream && strcmp (reply->key,"PREAUTH")) { sslstart_t stls = (sslstart_t) mail_parameters (NIL,GET_SSLSTART,NIL); /* get server capabilities */ if (!LOCAL->gotcapability) imap_capability (stream); if (LOCAL->netstream && /* does server support STARTTLS? */ stls && LOCAL->cap.starttls && !mb.sslflag && !mb.notlsflag && imap_OK (stream,imap_send (stream,"STARTTLS",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; } /* get capabilities now that TLS in effect */ if (LOCAL->netstream) imap_capability (stream); } else if (mb.tlsflag) { /* user specified /tls but can't do it */ mm_log ("Unable to negotiate TLS with this server",ERROR); return NIL; } if (LOCAL->netstream) { /* still in the land of the living? */ 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'; } /* need new capabilities after login */ LOCAL->gotcapability = NIL; if (!(stream->anonymous ? imap_anon (stream,tmp) : (LOCAL->cap.auth ? imap_auth (stream,&mb,tmp,usr) : imap_login (stream,&mb,tmp,usr)))) { /* failed, is there a referral? */ if (ir && LOCAL->referral && (s = (*ir) (stream,LOCAL->referral,REFAUTHFAILED))) { imap_close (stream,NIL); fs_give ((void **) &stream->mailbox); /* set as new mailbox name to open */ stream->mailbox = s; return imap_open (stream); } return NIL; /* authentication failed */ } else if (ir && LOCAL->referral && (s = (*ir) (stream,LOCAL->referral,REFAUTH))) { imap_close (stream,NIL); fs_give ((void **) &stream->mailbox); stream->mailbox = s; /* set as new mailbox name to open */ /* recurse to log in on real site */ return imap_open (stream); } } } /* get server capabilities again */ if (LOCAL->netstream && !LOCAL->gotcapability) imap_capability (stream); /* save state for future recycling */ if (mb.tlsflag) LOCAL->tlsflag = T; if (mb.tlssslv23) LOCAL->tlssslv23 = T; if (mb.notlsflag) LOCAL->notlsflag = T; if (mb.sslflag) LOCAL->sslflag = T; if (mb.novalidate) LOCAL->novalidate = T; if (mb.loser) LOCAL->loser = T; } if (LOCAL->netstream) { /* still have a connection? */ stream->perm_seen = stream->perm_deleted = stream->perm_answered = stream->perm_draft = LEVELIMAP4 (stream) ? NIL : T; stream->perm_user_flags = LEVELIMAP4 (stream) ? NIL : 0xffffffff; stream->sequence++; /* bump sequence number */ sprintf (tmp,"{%s",(long) mail_parameters (NIL,GET_TRUSTDNS,NIL) ? net_host (LOCAL->netstream) : mb.host); if (!((i = net_port (LOCAL->netstream)) & 0xffff0000)) sprintf (tmp + strlen (tmp),":%lu",i); strcat (tmp,"/imap"); if (LOCAL->tlsflag) strcat (tmp,"/tls"); if (LOCAL->tlssslv23) strcat (tmp,"/tls-sslv23"); if (LOCAL->notlsflag) strcat (tmp,"/notls"); if (LOCAL->sslflag) strcat (tmp,"/ssl"); if (LOCAL->novalidate) strcat (tmp,"/novalidate-cert"); if (LOCAL->loser) strcat (tmp,"/loser"); if (stream->secure) strcat (tmp,"/secure"); if (stream->rdonly) strcat (tmp,"/readonly"); if (stream->anonymous) strcat (tmp,"/anonymous"); else { /* record user name */ if (!LOCAL->user && usr[0]) LOCAL->user = cpystr (usr); if (LOCAL->user) sprintf (tmp + strlen (tmp),"/user=\"%s\"", LOCAL->user); } strcat (tmp,"}"); if (!stream->halfopen) { /* wants to open a mailbox? */ IMAPARG *args[2]; IMAPARG ambx; ambx.type = ASTRING; ambx.text = (void *) mb.mailbox; args[0] = &ambx; args[1] = NIL; stream->nmsgs = 0; if (imap_OK (stream,reply = imap_send (stream,stream->rdonly ? "EXAMINE": "SELECT",args))) { strcat (tmp,mb.mailbox);/* mailbox name */ if (!stream->nmsgs && !stream->silent) mm_log ("Mailbox is empty",(long) NIL); /* note if an INBOX or not */ stream->inbox = !compare_cstring (mb.mailbox,"INBOX"); } else if (ir && LOCAL->referral && (s = (*ir) (stream,LOCAL->referral,REFSELECT))) { imap_close (stream,NIL); fs_give ((void **) &stream->mailbox); stream->mailbox = s; /* set as new mailbox name to open */ return imap_open (stream); } else { mm_log (reply->text,ERROR); if (imap_closeonerror) return NIL; stream->halfopen = T; /* let him keep it half-open */ } } if (stream->halfopen) { /* half-open connection? */ strcat (tmp,"<no_mailbox>"); /* make sure dummy message counts */ mail_exists (stream,(long) 0); mail_recent (stream,(long) 0); } fs_give ((void **) &stream->mailbox); stream->mailbox = cpystr (tmp); } /* success if stream open */ return LOCAL->netstream ? stream : NIL;}/* IMAP rimap connect * Accepts: MAIL stream * NETMBX specification * service to use * user name * scratch buffer * Returns: parsed reply if success, else NIL */IMAPPARSEDREPLY *imap_rimap (MAILSTREAM *stream,char *service,NETMBX *mb, char *usr,char *tmp){ unsigned long i; char c[2]; NETSTREAM *tstream; IMAPPARSEDREPLY *reply = NIL; /* try rimap open */ if (!mb->norsh && (tstream = net_aopen (NIL,mb,service,usr))) { /* if success, see if reasonable banner */ if (net_getbuffer (tstream,(long) 1,c) && (*c == '*')) { i = 0; /* copy to buffer */ do tmp[i++] = *c; while (net_getbuffer (tstream,(long) 1,c) && (*c != '\015') && (*c != '\012') && (i < (MAILTMPLEN-1))); tmp[i] = '\0'; /* tie off */ /* snarfed a valid greeting? */ if ((*c == '\015') && net_getbuffer (tstream,(long) 1,c) && (*c == '\012') && !strcmp ((reply = imap_parse_reply (stream,cpystr (tmp)))->tag,"*")){ /* parse line as IMAP */ imap_parse_unsolicited (stream,reply); /* make sure greeting is good */ if (!strcmp (reply->key,"OK") || !strcmp (reply->key,"PREAUTH")) { LOCAL->netstream = tstream; return reply; /* return success */ } } } net_close (tstream); /* failed, punt the temporary netstream */ } return NIL;}/* IMAP log in as anonymous * Accepts: stream to authenticate * scratch buffer * Returns: T on success, NIL on failure */long imap_anon (MAILSTREAM *stream,char *tmp){ IMAPPARSEDREPLY *reply; char *s = net_localhost (LOCAL->netstream); if (LOCAL->cap.authanon) { char tag[16]; unsigned long i; char *broken = "[CLOSED] IMAP connection broken (anonymous auth)"; sprintf (tag,"%08lx",0xffffffff & (stream->gensym++)); /* build command */ sprintf (tmp,"%s AUTHENTICATE ANONYMOUS",tag); if (!imap_soutr (stream,tmp)) { mm_log (broken,ERROR); return NIL; } if (imap_challenge (stream,&i)) imap_response (stream,s,strlen (s)); /* get response */ if (!(reply = &LOCAL->reply)->tag) reply = imap_fake (stream,tag,broken); /* what we wanted? */ if (compare_cstring (reply->tag,tag)) { /* abort if don't have tagged response */ while (compare_cstring ((reply = imap_reply (stream,tag))->tag,tag)) imap_soutr (stream,"*"); } } else { IMAPARG *args[2]; IMAPARG ausr; ausr.type = ASTRING; ausr.text = (void *) s; args[0] = &ausr; args[1] = NIL; /* send "LOGIN anonymous <host>" */ reply = imap_send (stream,"LOGIN ANONYMOUS",args); } /* success if reply OK */ if (imap_OK (stream,reply)) return T; mm_log (reply->text,ERROR); return NIL;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -