/* ---------------- score_mat_string -------------------------- * This is not a score routine, it is not an alignment routine. * Maybe it should go in its own file. * Here are the tricks to remember. * Our M+N score matrix is actually (M+2)(M+2) so as to allow * for empty places and end-gaps. You don't have to use them if * you don't like them. * The loops below are far more elegant if we temporarily store * the strings with end bits at start and end. */ char * score_mat_string (struct score_mat *smat, struct seq *s1, struct seq *s2) { char *ret = NULL; char *str1, *str2; size_t n_rows = smat->n_rows; size_t n_cols = smat->n_cols; size_t i, j; const char *c_fmt = "%4c "; const char *f_fmt = "%4.2f "; const char *hat = "^"; seq_thomas2std (s1); seq_thomas2std (s2); str1 = save_str (hat); str1 = save_str_append (str1, s1->seq); str1 = save_str_append (str1, hat); str2 = save_str (hat); str2 = save_str_append (str2, s2->seq); str2 = save_str_append (str2, hat); scr_reset(); scr_printf (c_fmt, ' '); for ( i = 0; i < n_cols; i++) scr_printf (c_fmt, str2[i]); scr_printf ("\n"); for ( i = 0; i < n_rows; i++) { scr_printf (c_fmt, str1[i]); for ( j = 0 ; j < n_cols; j++) scr_printf (f_fmt, smat->mat[i][j]); ret = scr_printf ("\n"); } free (str1); free (str2); return (ret); }
/* ---------------- pair_set_chimera -------------------------- * Given an alignment, write pairs of atoms to a file in a format * that chimera can read. * We return a char * to space which is allocated by the * scr_printf() routines. */ char * pair_set_chimera (struct pair_set *pair_set, const struct coord *c1, const struct coord *c2) { const char *this_sub = "pair_set_chimera"; int **p; char *s1 = NULL; char *s2 = NULL; char *ret; size_t i; if (pair_set->n == 0) { err_printf (this_sub, "empty pair set\n"); return NULL; } s1 = save_str ("#0"); s2 = save_str ("#1"); p = pair_set->indices; for ( i = 0; i < pair_set->n; i++) { int a = p[i][0], b = p[i][1]; if (( a != GAP_INDEX) && ( b != GAP_INDEX)) { s1 = add_res (s1, a, c1); s2 = add_res (s2, b, c2); } } scr_reset(); ret = scr_printf ("match %s %s", s1, s2); free (s1); free (s2); return (ret); }
/* --------------------- seq_duplicate -------------- * creates a copy of a n-times duplicated sequence. * n = 1 returns a sequence copy * n = 2 returns a sequence duplicated (simply doubled) * n = ... * n = 0 is not allowed, returns NULL in failure case * params: * *src - struct seq : sequence to be duplicated * n - size_t : amount of wanted duplications * return: * dst - struct seq : new seq */ struct seq * seq_duplicate ( const struct seq *seq, size_t n ) { size_t newsize; struct seq *dst; if (!seq || n < 1) return NULL; newsize = seq->length * n ; dst = E_MALLOC (sizeof (*dst)); seq_ini (dst); dst->seq = E_MALLOC( newsize * sizeof(char)); if (seq->seq){ size_t i; for(i = 0; i < n ; i++){ memcpy ( dst->seq + (i * seq->length) , seq->seq , seq->length ); } /* dst->seq = save_anything ( seq->seq, ( n + 1) * sizeof (seq->seq[0])); */ } if (seq->comment) dst->comment = save_str (seq->comment); dst->length = newsize; dst->format = seq->format; return dst; }
static int pop3_fastuidl( int sock, struct query *ctl, unsigned int count, int *newp) { int ok; unsigned int first_nr, last_nr, try_nr; char id [IDLEN+1]; first_nr = 0; last_nr = count + 1; while (first_nr < last_nr - 1) { struct idlist *newl; try_nr = (first_nr + last_nr) / 2; if ((ok = pop3_getuidl(sock, try_nr, id, sizeof(id))) != 0) return ok; if ((newl = str_in_list(&ctl->oldsaved, id, FALSE))) { flag mark = newl->val.status.mark; if (mark == UID_DELETED || mark == UID_EXPUNGED) { if (outlevel >= O_VERBOSE) report(stderr, GT_("id=%s (num=%u) was deleted, but is still present!\n"), id, try_nr); /* just mark it as seen now! */ newl->val.status.mark = mark = UID_SEEN; } /* narrow the search region! */ if (mark == UID_UNSEEN) { if (outlevel >= O_DEBUG) report(stdout, GT_("%u is unseen\n"), try_nr); last_nr = try_nr; } else first_nr = try_nr; /* save the number */ newl->val.status.num = try_nr; } else { if (outlevel >= O_DEBUG) report(stdout, GT_("%u is unseen\n"), try_nr); last_nr = try_nr; /* save it */ newl = save_str(&ctl->oldsaved, id, UID_UNSEEN); newl->val.status.num = try_nr; } } if (outlevel >= O_DEBUG && last_nr <= count) report(stdout, GT_("%u is first unseen\n"), last_nr); /* update last! */ *newp = count - first_nr; last = first_nr; return 0; }
/* ---------------- save_str_append --------------------------- * Given a malloc'd string (dst) and another string (src), * grow dst appropriately and append src. */ char * save_str_append (char *dst, const char *src) { if (dst == NULL) { dst = save_str (src); } else { size_t s1 = strlen (src) + 1; size_t s2 = strlen (dst); dst = E_REALLOC (dst, s1 + s2 ); strncpy (dst + s2, src, s1); } return dst; }
/** add given address to xmit_names if it exactly matches a full address * \returns nonzero if matched */ static int map_address(const char *addr, struct query *ctl, struct idlist **xmit_names) { const char *lname; lname = idpair_find(&ctl->localnames, addr); if (lname) { if (outlevel >= O_DEBUG) report(stdout, GT_("mapped address %s to local %s\n"), addr, lname); save_str(xmit_names, lname, XMIT_ACCEPT); accept_count++; } return lname != NULL; }
/* ---------------- sub_mat_copy ------------------------------ * Make a copy of a substitution matrix. Not obviously a useful * thing to do, but we can overwrite the contents and manipulate * it. */ static struct sub_mat * sub_mat_copy (const struct sub_mat *src) { struct sub_mat* dst; int i, j; dst = E_MALLOC (sizeof (*dst)); dst ->fname = NULL; dst ->comment = NULL; dst ->fname = save_str (src->fname); for (i = 0; i < MAX_AA; i++) for (j = 0; j < MAX_AA; j++) dst->data[i][j] = src->data[i][j]; return dst; }
static ALWAYS_INLINE bool internal_printf(strbuf_t *s1, bool (*save_str)(strbuf_t *, const char *, size_t), const char *fmt, va_list values) { char *s2; int len; if (UNLIKELY((len = vasprintf(&s2, fmt, values)) < 0)) return false; bool success = save_str(s1, s2, (size_t)len); free(s2); return success; }
/** add given name to xmit_names if it matches declared localnames */ static void map_name(const char *name, struct query *ctl, struct idlist **xmit_names) /* name: name to map */ /* ctl: list of permissible aliases */ /* xmit_names: list of recipient names parsed out */ { const char *lname; lname = idpair_find(&ctl->localnames, name); if (!lname && ctl->wildcard) lname = name; if (lname != (char *)NULL) { if (outlevel >= O_DEBUG) report(stdout, GT_("mapped %s to local %s\n"), name, lname); save_str(xmit_names, lname, XMIT_ACCEPT); accept_count++; } }
int chkVersionChange() { char keySaved[14] = {0}; char keyNew[14] = {0}; struct tm tm = {0}; char* verTime = versionDateString(); if (verTime) { strptime(verTime, "%a %b %d %T PDT %Y", &tm); strftime(keyNew, sizeof(keyNew), "%s", &tm); load_str(MAND_CONF, "MAGIC_KEY", keySaved, sizeof(keySaved), NULL); g_first_run = strcmp(keySaved, keyNew); if (g_first_run != 0) save_str(MAND_CONF, "MAGIC_KEY", keyNew); } else { g_first_run = 0; } return g_first_run; }
/* ---------------- seq_deletion ------------------------------ * perl: seq_deletion seq start length * returns a new sequence with appropriately modified set * Operation : * for a deletion at s of length l, * 1.remove residues s to s+l-1 from the sequence */ struct seq * seq_deletion ( struct seq *oseq, size_t start, size_t sl, size_t ql) { const char *this_sub="seq_deletion"; /* From seq_copy */ size_t n; struct seq *dst; if (oseq==NULL) { err_printf (this_sub, "---- NULL SEQUENCE ----\n"); return(NULL); } if ((start>=oseq->length) || ((start+sl+ql)>oseq->length)) { err_printf (this_sub, "Unbounded Deletion of (%i, s%i, q%i) in sequence of %i residues.\n",start,sl,ql,oseq->length); return (NULL); } n = oseq->length-sl-ql; dst = E_MALLOC (sizeof (*oseq)); if (dst!=NULL) { seq_ini (dst); if (oseq->seq) { dst->seq = E_MALLOC(sizeof(oseq->seq[0])*(n+1)); if (start) memcpy(dst->seq, oseq->seq, (start)*sizeof(oseq->seq[0])); if (n-start) memcpy(dst->seq+start, oseq->seq+(start+ql), (1+n-start)*sizeof(oseq->seq[0])); dst->seq[n]='\0'; /* excessive ensureing */ if (oseq->comment) dst->comment = save_str (oseq->comment); } dst->length = n; dst->format = oseq->format; return dst; } else err_printf (this_sub, "---- NO SEQUENCE MEMORY ----"); return NULL; }
static void find_server_names(const char *hdr, struct query *ctl, struct idlist **xmit_names) /* parse names out of a RFC822 header into an ID list */ /* hdr: RFC822 header in question */ /* ctl: list of permissible aliases */ /* xmit_names: list of recipient names parsed out */ { if (hdr == (char *)NULL) return; else { char *cp; for (cp = nxtaddr(hdr); cp != NULL; cp = nxtaddr(NULL)) { char *atsign; /* * Handle empty address from a To: header containing only * a comment. */ if (!*cp) continue; /* * If the name of the user begins with a qmail virtual * domain prefix, ignore the prefix. Doing this here * means qvirtual will work either with ordinary name * mapping or with a localdomains option. */ if (ctl->server.qvirtual) { int sl = strlen(ctl->server.qvirtual); if (!strncasecmp((char *)cp, ctl->server.qvirtual, sl)) cp += sl; } if ((atsign = strchr((char *)cp, '@'))) { struct idlist *idp; /* try to match full address first, this takes * precedence over localdomains and alias mappings */ if (map_address(cp, ctl, xmit_names)) goto nomap; /* * Does a trailing segment of the hostname match something * on the localdomains list? If so, save the whole name * and keep going. */ for (idp = ctl->server.localdomains; idp; idp = idp->next) { char *rhs; rhs = atsign + (strlen(atsign) - strlen(idp->id)); if (rhs > atsign && (rhs[-1] == '.' || rhs[-1] == '@') && strcasecmp(rhs, idp->id) == 0) { if (outlevel >= O_DEBUG) report(stdout, GT_("passed through %s matching %s\n"), cp, idp->id); save_str(xmit_names, (const char *)cp, XMIT_ACCEPT); accept_count++; goto nomap; } } /* if we matched a local domain, idp != NULL */ if (!idp) { /* * Check to see if the right-hand part is an alias * or MX equivalent of the mailserver. If it's * not, skip this name. If it is, we'll keep * going and try to find a mapping to a client name. */ if (!is_host_alias(atsign+1, ctl, &ai0)) { save_str(xmit_names, cp, XMIT_REJECT); reject_count++; continue; } } atsign[0] = '\0'; map_name(cp, ctl, xmit_names); nomap:; } } } }
int readheaders(int sock, long fetchlen, long reallen, struct query *ctl, int num, flag *suppress_readbody) /* read message headers and ship to SMTP or MDA */ /* sock: to which the server is connected */ /* fetchlen: length of message according to fetch response */ /* reallen: length of message according to getsizes */ /* ctl: query control record */ /* num: index of message */ /* suppress_readbody: whether call to readbody() should be supressed */ { struct addrblk { int offset; struct addrblk *next; }; struct addrblk *to_addrchain = NULL; struct addrblk **to_chainptr = &to_addrchain; struct addrblk *resent_to_addrchain = NULL; struct addrblk **resent_to_chainptr = &resent_to_addrchain; char buf[MSGBUFSIZE+1]; int from_offs, reply_to_offs, resent_from_offs; int app_from_offs, sender_offs, resent_sender_offs; int env_offs; char *received_for, *rcv, *cp; static char *delivered_to = NULL; int n, oldlen, ch, remaining, skipcount; size_t linelen; int delivered_to_count; struct idlist *idp; flag no_local_matches = FALSE; flag has_nuls; int olderrs, good_addresses, bad_addresses; int retain_mail = 0, refuse_mail = 0; flag already_has_return_path = FALSE; sizeticker = 0; has_nuls = FALSE; msgblk.return_path[0] = '\0'; olderrs = ctl->errcount; /* read message headers */ msgblk.reallen = reallen; /* * We used to free the header block unconditionally at the end of * readheaders, but it turns out that if close_sink() hits an error * condition the code for sending bouncemail will actually look * at the freed storage and coredump... */ xfree(msgblk.headers); free_str_list(&msgblk.recipients); xfree(delivered_to); /* initially, no message digest */ memset(ctl->digest, '\0', sizeof(ctl->digest)); received_for = NULL; from_offs = reply_to_offs = resent_from_offs = app_from_offs = sender_offs = resent_sender_offs = env_offs = -1; oldlen = 0; msgblk.msglen = 0; skipcount = 0; delivered_to_count = 0; ctl->mimemsg = 0; for (remaining = fetchlen; remaining > 0 || protocol->delimited; ) { char *line, *rline; line = (char *)xmalloc(sizeof(buf)); linelen = 0; line[0] = '\0'; do { do { char *sp, *tp; set_timeout(mytimeout); if ((n = SockRead(sock, buf, sizeof(buf)-1)) == -1) { set_timeout(0); free(line); return(PS_SOCKET); } set_timeout(0); /* * Smash out any NULs, they could wreak havoc later on. * Some network stacks seem to generate these at random, * especially (according to reports) at the beginning of the * first read. NULs are illegal in RFC822 format. */ for (sp = tp = buf; sp < buf + n; sp++) if (*sp) *tp++ = *sp; *tp = '\0'; n = tp - buf; } while (n == 0); remaining -= n; linelen += n; msgblk.msglen += n; /* * Try to gracefully handle the case where the length of a * line exceeds MSGBUFSIZE. */ if (n && buf[n-1] != '\n') { rline = (char *) realloc(line, linelen + 1); if (rline == NULL) { free (line); return(PS_IOERR); } line = rline; memcpy(line + linelen - n, buf, n); line[linelen] = '\0'; ch = ' '; /* So the next iteration starts */ continue; } /* lines may not be properly CRLF terminated; fix this for qmail */ /* we don't want to overflow the buffer here */ if (ctl->forcecr && buf[n-1]=='\n' && (n==1 || buf[n-2]!='\r')) { char * tcp; rline = (char *) realloc(line, linelen + 2); if (rline == NULL) { free (line); return(PS_IOERR); } line = rline; memcpy(line + linelen - n, buf, n - 1); tcp = line + linelen - 1; *tcp++ = '\r'; *tcp++ = '\n'; *tcp = '\0'; /* n++; - not used later on */ linelen++; } else { rline = (char *) realloc(line, linelen + 1); if (rline == NULL) { free (line); return(PS_IOERR); } line = rline; memcpy(line + linelen - n, buf, n + 1); } /* check for end of headers */ if (end_of_header(line)) { eoh: if (linelen != strlen (line)) has_nuls = TRUE; free(line); goto process_headers; } /* * Check for end of message immediately. If one of your folders * has been mangled, the delimiter may occur directly after the * header. */ if (protocol->delimited && line[0] == '.' && EMPTYLINE(line+1)) { if (suppress_readbody) *suppress_readbody = TRUE; goto eoh; /* above */ } /* * At least one brain-dead website (netmind.com) is known to * send out robotmail that's missing the RFC822 delimiter blank * line before the body! Without this check fetchmail segfaults. * With it, we treat such messages as spam and refuse them. * * Frederic Marchal reported in February 2006 that hotmail * or something improperly wrapped a very long TO header * (wrapped without inserting whitespace in the continuation * line) and found that this code thus refused a message * that should have been delivered. * * XXX FIXME: we should probably wrap the message up as * message/rfc822 attachment and forward to postmaster (Rob * MacGregor) */ if (!refuse_mail && !ctl->server.badheader == BHACCEPT && !isspace((unsigned char)line[0]) && !strchr(line, ':')) { if (linelen != strlen (line)) has_nuls = TRUE; if (outlevel > O_SILENT) report(stdout, GT_("incorrect header line found - see manpage for bad-header option\n")); if (outlevel >= O_VERBOSE) report (stdout, GT_("line: %s"), line); refuse_mail = 1; } /* check for RFC822 continuations */ set_timeout(mytimeout); ch = SockPeek(sock); set_timeout(0); } while (ch == ' ' || ch == '\t'); /* continuation to next line? */ /* write the message size dots */ if ((outlevel > O_SILENT && outlevel < O_VERBOSE) && linelen > 0) { print_ticker(&sizeticker, linelen); } /* * Decode MIME encoded headers. We MUST do this before * looking at the Content-Type / Content-Transfer-Encoding * headers (RFC 2046). */ if ( ctl->mimedecode ) { char *tcp; UnMimeHeader(line); /* the line is now shorter. So we retrace back till we find * our terminating combination \n\0, we move backwards to * make sure that we don't catch some \n\0 stored in the * decoded part of the message */ for (tcp = line + linelen - 1; tcp > line && (*tcp != 0 || tcp[-1] != '\n'); tcp--); if (tcp > line) linelen = tcp - line; } /* skip processing if we are going to retain or refuse this mail */ if (retain_mail || refuse_mail) { free(line); continue; } /* we see an ordinary (non-header, non-message-delimiter) line */ if (linelen != strlen (line)) has_nuls = TRUE; /* * The University of Washington IMAP server (the reference * implementation of IMAP4 written by Mark Crispin) relies * on being able to keep base-UID information in a special * message at the head of the mailbox. This message should * neither be deleted nor forwarded. * * An example for such a message is (keep this in so people * find it when looking where the special code is to handle the * data): * * From MAILER-DAEMON Wed Nov 23 11:38:42 2005 * Date: 23 Nov 2005 11:38:42 +0100 * From: Mail System Internal Data <*****@*****.**> * Subject: DON'T DELETE THIS MESSAGE -- FOLDER INTERNAL DATA * Message-ID: <*****@*****.**> * X-IMAP: 1132742306 0000000001 * Status: RO * * This text is part of the internal format of your mail folder, and is not * a real message. It is created automatically by the mail system software. * If deleted, important folder data will be lost, and it will be re-created * with the data reset to initial values. * * This message is only visible if a POP3 server that is unaware * of these UWIMAP messages is used besides UWIMAP or PINE. * * We will just check if the first message in the mailbox has an * X-IMAP: header. */ #ifdef POP2_ENABLE /* * We disable this check under POP2 because there's no way to * prevent deletion of the message. So at least we ought to * forward it to the user so he or she will have some clue * that things have gone awry. */ if (servport("pop2") != servport(protocol->service)) #endif /* POP2_ENABLE */ if (num == 1 && !strncasecmp(line, "X-IMAP:", 7)) { free(line); retain_mail = 1; continue; } /* * This code prevents fetchmail from becoming an accessory after * the fact to upstream sendmails with the `E' option on. It also * copes with certain brain-dead POP servers (like NT's) that pass * through Unix from_ lines. * * Either of these bugs can result in a non-RFC822 line at the * beginning of the headers. If fetchmail just passes it * through, the client listener may think the message has *no* * headers (since the first) line it sees doesn't look * RFC822-conformant) and fake up a set. * * What the user would see in this case is bogus (synthesized) * headers, followed by a blank line, followed by the >From, * followed by the real headers, followed by a blank line, * followed by text. * * We forestall this lossage by tossing anything that looks * like an escaped or passed-through From_ line in headers. * These aren't RFC822 so our conscience is clear... */ if (!strncasecmp(line, ">From ", 6) || !strncasecmp(line, "From ", 5)) { free(line); continue; } /* * We remove all Delivered-To: headers if dropdelivered is set * - special care must be taken if Delivered-To: is also used * as envelope at the same time. * * This is to avoid false mail loops errors when delivering * local messages to and from a Postfix or qmail mailserver. */ if (ctl->dropdelivered && !strncasecmp(line, "Delivered-To:", 13)) { if (delivered_to || ctl->server.envelope == STRING_DISABLED || !ctl->server.envelope || strcasecmp(ctl->server.envelope, "Delivered-To") || delivered_to_count != ctl->server.envskip) free(line); else delivered_to = line; delivered_to_count++; continue; } /* * If we see a Status line, it may have been inserted by an MUA * on the mail host, or it may have been inserted by the server * program after the headers in the transaction stream. This * can actually hose some new-mail notifiers such as xbuffy, * which assumes any Status line came from a *local* MDA and * therefore indicates that the message has been seen. * * Some buggy POP servers (including at least the 3.3(20) * version of the one distributed with IMAP) insert empty * Status lines in the transaction stream; we'll chuck those * unconditionally. Nonempty ones get chucked if the user * turns on the dropstatus flag. */ { char *tcp; if (!strncasecmp(line, "Status:", 7)) tcp = line + 7; else if (!strncasecmp(line, "X-Mozilla-Status:", 17)) tcp = line + 17; else tcp = NULL; if (tcp) { while (*tcp && isspace((unsigned char)*tcp)) tcp++; if (!*tcp || ctl->dropstatus) { free(line); continue; } } } if (ctl->rewrite) line = reply_hack(line, ctl->server.truename, &linelen); /* * OK, this is messy. If we're forwarding by SMTP, it's the * SMTP-receiver's job (according to RFC821, page 22, section * 4.1.1) to generate a Return-Path line on final delivery. * The trouble is, we've already got one because the * mailserver's SMTP thought *it* was responsible for final * delivery. * * Stash away the contents of Return-Path (as modified by reply_hack) * for use in generating MAIL FROM later on, then prevent the header * from being saved with the others. In effect, we strip it off here. * * If the SMTP server conforms to the standards, and fetchmail gets the * envelope sender from the Return-Path, the new Return-Path should be * exactly the same as the original one. * * We do *not* want to ignore empty Return-Path headers. These should * be passed through as a way of indicating that a message should * not trigger bounces if delivery fails. What we *do* need to do is * make sure we never try to rewrite such a blank Return-Path. We * handle this with a check for <> in the rewrite logic above. * * Also, if an email has multiple Return-Path: headers, we only * read the first occurance, as some spam email has more than one * Return-Path. * */ if ((already_has_return_path==FALSE) && !strncasecmp("Return-Path:", line, 12) && (cp = nxtaddr(line))) { char nulladdr[] = "<>"; already_has_return_path = TRUE; if (cp[0]=='\0') /* nxtaddr() strips the brackets... */ cp=nulladdr; strncpy(msgblk.return_path, cp, sizeof(msgblk.return_path)); msgblk.return_path[sizeof(msgblk.return_path)-1] = '\0'; if (!ctl->mda) { free(line); continue; } } if (!msgblk.headers) { oldlen = linelen; msgblk.headers = (char *)xmalloc(oldlen + 1); (void) memcpy(msgblk.headers, line, linelen); msgblk.headers[oldlen] = '\0'; free(line); line = msgblk.headers; } else { char *newhdrs; int newlen; newlen = oldlen + linelen; newhdrs = (char *) realloc(msgblk.headers, newlen + 1); if (newhdrs == NULL) { free(line); return(PS_IOERR); } msgblk.headers = newhdrs; memcpy(msgblk.headers + oldlen, line, linelen); msgblk.headers[newlen] = '\0'; free(line); line = msgblk.headers + oldlen; oldlen = newlen; } /* find offsets of various special headers */ if (!strncasecmp("From:", line, 5)) from_offs = (line - msgblk.headers); else if (!strncasecmp("Reply-To:", line, 9)) reply_to_offs = (line - msgblk.headers); else if (!strncasecmp("Resent-From:", line, 12)) resent_from_offs = (line - msgblk.headers); else if (!strncasecmp("Apparently-From:", line, 16)) app_from_offs = (line - msgblk.headers); /* * Netscape 4.7 puts "Sender: zap" in mail headers. Perverse... * * But a literal reading of RFC822 sec. 4.4.2 supports the idea * that Sender: *doesn't* have to be a working email address. * * The definition of the Sender header in RFC822 says, in * part, "The Sender mailbox specification includes a word * sequence which must correspond to a specific agent (i.e., a * human user or a computer program) rather than a standard * address." That implies that the contents of the Sender * field don't need to be a legal email address at all So * ignore any Sender or Resent-Sender lines unless they * contain @. * * (RFC2822 says the contents of Sender must be a valid mailbox * address, which is also what RFC822 4.4.4 implies.) */ else if (!strncasecmp("Sender:", line, 7) && (strchr(line, '@') || strchr(line, '!'))) sender_offs = (line - msgblk.headers); else if (!strncasecmp("Resent-Sender:", line, 14) && (strchr(line, '@') || strchr(line, '!'))) resent_sender_offs = (line - msgblk.headers); #ifdef __UNUSED__ else if (!strncasecmp("Message-Id:", line, 11)) { if (ctl->server.uidl) { char id[IDLEN+1]; line[IDLEN+12] = 0; /* prevent stack overflow */ sscanf(line+12, "%s", id); if (!str_find( &ctl->newsaved, num)) { struct idlist *newl = save_str(&ctl->newsaved,id,UID_SEEN); newl->val.status.num = num; } } } #endif /* __UNUSED__ */ /* if multidrop is on, gather addressee headers */ if (MULTIDROP(ctl)) { if (!strncasecmp("To:", line, 3) || !strncasecmp("Cc:", line, 3) || !strncasecmp("Bcc:", line, 4) || !strncasecmp("Apparently-To:", line, 14)) { *to_chainptr = (struct addrblk *)xmalloc(sizeof(struct addrblk)); (*to_chainptr)->offset = (line - msgblk.headers); to_chainptr = &(*to_chainptr)->next; *to_chainptr = NULL; } else if (!strncasecmp("Resent-To:", line, 10) || !strncasecmp("Resent-Cc:", line, 10) || !strncasecmp("Resent-Bcc:", line, 11)) { *resent_to_chainptr = (struct addrblk *)xmalloc(sizeof(struct addrblk)); (*resent_to_chainptr)->offset = (line - msgblk.headers); resent_to_chainptr = &(*resent_to_chainptr)->next; *resent_to_chainptr = NULL; } else if (ctl->server.envelope != STRING_DISABLED) { if (ctl->server.envelope && strcasecmp(ctl->server.envelope, "Received")) { if (env_offs == -1 && !strncasecmp(ctl->server.envelope, line, strlen(ctl->server.envelope))) { if (skipcount++ < ctl->server.envskip) continue; env_offs = (line - msgblk.headers); } } else if (!received_for && !strncasecmp("Received:", line, 9)) { if (skipcount++ < ctl->server.envskip) continue; received_for = parse_received(ctl, line); } } } } process_headers: if (retain_mail) { return(PS_RETAINED); } if (refuse_mail) return(PS_REFUSED); /* * This is the duplicate-message killer code. * * When mail delivered to a multidrop mailbox on the server is * addressed to multiple people on the client machine, there will * be one copy left in the box for each recipient. This is not a * problem if we have the actual recipient address to dispatch on * (e.g. because we've mined it out of sendmail trace headers, or * a qmail Delivered-To line, or a declared sender envelope line). * * But if we're mining addressees out of the To/Cc/Bcc fields, and * if the mail is addressed to N people, each recipient will * get N copies. This is bad when N > 1. * * Foil this by suppressing all but one copy of a message with a * given set of headers. * * Note: This implementation only catches runs of successive * messages with the same ID, but that should be good * enough. A more general implementation would have to store * ever-growing lists of seen message-IDs; in a long-running * daemon this would turn into a memory leak even if the * implementation were perfect. * * Don't mess with this code casually. It would be way too easy * to break it in a way that blackholed mail. Better to pass * the occasional duplicate than to do that... * * Matthias Andree: * The real fix however is to insist on Delivered-To: or similar * headers and require that one copy per recipient be dropped. * Everything else breaks sooner or later. */ if (MULTIDROP(ctl) && msgblk.headers) { MD5_CTX context; MD5Init(&context); MD5Update(&context, (unsigned char *)msgblk.headers, strlen(msgblk.headers)); MD5Final(ctl->digest, &context); if (!received_for && env_offs == -1 && !delivered_to) { /* * Hmmm...can MD5 ever yield all zeroes as a hash value? * If so there is a one in 18-quadrillion chance this * code will incorrectly nuke the first message. */ if (!memcmp(ctl->lastdigest, ctl->digest, DIGESTLEN)) return(PS_REFUSED); } memcpy(ctl->lastdigest, ctl->digest, DIGESTLEN); } /* * Hack time. If the first line of the message was blank, with no headers * (this happens occasionally due to bad gatewaying software) cons up * a set of fake headers. * * If you modify the fake header template below, be sure you don't * make either From or To address @-less, otherwise the reply_hack * logic will do bad things. */ if (msgblk.headers == (char *)NULL) { snprintf(buf, sizeof(buf), "From: FETCHMAIL-DAEMON\r\n" "To: %s@%s\r\n" "Subject: Headerless mail from %s's mailbox on %s\r\n", user, fetchmailhost, ctl->remotename, ctl->server.truename); msgblk.headers = xstrdup(buf); } /* * We can now process message headers before reading the text. * In fact we have to, as this will tell us where to forward to. */ /* Check for MIME headers indicating possible 8-bit data */ ctl->mimemsg = MimeBodyType(msgblk.headers, ctl->mimedecode); #ifdef SDPS_ENABLE if (ctl->server.sdps && sdps_envfrom) { /* We have the real envelope return-path, stored out of band by * SDPS - that's more accurate than any header is going to be. */ strlcpy(msgblk.return_path, sdps_envfrom, sizeof(msgblk.return_path)); free(sdps_envfrom); } else #endif /* SDPS_ENABLE */ /* * If there is a Return-Path address on the message, this was * almost certainly the MAIL FROM address given the originating * sendmail. This is the best thing to use for logging the * message origin (it sets up the right behavior for bounces and * mailing lists). Otherwise, fall down to the next available * envelope address (which is the most probable real sender). * *** The order is important! *** * This is especially useful when receiving mailing list * messages in multidrop mode. if a local address doesn't * exist, the bounce message won't be returned blindly to the * author or to the list itself but rather to the list manager * (ex: specified by "Sender:") which is much less annoying. This * is true for most mailing list packages. */ if( !msgblk.return_path[0] ){ char *ap = NULL; if (resent_sender_offs >= 0 && (ap = nxtaddr(msgblk.headers + resent_sender_offs))); else if (sender_offs >= 0 && (ap = nxtaddr(msgblk.headers + sender_offs))); else if (resent_from_offs >= 0 && (ap = nxtaddr(msgblk.headers + resent_from_offs))); else if (from_offs >= 0 && (ap = nxtaddr(msgblk.headers + from_offs))); else if (reply_to_offs >= 0 && (ap = nxtaddr(msgblk.headers + reply_to_offs))); else if (app_from_offs >= 0 && (ap = nxtaddr(msgblk.headers + app_from_offs))) {} /* multi-line MAIL FROM addresses confuse SMTP terribly */ if (ap && !strchr(ap, '\n')) { strncpy(msgblk.return_path, ap, sizeof(msgblk.return_path)); msgblk.return_path[sizeof(msgblk.return_path)-1] = '\0'; } } /* cons up a list of local recipients */ msgblk.recipients = (struct idlist *)NULL; accept_count = reject_count = 0; /* is this a multidrop box? */ if (MULTIDROP(ctl)) { #ifdef SDPS_ENABLE if (ctl->server.sdps && sdps_envto) { /* We have the real envelope recipient, stored out of band by * SDPS - that's more accurate than any header is going to be. */ find_server_names(sdps_envto, ctl, &msgblk.recipients); free(sdps_envto); } else #endif /* SDPS_ENABLE */ if (env_offs > -1) /* We have the actual envelope addressee */ find_server_names(msgblk.headers + env_offs, ctl, &msgblk.recipients); else if (delivered_to && ctl->server.envelope != STRING_DISABLED && ctl->server.envelope && !strcasecmp(ctl->server.envelope, "Delivered-To")) { find_server_names(delivered_to, ctl, &msgblk.recipients); xfree(delivered_to); } else if (received_for) /* * We have the Received for addressee. * It has to be a mailserver address, or we * wouldn't have got here. * We use find_server_names() to let local * hostnames go through. */ find_server_names(received_for, ctl, &msgblk.recipients); else { /* * We haven't extracted the envelope address. * So check all the "Resent-To" header addresses if * they exist. If and only if they don't, consider * the "To" addresses. */ register struct addrblk *nextptr; if (resent_to_addrchain) { /* delete the "To" chain and substitute it * with the "Resent-To" list */ while (to_addrchain) { nextptr = to_addrchain->next; free(to_addrchain); to_addrchain = nextptr; } to_addrchain = resent_to_addrchain; resent_to_addrchain = NULL; } /* now look for remaining adresses */ while (to_addrchain) { find_server_names(msgblk.headers+to_addrchain->offset, ctl, &msgblk.recipients); nextptr = to_addrchain->next; free(to_addrchain); to_addrchain = nextptr; } } if (!accept_count) { no_local_matches = TRUE; save_str(&msgblk.recipients, run.postmaster, XMIT_ACCEPT); if (outlevel >= O_DEBUG) report(stdout, GT_("no local matches, forwarding to %s\n"), run.postmaster); } } else /* it's a single-drop box, use first localname */ save_str(&msgblk.recipients, ctl->localnames->id, XMIT_ACCEPT); /* * Time to either address the message or decide we can't deliver it yet. */ if (ctl->errcount > olderrs) /* there were DNS errors above */ { if (outlevel >= O_DEBUG) report(stdout, GT_("forwarding and deletion suppressed due to DNS errors\n")); return(PS_TRANSIENT); } else { /* set up stuffline() so we can deliver the message body through it */ if ((n = open_sink(ctl, &msgblk, &good_addresses, &bad_addresses)) != PS_SUCCESS) { return(n); } } n = 0; /* * Some server/sendmail combinations cause problems when our * synthetic Received line is before the From header. Cope * with this... */ if ((rcv = strstr(msgblk.headers, "Received:")) == (char *)NULL) rcv = msgblk.headers; /* handle ">Received:" lines too */ while (rcv > msgblk.headers && rcv[-1] != '\n') rcv--; if (rcv > msgblk.headers) { char c = *rcv; *rcv = '\0'; n = stuffline(ctl, msgblk.headers); *rcv = c; } if (!run.invisible && n != -1) { /* utter any per-message Received information we need here */ if (ctl->server.trueaddr) { char saddr[50]; int e; e = getnameinfo(ctl->server.trueaddr, ctl->server.trueaddr_len, saddr, sizeof(saddr), NULL, 0, NI_NUMERICHOST); if (e) snprintf(saddr, sizeof(saddr), "(%-.*s)", (int)(sizeof(saddr) - 3), gai_strerror(e)); snprintf(buf, sizeof(buf), "Received: from %s [%s]\r\n", ctl->server.truename, saddr); } else { snprintf(buf, sizeof(buf), "Received: from %s\r\n", ctl->server.truename); } n = stuffline(ctl, buf); if (n != -1) { /* * We SHOULD (RFC-2821 sec. 4.4/p. 53) make sure to only use * IANA registered protocol names here. */ snprintf(buf, sizeof(buf), "\tby %s with %s (fetchmail-%s", fetchmailhost, protocol->name, VERSION); if (ctl->server.tracepolls) { snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), " polling %s account %s", ctl->server.pollname, ctl->remotename); if (ctl->folder) snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), " folder %s", ctl->folder); } snprintf(buf+strlen(buf), sizeof(buf)-strlen(buf), ")\r\n"); n = stuffline(ctl, buf); if (n != -1) { buf[0] = '\t'; if (good_addresses == 0) { snprintf(buf+1, sizeof(buf)-1, "for <%s> (by default); ", rcpt_address (ctl, run.postmaster, 0)); } else if (good_addresses == 1) { for (idp = msgblk.recipients; idp; idp = idp->next) if (idp->val.status.mark == XMIT_ACCEPT) break; /* only report first address */ if (idp) snprintf(buf+1, sizeof(buf)-1, "for <%s>", rcpt_address (ctl, idp->id, 1)); snprintf(buf+strlen(buf), sizeof(buf)-strlen(buf)-1, " (%s); ", MULTIDROP(ctl) ? "multi-drop" : "single-drop"); } else buf[1] = '\0'; snprintf(buf+strlen(buf), sizeof(buf)-strlen(buf), "%s\r\n", rfc822timestamp()); n = stuffline(ctl, buf); } } } if (n != -1) n = stuffline(ctl, rcv); /* ship out rest of msgblk.headers */ if (n == -1) { report(stdout, GT_("writing RFC822 msgblk.headers\n")); release_sink(ctl); return(PS_IOERR); } if (want_progress()) fputc('#', stdout); /* write error notifications */ if (no_local_matches || has_nuls || bad_addresses) { int errlen = 0; char errhd[USERNAMELEN + POPBUFSIZE], *errmsg; errmsg = errhd; strlcpy(errhd, "X-Fetchmail-Warning: ", sizeof(errhd)); if (no_local_matches) { if (reject_count != 1) strlcat(errhd, GT_("no recipient addresses matched declared local names"), sizeof(errhd)); else { for (idp = msgblk.recipients; idp; idp = idp->next) if (idp->val.status.mark == XMIT_REJECT) break; snprintf(errhd+strlen(errhd), sizeof(errhd)-strlen(errhd), GT_("recipient address %s didn't match any local name"), idp->id); } } if (has_nuls) { if (errhd[sizeof("X-Fetchmail-Warning: ")]) snprintf(errhd+strlen(errhd), sizeof(errhd)-strlen(errhd), "; "); snprintf(errhd+strlen(errhd), sizeof(errhd)-strlen(errhd), GT_("message has embedded NULs")); } if (bad_addresses) { if (errhd[sizeof("X-Fetchmail-Warning: ")]) snprintf(errhd+strlen(errhd), sizeof(errhd)-strlen(errhd), "; "); snprintf(errhd+strlen(errhd), sizeof(errhd)-strlen(errhd), GT_("SMTP listener rejected local recipient addresses: ")); errlen = strlen(errhd); for (idp = msgblk.recipients; idp; idp = idp->next) if (idp->val.status.mark == XMIT_RCPTBAD) errlen += strlen(idp->id) + 2; errmsg = (char *)xmalloc(errlen + 3); strcpy(errmsg, errhd); for (idp = msgblk.recipients; idp; idp = idp->next) if (idp->val.status.mark == XMIT_RCPTBAD) { strcat(errmsg, idp->id); if (idp->next) strcat(errmsg, ", "); } } strcat(errmsg, "\r\n"); /* ship out the error line */ stuffline(ctl, errmsg); if (errmsg != errhd) free(errmsg); } /* issue the delimiter line */ cp = buf; *cp++ = '\r'; *cp++ = '\n'; *cp = '\0'; n = stuffline(ctl, buf); if ((size_t)n == strlen(buf)) return PS_SUCCESS; else return PS_SOCKET; }
/** Read saved IDs from \a idfile and attach to each host in \a hostlist. */ void initialize_saved_lists(struct query *hostlist, const char *idfile) { struct stat statbuf; FILE *tmpfp; struct query *ctl; /* make sure lists are initially empty */ for (ctl = hostlist; ctl; ctl = ctl->next) { ctl->skipped = (struct idlist *)NULL; init_uid_db(&ctl->oldsaved); init_uid_db(&ctl->newsaved); } errno = 0; /* * Croak if the uidl directory does not exist. * This probably means an NFS mount failed and we can't * see a uidl file that ought to be there. * Question: is this a portable check? It's not clear * that all implementations of lstat() will return ENOTDIR * rather than plain ENOENT in this case... */ if (lstat(idfile, &statbuf) < 0) { if (errno == ENOTDIR) { report(stderr, "lstat: %s: %s\n", idfile, strerror(errno)); exit(PS_IOERR); } } /* let's get stored message UIDs from previous queries */ if ((tmpfp = fopen(idfile, "r")) != (FILE *)NULL) { char buf[POPBUFSIZE+1]; char *host = NULL; /* pacify -Wall */ char *user; char *id; char *atsign; /* temp pointer used in parsing user and host */ char *delimp1; char saveddelim1; char *delimp2; char saveddelim2 = '\0'; /* pacify -Wall */ while (fgets(buf, POPBUFSIZE, tmpfp) != (char *)NULL) { /* * At this point, we assume the bug has two fields -- a user@host * part, and an ID part. Either field may contain spurious @ signs. * The previous version of this code presumed one could split at * the rightmost '@'. This is not correct, as InterMail puts an * '@' in the UIDL. */ /* first, skip leading spaces */ user = buf + strspn(buf, " \t"); /* * First, we split the buf into a userhost part and an id * part ... but id doesn't necessarily start with a '<', * espescially if the POP server returns an X-UIDL header * instead of a Message-ID, as GMX's (www.gmx.net) POP3 * StreamProxy V1.0 does. * * this is one other trick. The userhost part * may contain ' ' in the user part, at least in * the lotus notes case. * So we start looking for the '@' after which the * host will follow with the ' ' separator with the id. * * XXX FIXME: There is a case this code cannot handle: * the user name cannot have blanks after a '@'. */ if ((delimp1 = strchr(user, '@')) != NULL && (id = strchr(delimp1,' ')) != NULL) { for (delimp1 = id; delimp1 >= user; delimp1--) if ((*delimp1 != ' ') && (*delimp1 != '\t')) break; /* * It should be safe to assume that id starts after * the " " - after all, we're writing the " " * ourselves in write_saved_lists() :-) */ id = id + strspn(id, " "); delimp1++; /* but what if there is only white space ?!? */ /* we have at least one @, else we are not in this branch */ saveddelim1 = *delimp1; /* save char after token */ *delimp1 = '\0'; /* delimit token with \0 */ /* now remove trailing white space chars from id */ if ((delimp2 = strpbrk(id, " \t\n")) != NULL ) { saveddelim2 = *delimp2; *delimp2 = '\0'; } atsign = strrchr(user, '@'); /* we have at least one @, else we are not in this branch */ *atsign = '\0'; host = atsign + 1; /* find uidl db and save it */ for (ctl = hostlist; ctl; ctl = ctl->next) { if (strcasecmp(host, ctl->server.queryname) == 0 && strcasecmp(user, ctl->remotename) == 0) { uid_db_insert(&ctl->oldsaved, id, UID_SEEN); break; } } /* * If it's not in a host we're querying, * save it anyway. Otherwise we'd lose UIDL * information any time we queried an explicit * subset of hosts. */ if (ctl == (struct query *)NULL) { /* restore string */ *delimp1 = saveddelim1; *atsign = '@'; if (delimp2 != NULL) { *delimp2 = saveddelim2; } save_str(&scratchlist, buf, UID_SEEN); } } } fclose(tmpfp); /* not checking should be safe, mode was "r" */ } if (outlevel >= O_DEBUG) { struct idlist *idp; for (ctl = hostlist; ctl; ctl = ctl->next) { report_build(stdout, GT_("Old UID list from %s:"), ctl->server.pollname); if (!uid_db_n_records(&ctl->oldsaved)) report_build(stdout, GT_(" <empty>")); else traverse_uid_db(&ctl->oldsaved, dump_saved_uid, NULL); report_complete(stdout, "\n"); } report_build(stdout, GT_("Scratch list of UIDs:")); if (!scratchlist) report_build(stdout, GT_(" <empty>")); else for (idp = scratchlist; idp; idp = idp->next) { char *t = sdump(idp->id, strlen(idp->id)-1); report_build(stdout, " %s\n", t); free(t); } report_complete(stdout, "\n"); } }
/* ---------------- sub_mat_read ------------------------------ */ struct sub_mat * sub_mat_read (const char *fname) { # ifndef BUFSIZ # error please define BUFSIZ to around 1024 # endif fpos_t pos; struct sub_mat *smat = NULL; FILE *fp; char buf [BUFSIZ]; char aanames [ MAX_AA + 3]; const char *this_sub = "read_mat"; const char comment = '#'; if ((fp = mfopen (fname, "r", this_sub)) == NULL) return NULL; /* Portably initialise the fpos_t structure * because =0 is insufficient */ if (fgetpos(fp, &pos)) { mperror (this_sub); goto broken; } smat = E_MALLOC ( sizeof (*smat)); smat -> fname = NULL; smat -> comment = NULL; smat->fname = save_str (fname); while (fgets (buf, BUFSIZ, fp) != NULL) { if ( buf[0] != comment) { if (fsetpos (fp, &pos)) { mperror (this_sub); goto broken; } break; } smat->comment = save_str_append (smat->comment, buf); if (fgetpos(fp, &pos)) { mperror (this_sub); goto broken; } } if (fgets (buf, BUFSIZ, fp) == NULL) goto broken; memset (aanames, BAD_AA, MAX_AA); if (get_aa_names (aanames, buf, BAD_AA) == EXIT_FAILURE) goto broken; { int n, m; for (n = 0; n < MAX_AA; n++) for ( m = 0; m < MAX_AA; m++) smat->data[n][m] = (mat_t) INVALID; } { int n = 0; for ( ;fgets(buf, BUFSIZ, fp) != NULL; n++) { if (aanames [n] == BAD_AA) continue; if (add_to_mat (smat, aanames, buf, n) == EXIT_FAILURE) err_printf (this_sub, "Ignoring matrix line\n"); } } fclose (fp); return smat; broken: fclose (fp); free_if_not_null (smat->comment); free_if_not_null (smat->fname); free_if_not_null (smat); return NULL; }
/** parse and validate the command line options */ int parsecmdline (int argc /** argument count */, char **argv /** argument strings */, struct runctl *rctl /** global run controls to modify */, struct query *ctl /** option record to initialize */, flag *safewithbg /** set to whether options are compatible with another copy running in the background */) { /* * return value: if positive, argv index of last parsed option + 1 * (presumes one or more server names follows). if zero, the * command line switches are such that no server names are * required (e.g. --version). if negative, the command line is * has one or more syntax errors. */ int c; int ocount = 0; /* count of destinations specified */ int errflag = 0; /* TRUE when a syntax error is detected */ int helpflag = 0; /* TRUE when option help was explicitly requested */ int option_index; int option_safe; /* to track if option currently parsed is safe with a background copy */ char *buf, *cp; rctl->poll_interval = -1; *safewithbg = TRUE; memset(ctl, '\0', sizeof(struct query)); /* start clean */ ctl->smtp_socket = -1; while (!errflag && (c = getopt_long(argc,argv,shortoptions, longoptions, &option_index)) != -1) { option_safe = FALSE; switch (c) { #ifdef HAVE_LIBPWMD case 'C': ctl->pwmd_socket = prependdir(optarg, currentwd); break; case 'G': ctl->pwmd_file = xstrdup(optarg); break; case 'O': rctl->pinentry_timeout = atoi(optarg); break; #endif case 'V': versioninfo = TRUE; option_safe = TRUE; break; case 'c': check_only = TRUE; break; case 's': outlevel = O_SILENT; option_safe = 1; break; case 'v': if (outlevel >= O_VERBOSE) outlevel = O_DEBUG; else outlevel = O_VERBOSE; option_safe = TRUE; break; case 'd': rctl->poll_interval = xatoi(optarg, &errflag); break; case 'N': nodetach = TRUE; break; case 'q': quitmode = TRUE; quitind = optind; break; case 'L': rctl->logfile = prependdir (optarg, currentwd); break; case LA_INVISIBLE: rctl->invisible = FLAG_TRUE; break; case LA_SHOWDOTS: rctl->showdots = FLAG_TRUE; break; case 'f': xfree(rcfile); rcfile = prependdir (optarg, currentwd); break; case 'i': rctl->idfile = prependdir (optarg, currentwd); break; case LA_PIDFILE: rctl->pidfile = prependdir (optarg, currentwd); break; case LA_POSTMASTER: rctl->postmaster = (char *) xstrdup(optarg); break; case LA_NOBOUNCE: rctl->bouncemail = FLAG_FALSE; break; case LA_NOSOFTBOUNCE: rctl->softbounce = FLAG_FALSE; break; case LA_SOFTBOUNCE: rctl->softbounce = FLAG_TRUE; break; case LA_BADHEADER: if (strcasecmp(optarg,"accept") == 0) { ctl->server.badheader = BHACCEPT; } else if (strcasecmp(optarg,"reject") == 0) { ctl->server.badheader = BHREJECT; } else { fprintf(stderr,GT_("Invalid bad-header policy `%s' specified.\n"), optarg); errflag++; } break; case 'p': /* XXX -- should probably use a table lookup here */ if (strcasecmp(optarg,"auto") == 0) ctl->server.protocol = P_AUTO; #ifdef SDPS_ENABLE else if (strcasecmp(optarg,"sdps") == 0) { ctl->server.protocol = P_POP3; ctl->server.sdps = TRUE; } #endif /* SDPS_ENABLE */ else if (strcasecmp(optarg,"pop3") == 0) ctl->server.protocol = P_POP3; else if (strcasecmp(optarg,"kpop") == 0) { ctl->server.protocol = P_POP3; ctl->server.service = xstrdup(KPOP_PORT); #ifdef KERBEROS_V5 ctl->server.authenticate = A_KERBEROS_V5; #endif /* KERBEROS_V5 */ } else if (strcasecmp(optarg,"imap") == 0) ctl->server.protocol = P_IMAP; else if (strcasecmp(optarg,"etrn") == 0) ctl->server.protocol = P_ETRN; else if (strcasecmp(optarg,"odmr") == 0) ctl->server.protocol = P_ODMR; else { fprintf(stderr,GT_("Invalid protocol `%s' specified.\n"), optarg); errflag++; } break; case 'U': /* EMPTY - removed in 7.0.0 */ break; case LA_IDLE: ctl->idle = FLAG_TRUE; break; case 'P': ctl->server.service = optarg; break; case LA_AUTH: if (strcmp(optarg, "password") == 0) ctl->server.authenticate = A_PASSWORD; #ifdef KERBEROS_V5 else if (strcmp(optarg, "kerberos") == 0) ctl->server.authenticate = A_KERBEROS_V5; else if (strcmp(optarg, "kerberos_v5") == 0) ctl->server.authenticate = A_KERBEROS_V5; #endif /* KERBEROS_V5 */ else if (strcmp(optarg, "ssh") == 0) ctl->server.authenticate = A_SSH; else if (strcasecmp(optarg, "external") == 0) ctl->server.authenticate = A_EXTERNAL; else if (strcmp(optarg, "otp") == 0) ctl->server.authenticate = A_OTP; else if (strcmp(optarg, "opie") == 0) ctl->server.authenticate = A_OTP; else if (strcmp(optarg, "ntlm") == 0) ctl->server.authenticate = A_NTLM; else if (strcmp(optarg, "cram") == 0) ctl->server.authenticate = A_CRAM_MD5; else if (strcmp(optarg, "cram-md5") == 0) ctl->server.authenticate = A_CRAM_MD5; else if (strcmp(optarg, "gssapi") == 0) ctl->server.authenticate = A_GSSAPI; else if (strcmp(optarg, "any") == 0) ctl->server.authenticate = A_ANY; else if (strcmp(optarg, "msn") == 0) ctl->server.authenticate = A_MSN; else if (strcmp(optarg, "apop") == 0) ctl->server.authenticate = A_APOP; else { fprintf(stderr,GT_("Invalid authentication `%s' specified.\n"), optarg); errflag++; } break; case 't': ctl->server.timeout = xatoi(optarg, &errflag); if (ctl->server.timeout == 0) ctl->server.timeout = -1; break; case 'E': ctl->server.envelope = xstrdup(optarg); break; case 'Q': ctl->server.qvirtual = xstrdup(optarg); break; case 'u': ctl->remotename = xstrdup(optarg); break; case 'a': ctl->fetchall = FLAG_TRUE; break; case 'K': ctl->keep = FLAG_FALSE; break; case 'k': ctl->keep = FLAG_TRUE; break; case 'F': ctl->flush = FLAG_TRUE; break; case LA_LIMITFLUSH: ctl->limitflush = FLAG_TRUE; break; case 'n': ctl->rewrite = FLAG_FALSE; break; case 'l': c = xatoi(optarg, &errflag); ctl->limit = NUM_VALUE_IN(c); break; case 'r': buf = xstrdup(optarg); cp = strtok(buf, ","); do { save_str(&ctl->mailboxes, cp, 0); } while ((cp = strtok((char *)NULL, ","))); free(buf); break; case 'S': buf = xstrdup(optarg); cp = strtok(buf, ","); do { save_str(&ctl->smtphunt, cp, TRUE); } while ((cp = strtok((char *)NULL, ","))); free(buf); ocount++; break; case LA_FETCHDOMAINS: buf = xstrdup(optarg); cp = strtok(buf, ","); do { save_str(&ctl->domainlist, cp, TRUE); } while ((cp = strtok((char *)NULL, ","))); free(buf); break; case 'D': ctl->smtpaddress = xstrdup(optarg); break; case LA_SMTPNAME: ctl->smtpname = xstrdup(optarg); break; case 'Z': buf = xstrdup(optarg); cp = strtok(buf, ","); do { struct idlist *idp = save_str(&ctl->antispam, STRING_DUMMY, 0); idp->val.status.num = xatoi(cp, &errflag); } while ((cp = strtok((char *)NULL, ","))); free(buf); break; case 'b': c = xatoi(optarg, &errflag); ctl->batchlimit = NUM_VALUE_IN(c); break; case 'B': c = xatoi(optarg, &errflag); ctl->fetchlimit = NUM_VALUE_IN(c); break; case LA_FETCHSIZELIMIT: c = xatoi(optarg, &errflag); ctl->fetchsizelimit = NUM_VALUE_IN(c); break; case LA_FASTUIDL: c = xatoi(optarg, &errflag); ctl->fastuidl = NUM_VALUE_IN(c); break; case 'e': c = xatoi(optarg, &errflag); ctl->expunge = NUM_VALUE_IN(c); break; case 'm': ctl->mda = xstrdup(optarg); ocount++; break; case LA_BSMTP: ctl->bsmtp = prependdir (optarg, currentwd); ocount++; break; case LA_LMTP: ctl->listener = LMTP_MODE; break; #ifdef CAN_MONITOR case 'I': interface_parse(optarg, &ctl->server); break; case 'M': ctl->server.monitor = xstrdup(optarg); break; #endif /* CAN_MONITOR */ case LA_PLUGIN: ctl->server.plugin = xstrdup(optarg); break; case LA_PLUGOUT: ctl->server.plugout = xstrdup(optarg); break; #ifdef SSL_ENABLE case LA_SSL: ctl->sslmode = TLSM_WRAPPED; if (outlevel > O_SILENT) report(stderr, GT_("Warning: --ssl is obsolescent, please use --sslmode=wrapped instead.\n")); break; case LA_SSLKEY: ctl->sslkey = prependdir (optarg, currentwd); break; case LA_SSLCERT: ctl->sslcert = prependdir (optarg, currentwd); break; case LA_SSLMODE: { e_sslmode e = tlsm_parse(optarg); if (e != TLSM_INVALID) { ctl->sslmode = e; } else { report(stderr, GT_("Invalid argument to --sslmode \"%s\" specified.\n"), optarg); errflag = 1; } break; } case LA_SSLPROTOVER: ctl->sslproto = xstrdup(optarg); break; case LA_SSLCERTCK: ctl->sslcertck = FLAG_TRUE; break; case LA_NOSSLCERTCK: ctl->sslcertck = FLAG_FALSE; break; case LA_SSLCERTFILE: ctl->sslcertfile = prependdir(optarg, currentwd); break; case LA_SSLCERTPATH: ctl->sslcertpath = prependdir(optarg, currentwd); break; case LA_SSLCOMMONNAME: ctl->sslcommonname = xstrdup(optarg); break; case LA_SSLFINGERPRINT: ctl->sslfingerprint = xstrdup(optarg); break; #endif case LA_PRINCIPAL: ctl->server.principal = xstrdup(optarg); break; case 'y': yydebug = TRUE; break; case 'w': c = xatoi(optarg, &errflag); ctl->warnings = NUM_VALUE_IN(c); break; case LA_CONFIGDUMP: configdump = TRUE; option_safe = TRUE; break; case LA_SYSLOG: rctl->use_syslog = FLAG_TRUE; break; case LA_NOSYSLOG: rctl->use_syslog = FLAG_FALSE; break; case LA_TRACEPOLLS: ctl->server.tracepolls = FLAG_TRUE; break; case LA_RETRIEVEERROR: if (strcasecmp(optarg,"abort") == 0) { ctl->server.retrieveerror = RE_ABORT; } else if (strcasecmp(optarg,"continue") == 0) { ctl->server.retrieveerror = RE_CONTINUE; } else if (strcasecmp(optarg,"markseen") == 0) { ctl->server.retrieveerror = RE_MARKSEEN; } else { fprintf(stderr,GT_("Invalid retrieve-error policy `%s' specified.\n"), optarg); errflag++; } break; case '?': helpflag = 1; default: break; } *safewithbg &= option_safe; } if (errflag || ocount > 1 || helpflag) { /* squawk if syntax errors were detected */ #define P(s) fputs(s, helpflag ? stdout : stderr) P(GT_("usage: fetchmail [options] [server ...]\n")); P(GT_(" Options are as follows:\n")); P(GT_(" -?, --help display this option help\n")); P(GT_(" -V, --version display version info\n")); P(GT_(" -c, --check check for messages without fetching\n")); P(GT_(" -s, --silent work silently\n")); P(GT_(" -v, --verbose work noisily (diagnostic output)\n")); P(GT_(" -d, --daemon run as a daemon once per n seconds\n")); P(GT_(" -N, --nodetach don't detach daemon process\n")); P(GT_(" -q, --quit kill daemon process\n")); P(GT_(" -L, --logfile specify logfile name\n")); P(GT_(" --syslog use syslog(3) for most messages when running as a daemon\n")); P(GT_(" --invisible don't write Received & enable host spoofing\n")); P(GT_(" -f, --fetchmailrc specify alternate run control file\n")); P(GT_(" -i, --idfile specify alternate UIDs file\n")); P(GT_(" --pidfile specify alternate PID (lock) file\n")); P(GT_(" --postmaster specify recipient of last resort\n")); P(GT_(" --nobounce redirect bounces from user to postmaster.\n")); P(GT_(" --nosoftbounce fetchmail deletes permanently undeliverable messages.\n")); P(GT_(" --softbounce keep permanently undeliverable messages on server (default).\n")); #ifdef CAN_MONITOR P(GT_(" -I, --interface interface required specification\n")); P(GT_(" -M, --monitor monitor interface for activity\n")); #endif #if defined( SSL_ENABLE ) P(GT_(" --ssl enable ssl encrypted session\n")); P(GT_(" --sslkey ssl private key file\n")); P(GT_(" --sslcert ssl client certificate\n")); P(GT_(" --nosslcertck INSECURE disable server certificate check (discouraged)\n")); P(GT_(" --sslcertck do strict server certificate check (recommended)\n")); P(GT_(" --sslcertfile path to trusted-CA ssl certificate file\n")); P(GT_(" --sslcertpath path to trusted-CA ssl certificate directory\n")); P(GT_(" --sslcommonname expect this CommonName from server (discouraged)\n")); P(GT_(" --sslfingerprint fingerprint that must match that of the server's cert.\n")); P(GT_(" --sslmode force ssl mode (none/wrapped/starttls=may/starttls=must)\n")); // see tls.c P(GT_(" --sslprotocolver force ssl version (often unneeded, see manual page!)\n")); #endif P(GT_(" --plugin specify external command to open connection\n")); P(GT_(" --plugout specify external command to open smtp connection\n")); P(GT_(" --bad-header {reject|accept}\n" " specify policy for handling messages with bad headers\n")); P(GT_(" --retrieve-error {abort|continue|markseen}\n" " specify policy for processing messages with retrieve errors\n")); P(GT_(" -p, --protocol specify retrieval protocol (see man page)\n")); #ifdef HAVE_LIBPWMD P(GT_(" -C, --pwmd-socket pwmd socket path (~/.pwmd/socket)\n")); P(GT_(" -G, --pwmd-file filename to use on the pwmd server\n")); P(GT_(" -O, --pinentry-timeout seconds until pinentry is canceled\n")); #endif P(GT_(" --port TCP port to connect to (obsolete, use --service)\n")); P(GT_(" -P, --service TCP service to connect to (can be numeric TCP port)\n")); P(GT_(" --auth authentication type (password/kerberos/ssh/otp)\n")); P(GT_(" -t, --timeout server nonresponse timeout\n")); P(GT_(" -E, --envelope envelope address header\n")); P(GT_(" -Q, --qvirtual prefix to remove from local user id\n")); P(GT_(" --principal mail service principal\n")); P(GT_(" --tracepolls add poll-tracing information to Received header\n")); P(GT_(" -u, --username specify users's login on server\n")); P(GT_(" -a, --[fetch]all retrieve old and new messages\n")); P(GT_(" -K, --nokeep delete new messages after retrieval\n")); P(GT_(" -k, --keep save new messages after retrieval\n")); P(GT_(" -F, --flush delete old messages from server\n")); P(GT_(" --limitflush delete oversized messages\n")); P(GT_(" -n, --norewrite don't rewrite header addresses\n")); P(GT_(" -l, --limit don't fetch messages over given size\n")); P(GT_(" -w, --warnings interval between warning mail notification\n")); P(GT_(" -S, --smtphost set SMTP forwarding host\n")); P(GT_(" --fetchdomains fetch mail for specified domains\n")); P(GT_(" -D, --smtpaddress set SMTP delivery domain to use\n")); P(GT_(" --smtpname set SMTP full name username@domain\n")); P(GT_(" -Z, --antispam, set antispam response values\n")); P(GT_(" -b, --batchlimit set batch limit for SMTP connections\n")); P(GT_(" -B, --fetchlimit set fetch limit for server connections\n")); P(GT_(" --fetchsizelimit set fetch message size limit\n")); P(GT_(" --fastuidl do a binary search for UIDLs\n")); P(GT_(" -e, --expunge set max deletions between expunges\n")); P(GT_(" -m, --mda set MDA to use for forwarding\n")); P(GT_(" --bsmtp set output BSMTP file\n")); P(GT_(" --lmtp use LMTP (RFC2033) for delivery\n")); P(GT_(" -r, --folder specify remote folder name\n")); P(GT_(" --showdots show progress dots even in logfiles\n")); #undef P /* undocumented: * --configdump (internal use by fetchmailconf, dumps * configuration as Python source code) * --yydebug (developer use, enables parser debugging) */ if (helpflag) exit(PS_SUCCESS); else exit(PS_SYNTAX); } return(optind); }