struct taginfo *cgit_parse_tag(struct tag *tag) { void *data; enum object_type type; unsigned long size; const char *p; struct taginfo *ret = NULL; data = read_sha1_file(tag->object.oid.hash, &type, &size); if (!data || type != OBJ_TAG) goto cleanup; ret = xcalloc(1, sizeof(struct taginfo)); for (p = data; !end_of_header(p); p = next_header_line(p)) { if (skip_prefix(p, "tagger ", &p)) { parse_user(p, &ret->tagger, &ret->tagger_email, &ret->tagger_date, &ret->tagger_tz); } } while (p && *p == '\n') p++; if (p && *p) ret->msg = xstrdup(p); cleanup: free(data); return ret; }
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; }
int read_rtsp (sockets * s) { char *arg[50]; int cseq, la, i, rlen; char *proto, *transport = NULL, *useragent = NULL; int sess_id = 0; char buf[2000]; streams *sid = get_sid(s->sid); if(s->buf[0]==0x24 && s->buf[1]<2) { if(sid) sid->rtime = s->rtime; int rtsp_len = s->buf[2]*256+s->buf[3]; LOG("Received RTSP over tcp packet (sock_id %d, stream %d, rlen %d) packet len: %d, type %02X %02X discarding %s...", s->id, s->sid, s->rlen, rtsp_len , s->buf[4], s->buf[5], (s->rlen == rtsp_len+4)?"complete":"fragment" ); if(s->rlen == rtsp_len+4){ // we did not receive the entire packet s->rlen = 0; return 0; } } if (s->rlen < 4 || !end_of_header(s->buf + s->rlen - 4)) { if( s->rlen > RBUF - 10 ) { LOG("Discarding %d bytes from the socket buffer, request > %d, consider increasing RBUF", s->rlen, RBUF); s->rlen = 0; } LOG("read_rtsp: read %d bytes from handle %d, sock_id %d, flags %d not ending with \\r\\n\\r\\n", s->rlen, s->sock, s->id, s->flags); if ( s->flags & 1 ) return 0; unsigned char *new_alloc = malloc1 (RBUF); memcpy(new_alloc, s->buf, s->rlen); s->buf = new_alloc; s->flags = s->flags | 1; return 0; } rlen = s->rlen; s->rlen = 0; LOG ("read RTSP (from handle %d sock_id %d, len: %d, sid %d):\n%s", s->sock, s->id, s->rlen, s->sid, s->buf); if( (s->type != TYPE_HTTP ) && (strncasecmp(s->buf, "GET", 3) == 0)) { http_response (s , 404, NULL, NULL, 0, 0); return 0; } la = split (arg, s->buf, 50, ' '); cseq = 0; if (la<2) LOG_AND_RETURN(0, "Most likely not an RTSP packet sock_id: %d sid: %d rlen: %d, dropping ....", s->id, s->sid, rlen); if(s->sid<0) for (i = 0; i < la; i++) if (strncasecmp ("Session:", arg[i], 8) == 0) { sess_id = map_int(header_parameter(arg, i), NULL); s->sid = find_session_id(sess_id); } if(strstr(arg[1], "freq") || strstr(arg[1], "pids")) { int old_sid = s->sid; sid = (streams *) setup_stream (arg[1], s); } sid = get_sid(s->sid); if(sid) sid->rtime = s->rtime; if (sess_id) set_session_id(s->sid, sess_id); for (i = 0; i < la; i++) if (strncasecmp ("CSeq:", arg[i], 5) == 0) cseq = map_int (header_parameter(arg, i), NULL); else if (strncasecmp ("Transport:", arg[i], 9) == 0){ transport = header_parameter(arg, i); if( -1 == decode_transport (s, transport, opts.rrtp, opts.start_rtp)) { http_response (s, 400, NULL, NULL, cseq, 0); return 0; } } else if (strstr (arg[i], "LIVE555")) { if(sid) sid->timeout = 0; } else if (strstr (arg[i], "Lavf")) { if(sid) sid->timeout = 0; } else if (strncasecmp ("User-Agent:", arg[i], 10) == 0) useragent = header_parameter(arg, i); if((strncasecmp (arg[0], "PLAY", 4) == 0) || (strncasecmp (arg[0], "GET", 3) == 0) || (strncasecmp (arg[0], "SETUP", 5) == 0)) { char ra[100]; int rv; if (!( sid = get_sid(s->sid))) { http_response (s, 454, NULL, NULL, cseq, 0); return 0; } if (useragent) strncpy(sid->useragent, useragent, 127); if ((strncasecmp (arg[0], "PLAY", 3) == 0) || (strncasecmp (arg[0], "GET", 3) == 0)) if ((rv = start_play (sid, s)) < 0) { http_response (s, -rv , NULL, NULL, cseq, 0); return 0; } strcpy(ra, inet_ntoa (sid->sa.sin_addr)); buf[0] = 0; if(transport) { int s_timeout = (sid->timeout ? sid->timeout : opts.timeout_sec) / 1000; switch (sid->type) { case STREAM_RTSP_UDP: if (atoi (ra) < 239) snprintf (buf, sizeof(buf), "Transport: RTP/AVP;unicast;destination=%s;source=%s;client_port=%d-%d;server_port=%d-%d\r\nSession: %010d;timeout=%d\r\ncom.ses.streamID: %d", ra, get_sock_host (s->sock), ntohs (sid->sa.sin_port), ntohs (sid->sa.sin_port) + 1, // opts.start_rtp, opts.start_rtp + 1, get_sock_port(sid->rsock), get_sock_port(sid->rtcp), get_session_id (s->sid), s_timeout, sid->sid + 1); else snprintf (buf, sizeof(buf), "Transport: RTP/AVP;multicast;destination=%s;port=%d-%d\r\nSession: %010d;timeout=%d\r\ncom.ses.streamID: %d", ra, ntohs (sid->sa.sin_port), ntohs (sid->sa.sin_port) + 1, get_session_id (s->sid), s_timeout , sid->sid + 1); break; case STREAM_RTSP_TCP: snprintf(buf, sizeof(buf), "Transport: RTP/AVP/TCP;interleaved=0-1\r\nSession: %010d;timeout=%d\r\ncom.ses.streamID: %d", get_session_id (s->sid), s_timeout, sid->sid + 1); break; } } if (strncasecmp(arg[0], "PLAY", 4) == 0) { char *qm = strchr(arg[1], '?'); if(qm) *qm = 0; if(buf[0]) strcat(buf, "\r\n"); snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf) - 1, "RTP-Info: url=%s;seq=%d;rtptime=%lld\r\nRange: npt=0.000-", arg[1], getTick(),(long long int)(getTickUs()/1000000)); } if(buf[0]==0 && sid->type == STREAM_HTTP) snprintf(buf, sizeof(buf), "Content-Type: video/mp2t"); http_response (s, 200, buf, NULL, cseq, 0); } else if (strncmp (arg[0], "TEARDOWN", 8) == 0) { streams *sid; buf[0] = 0; if(get_sid(s->sid)) sprintf(buf, "Session: %010d", get_session_id(s->sid)); close_stream (s->sid); http_response (s, 200, buf, NULL, cseq, 0); } else { if (strncmp (arg[0], "DESCRIBE", 8) == 0) { char sbuf[1000]; char *rv = NULL; rv = describe_streams(s, arg[1], sbuf, sizeof(sbuf)); if (! rv) { http_response (s, 404, NULL, NULL, cseq, 0); return 0; } snprintf(buf, sizeof(buf), "Content-type: application/sdp\r\nContent-Base: rtsp://%s/", get_sock_host(s->sock)); http_response (s, 200, buf, sbuf, cseq, 0); } else if (strncmp (arg[0], "OPTIONS", 8) == 0) { http_response (s, 200, public, NULL, cseq, 0); } }
struct commitinfo *cgit_parse_commit(struct commit *commit) { const int sha1hex_len = 40; struct commitinfo *ret; const char *p = get_cached_commit_buffer(commit, NULL); const char *t; ret = xcalloc(1, sizeof(struct commitinfo)); ret->commit = commit; if (!p) return ret; if (!skip_prefix(p, "tree ", &p)) die("Bad commit: %s", oid_to_hex(&commit->object.oid)); p += sha1hex_len + 1; while (skip_prefix(p, "parent ", &p)) p += sha1hex_len + 1; if (p && skip_prefix(p, "author ", &p)) { parse_user(p, &ret->author, &ret->author_email, &ret->author_date, &ret->author_tz); p = next_header_line(p); } if (p && skip_prefix(p, "committer ", &p)) { parse_user(p, &ret->committer, &ret->committer_email, &ret->committer_date, &ret->committer_tz); p = next_header_line(p); } if (p && skip_prefix(p, "encoding ", &p)) { t = strchr(p, '\n'); if (t) { ret->msg_encoding = substr(p, t + 1); p = t + 1; } } if (!ret->msg_encoding) ret->msg_encoding = xstrdup("UTF-8"); while (!end_of_header(p)) p = next_header_line(p); while (p && *p == '\n') p++; if (!p) return ret; t = strchrnul(p, '\n'); ret->subject = substr(p, t); while (*t == '\n') t++; ret->msg = xstrdup(t); reencode(&ret->author, ret->msg_encoding, PAGE_ENCODING); reencode(&ret->author_email, ret->msg_encoding, PAGE_ENCODING); reencode(&ret->committer, ret->msg_encoding, PAGE_ENCODING); reencode(&ret->committer_email, ret->msg_encoding, PAGE_ENCODING); reencode(&ret->subject, ret->msg_encoding, PAGE_ENCODING); reencode(&ret->msg, ret->msg_encoding, PAGE_ENCODING); return ret; }