📄 imap4r1.c
字号:
return elt->private.msg.env; } if (body) *body = NIL; /* can't find the UID */ return NIL; } elt = mail_elt (stream,msgno);/* get cache pointer */ if (stream->scache) { /* short caching? */ env = &stream->env; /* use temporaries on the stream */ b = &stream->body; if (msgno != stream->msgno){/* flush old poop if a different message */ mail_free_envelope (env); mail_free_body (b); stream->msgno = msgno; /* this is now the current short cache msg */ } } else { /* normal cache */ env = &elt->private.msg.env;/* get envelope and body pointers */ b = &elt->private.msg.body; /* prefetch if don't have envelope */ if (!(flags & FT_NOLOOKAHEAD) && ((!*env || (*env)->incomplete) || (body && !*b && LEVELIMAP2bis (stream)))) { if (set) { /* have a lookahead list? */ MESSAGE *msg; for (k = imap_fetchlookaheadlimit; k && set && (((s += strlen (s)) - seq) < (MAXCOMMAND - 30)); set = set->next) { i = (set->first == 0xffffffff) ? stream->nmsgs : min (set->first,stream->nmsgs); if (j = (set->last == 0xffffffff) ? stream->nmsgs : min (set->last,stream->nmsgs)) { if (i > j) { /* swap the range if backwards */ x = i; i = j; j = x; } /* find first message not msgno or in cache */ while (((i == msgno) || ((msg = &(mail_elt (stream,i)->private.msg))->env && (!body || msg->body))) && (i++ < j)); /* until range or lookahead finished */ while (k && (i <= j)) { /* find first cached message in range */ for (x = i + 1; (x <= j) && !((msg = &(mail_elt (stream,x)->private.msg))->env && (!body || msg->body)); x++); if (i == --x) { /* only one message? */ sprintf (s += strlen (s),",%lu",i++); k--; /* prefetching one message */ } else { /* a range to prefetch */ sprintf (s += strlen (s),",%lu:%lu",i,x); i = 1 + x - i; /* number of messages in this range */ /* still can look ahead some more? */ if (k = (k > i) ? k - i : 0) /* yes, scan further in this range */ for (i = x + 2; (i <= j) && ((i == msgno) || ((msg = &(mail_elt (stream,i)->private.msg))->env && (!body || msg->body))); i++); } } } else if ((i != msgno) && !mail_elt (stream,i)->private.msg.env) { sprintf (s += strlen (s),",%lu",i); k--; /* prefetching one message */ } } } /* build message number list */ else for (i = msgno+1,k = imap_lookahead; k && (i <= stream->nmsgs); i++) if (!mail_elt (stream,i)->private.msg.env) { s += strlen (s); /* find string end, see if nearing end */ if ((s - seq) > (MAILTMPLEN - 20)) break; sprintf (s,",%lu",i); /* append message */ for (j = i + 1, k--; /* hunt for last message without an envelope */ k && (j <= stream->nmsgs) && !mail_elt (stream,j)->private.msg.env; j++, k--); /* if different, make a range */ if (i != --j) sprintf (s + strlen (s),":%lu",i = j); } } } if (!stream->lock) { /* no-op if stream locked */ /* Build the fetch attributes. Unlike imap_fetch(), this tries not to * fetch data that is already cached. However, since it is based on the * message requested and not on any of the prefetched messages, it can * goof, either by fetching data already cached or not prefetching data * that isn't cached (but was cached in the message requested). * Fortunately, no great harm is done. If it doesn't prefetch the data, * it will get it when the affected message(s) are requested. */ if (!elt->private.uid && LEVELIMAP4 (stream)) strcpy (tmp," UID"); else tmp[0] = '\0'; /* initialize command */ /* need envelope? */ if (!*env || (*env)->incomplete) { strcat (tmp," ENVELOPE"); /* yes, get it and possible extra poop */ if (!(flags & FT_NOHDRS) && LEVELIMAP4rev1 (stream)) { if (imap_extrahdrs) sprintf (tmp + strlen (tmp)," %s %s %s", hdrheader[LOCAL->cap.extlevel], imap_extrahdrs,hdrtrailer); else sprintf (tmp + strlen (tmp)," %s %s", hdrheader[LOCAL->cap.extlevel],hdrtrailer); } } /* need body? */ if (body && !*b && LEVELIMAP2bis (stream)) strcat (tmp,LEVELIMAP4 (stream) ? " BODYSTRUCTURE" : " BODY"); if (!elt->day) strcat (tmp," INTERNALDATE"); if (!elt->rfc822_size) strcat (tmp," RFC822.SIZE"); if (tmp[0]) { /* anything to do? */ tmp[0] = '('; /* make into a list */ strcat (tmp," FLAGS)"); /* always get current flags */ aatt.text = (void *) tmp; /* do the built command */ if (!imap_OK (stream,reply = imap_send (stream,"FETCH",args))) { /* failed, probably RFC-1176 server */ if (!LEVELIMAP4 (stream) && LEVELIMAP2bis (stream) && body && !*b){ aatt.text = (void *) "ALL"; if (imap_OK (stream,reply = imap_send (stream,"FETCH",args))) /* doesn't have body capabilities */ LOCAL->cap.imap2bis = NIL; else mm_log (reply->text,ERROR); } else mm_log (reply->text,ERROR); } } } if (body) { /* wants to return body */ if (!*b && !LEVELIMAP2bis (stream)) { /* simulate body structure fetch for IMAP2 */ *b = mail_initbody (mail_newbody ()); (*b)->subtype = cpystr (rfc822_default_subtype ((*b)->type)); ((*b)->parameter = mail_newbody_parameter ())->attribute = cpystr ("CHARSET"); (*b)->parameter->value = cpystr ("US-ASCII"); s = mail_fetch_text (stream,msgno,NIL,&i,flags); (*b)->size.bytes = i; while (i--) if (*s++ == '\n') (*b)->size.lines++; } *body = *b; /* return the body */ } return *env; /* return the envelope */}/* IMAP fetch message data * Accepts: MAIL stream * message number * section specifier * offset of first designated byte or 0 to start at beginning * maximum number of bytes or 0 for all bytes * lines to fetch if header * flags * Returns: T on success, NIL on failure */long imap_msgdata (MAILSTREAM *stream,unsigned long msgno,char *section, unsigned long first,unsigned long last,STRINGLIST *lines, long flags){ int i; char *t,tmp[MAILTMPLEN],partial[40],seq[40]; char *noextend,*nopartial,*nolines,*nopeek,*nononpeek; char *cmd = (LEVELIMAP4 (stream) && (flags & FT_UID)) ? "UID FETCH":"FETCH"; IMAPPARSEDREPLY *reply; IMAPARG *args[5],*auxargs[3],aseq,aatt,alns,acls,aflg; noextend = nopartial = nolines = nopeek = nononpeek = NIL; /* does searching desire a lookahead? */ if ((flags & FT_SEARCHLOOKAHEAD) && (msgno < stream->nmsgs) && !stream->scache) { sprintf (seq,"%lu:%lu",msgno, (unsigned long) min (msgno + IMAPLOOKAHEAD,stream->nmsgs)); aseq.type = SEQUENCE; aseq.text = (void *) seq; } else { /* no, do it the easy way */ aseq.type = NUMBER; aseq.text = (void *) msgno; } aatt.type = ATOM; /* assume atomic attribute */ alns.type = LIST; alns.text = (void *) lines; acls.type = BODYCLOSE; acls.text = (void *) partial; aflg.type = ATOM; aflg.text = (void *) "FLAGS"; args[0] = &aseq; args[1] = &aatt; args[2] = args[3] = args[4] = NIL; auxargs[0] = &aseq; auxargs[1] = &aflg; auxargs[2] = NIL; partial[0] = '\0'; /* initially no partial specifier */ if (LEVELIMAP4rev1 (stream)) {/* easy if IMAP4rev1 server */ /* HEADER fetching with special handling? */ if (!strcmp (section,"HEADER") && (lines || (flags & FT_PREFETCHTEXT))) { if (lines) { /* want specific header lines? */ aatt.type = (flags & FT_PEEK) ? BODYPEEK : BODYTEXT; aatt.text = (void *) ((flags & FT_NOT) ? "HEADER.FIELDS.NOT" : "HEADER.FIELDS"); args[2] = &alns; args[3] = &acls; } /* must be prefetching */ else aatt.text = (void *) ((flags & FT_PEEK) ? "(BODY.PEEK[HEADER] BODY.PEEK[TEXT])" : "(BODY[HEADER] BODY[TEXT])"); } else { /* simple case */ aatt.type = (flags & FT_PEEK) ? BODYPEEK : BODYTEXT; aatt.text = (void *) section; args[2] = &acls; } if (first || last) sprintf (partial,"<%lu.%lu>",first,last ? last:-1); } /* IMAP4 did not have: * . HEADER body part (can simulate with BODY[0] or BODY.PEEK[0]) * . TEXT body part (can simulate top-level with RFC822.TEXT or * RFC822.TEXT.PEEK) * . MIME body part * . (usable) partial fetching * . (usable) selective header line fetching */ else if (LEVEL1730 (stream)) {/* IMAP4 (RFC 1730) compatibility */ /* BODY[HEADER] becomes BODY.PEEK[0] */ if (!strcmp (section,"HEADER")) aatt.text = (void *) ((flags & FT_PREFETCHTEXT) ? ((flags & FT_PEEK) ? "(BODY.PEEK[0] RFC822.TEXT.PEEK)" : "(BODY[0] RFC822.TEXT)") : ((flags & FT_PEEK) ? "BODY.PEEK[0]" : "BODY[0]")); /* BODY[TEXT] becomes RFC822.TEXT */ else if (!strcmp (section,"TEXT")) aatt.text = (void *) ((flags & FT_PEEK) ? "RFC822.TEXT.PEEK" : "RFC822.TEXT"); else if (!section[0]) /* BODY[] becomes RFC822 */ aatt.text = (void *) ((flags & FT_PEEK) ? "RFC822.PEEK" : "RFC822"); /* nested header */ else if (t = strstr (section,".HEADER")) { aatt.type = (flags & FT_PEEK) ? BODYPEEK : BODYTEXT; args[2] = &acls; /* will need to close section */ aatt.text = (void *) tmp; /* convert .HEADER to .0 */ strncpy (tmp,section,t-section); strcpy (tmp+(t-section),".0"); } else { /* IMAP4 body part */ aatt.type = (flags & FT_PEEK) ? BODYPEEK : BODYTEXT; args[2] = &acls; /* will need to close section */ aatt.text = (void *) section; } if (strstr (section,".MIME") || strstr (section,".TEXT")) noextend = "4"; if (first || last) nopartial = "4"; if (lines) nolines = "4"; } /* IMAP2bis did not have: * . HEADER body part (can simulate peeking top-level with RFC822.HEADER) * . TEXT body part (can simulate non-peeking top-level with RFC822.TEXT) * . MIME body part * . partial fetching * . selective header line fetching * . non-peeking header fetching * . peeking body fetching */ /* IMAP2bis compatibility */ else if (LEVELIMAP2bis (stream)) { /* BODY[HEADER] becomes RFC822.HEADER */ if (!strcmp (section,"HEADER")) { aatt.text = (void *) ((flags & FT_PREFETCHTEXT) ? "(RFC822.HEADER RFC822.TEXT)" : "RFC822.HEADER"); if (flags & FT_PEEK) flags &= ~FT_PEEK; else nononpeek = "2bis"; } /* BODY[TEXT] becomes RFC822.TEXT */ else if (!strcmp (section,"TEXT")) aatt.text = (void *) "RFC822.TEXT"; /* BODY[] becomes RFC822 */ else if (!section[0]) aatt.text = (void *) "RFC822"; else { /* IMAP2bis body part */ aatt.type = BODYTEXT; args[2] = &acls; /* will need to close section */ aatt.text = (void *) section; } if (strstr (section,".HEADER") || strstr (section,".MIME") || strstr (section,".TEXT")) noextend = "2bis"; if (first || last) nopartial = "2bis"; if (lines) nolines = "2bis"; if (flags & FT_PEEK) nopeek = "2bis"; } /* IMAP2 did not have: * . HEADER body part (can simulate peeking top-level with RFC822.HEADER) * . TEXT body part (can simulate non-peeking top-level with RFC822.TEXT) * . MIME body part * . multiple body parts (can simulate BODY[1] with RFC822.TEXT) * . partial fetching * . selective header line fetching * . non-peeking header fetching * . peeking body fetching */ else { /* IMAP2 (RFC 1176/1064) compatibility */ /* BODY[HEADER] */ if (!strcmp (section,"HEADER")) { aatt.text = (void *) ((flags & FT_PREFETCHTEXT) ? "(RFC822.HEADER RFC822.TEXT)" : "RFC822.HEADER"); if (flags & FT_PEEK) flags &= ~FT_PEEK; nononpeek = "2"; } /* BODY[TEXT] becomes RFC822.TEXT */ else if (!strcmp (section,"TEXT")) aatt.text = (void *) "RFC822.TEXT"; /* BODY[1] treated like RFC822.TEXT */ else if (!strcmp (section,"1")) { SIZEDTEXT text; MESSAGECACHE *elt = mail_elt (stream,msgno); /* have a cached RFC822.TEXT? */ if (elt->private.msg.text.text.data) { text.size = elt->private.msg.text.text.size; /* should move instead of copy */ text.data = memcpy (fs_get (text.size+1), elt->private.msg.text.text.data,text.size); (t = (char *) text.data)[text.size] = '\0'; imap_cache (stream,msgno,"1",NIL,&text); return LONGT; /* don't have to do any fetches */ } /* otherwise do RFC822.TEXT */ aatt.text = (void *) "RFC822.TEXT"; } /* BODY[] becomes RFC822 */ else if (!section[0]) aatt.text = (void *) "RFC822"; else noextend = "2"; /* how did we get here? */ if (flags & FT_PEEK) nopeek = "2"; if (first || last) nopartial = "2"; if (lines) nolines = "2"; } /* Report unavailable functionalities. The application can use the helpful * LEVELIMAPREV1, LEVELIMAP4, and LEVELIMAP2bis operations provided in * imap4r1.h to avoid triggering these errors. There aren't any workarounds * for these restrictions. */ if (noextend) { sprintf (tmp,"[NOTIMAP4REV1] IMAP%s server can't do extended body fetch", noextend); mm_log (tmp,ERROR); return NIL; /* can't do anything close either */ } if (nopartial) { sprintf (tmp,"[NOTIMAP4REV1] IMAP%s server can't do partial fetch", nopartial); mm_notify (stream,tmp,WARN); } if (nolines) { sprintf(tmp,"[NOTIMAP4REV1] IMAP%s server can't do selective header fetch", nolines); mm_notify (stream,tmp,WARN); } /* trying to do unsupported peek behavior? */ if ((t = nopeek) || (t = nononpeek)) { /* get most recent \Seen setting */ if (!imap_OK (stream,reply = imap_send (stream,cmd,auxargs))) mm_log (reply->text,WARN); /* note current setting of \Seen flag */ if (!(i = mail_elt (stream,msgno)->seen)) { sprintf (tmp,nopeek ? /* only babble if \Seen not set */ "[NOTIMAP4] Simulating peeking fetch in IMAP%s" : "[NOTIMAP4] Simulating non-peeking header fetch in IMAP%s",t); mm_notify (stream,tmp,NIL); } /* send the fetch command */ if (!imap_OK (stream,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -