Ejemplo n.º 1
0
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;
}
Ejemplo n.º 2
0
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;
}
Ejemplo n.º 3
0
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);
		}
	}
Ejemplo n.º 4
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;
}