Beispiel #1
0
static int mbox_parse_year(const unsigned char *msg, struct tm *tm)
{
	if (!i_isdigit(msg[0]) || !i_isdigit(msg[1]) ||
	    !i_isdigit(msg[2]) || !i_isdigit(msg[3]))
		return -1;

	tm->tm_year = (msg[0]-'0') * 1000 + (msg[1]-'0') * 100 +
		(msg[2]-'0') * 10 + (msg[3]-'0') - 1900;
	return 0;
}
static int parse_timezone(const char *str)
{
	int offset;

	/* +|-zone */
	if ((*str != '+' && *str != '-') ||
	    !i_isdigit(str[1]) || !i_isdigit(str[2]) ||
	    !i_isdigit(str[3]) || !i_isdigit(str[4]))
		return 0;

	offset = (str[1]-'0') * 10*60 + (str[2]-'0') * 60 +
		(str[3]-'0') * 10 + (str[4]-'0');
	return *str == '+' ? offset : -offset;
}
Beispiel #3
0
static int uri_parse_port(struct uri_parser *parser, struct uri_authority *auth)
{
	unsigned long port = 0;
	int count = 0;

	/* RFC 3986:
	 *
	 * port        = *DIGIT
	 */

	while (parser->cur < parser->end && i_isdigit(*parser->cur)) {
		port = port * 10 + (parser->cur[0] - '0');
		if (port > (in_port_t)-1) {
			parser->error = "Port number is too high";
			return -1;
		}
		parser->cur++;
		count++;
	}

	if (count > 0) {
		if (auth != NULL) {
			auth->port = port;
			auth->have_port = TRUE;
		}
		return 1;
	}
	return 0;
}
Beispiel #4
0
static int
uri_parse_dec_octet(struct uri_parser *parser, string_t *literal,
		    uint8_t *octet_r)
{
	unsigned int octet = 0;
	int count = 0;

	/* RFC 3986:
	 *
	 * dec-octet     = DIGIT                 ; 0-9
	 *               / %x31-39 DIGIT         ; 10-99
	 *               / "1" 2DIGIT            ; 100-199
	 *               / "2" %x30-34 DIGIT     ; 200-249
	 *               / "25" %x30-35          ; 250-255
	 */

	while (parser->cur < parser->end && i_isdigit(*parser->cur)) {
		octet = octet * 10 + (parser->cur[0] - '0');
		if (octet > 255)
			return -1;

		if (literal != NULL)
			str_append_c(literal, *parser->cur);

		parser->cur++;
		count++;
	}

	if (count > 0) {
		*octet_r = octet;
		return 1;
	}
	return 0;
}
Beispiel #5
0
/* Expand key code - returns TRUE if successful. */
static int expand_key(const char *key, GSList **out)
{
	GSList *tmp;
	const char *start;
	int last_hyphen;

	/* meta-^W^Gf -> ^[-^W-^G-f */
        start = NULL; last_hyphen = TRUE;
	for (; *key != '\0'; key++) {
		if (start != NULL) {
			if (i_isalnum(*key) || *key == '_') {
                                /* key combo continues */
				continue;
			}

			if (!expand_combo(start, key-1, out))
                                return FALSE;
			expand_out_char(*out, '-');
                        start = NULL;
		}

		if (*key == '-') {
			if (last_hyphen) {
                                expand_out_char(*out, '-');
                                expand_out_char(*out, '-');
			}
			last_hyphen = !last_hyphen;
		} else if (*key == '^') {
                        /* ctrl-code */
			if (key[1] != '\0')
				key++;

			expand_out_char(*out, '^');
			expand_out_char(*out, *key);
			expand_out_char(*out, '-');
                        last_hyphen = FALSE; /* optional */
		} else if (last_hyphen && i_isalnum(*key) && !i_isdigit(*key)) {
                        /* possibly beginning of keycombo */
			start = key;
                        last_hyphen = FALSE;
		} else {
			expand_out_char(*out, *key);
			expand_out_char(*out, '-');
                        last_hyphen = FALSE; /* optional */
		}
	}

	if (start != NULL)
		return expand_combo(start, key-1, out);

	for (tmp = *out; tmp != NULL; tmp = tmp->next) {
		GString *str = tmp->data;

		g_string_truncate(str, str->len-1);
	}

        return TRUE;
}
Beispiel #6
0
int is_ipv4_address(const char *host)
{
	while (*host != '\0') {
		if (*host != '.' && !i_isdigit(*host))
			return 0;
                host++;
	}

	return 1;
}
static inline int
iso8601_date_parse_number(struct iso8601_date_parser *parser,
			  int digits, int *number_r)
{
	int i;

	if (parser->cur >= parser->end || !i_isdigit(parser->cur[0]))
		return 0;

	*number_r = parser->cur[0] - '0';
	parser->cur++;

	for (i=0; i < digits-1; i++) {
		if (parser->cur >= parser->end || !i_isdigit(parser->cur[0]))
			return -1;
		*number_r = ((*number_r) * 10) + parser->cur[0] - '0';
		parser->cur++;
	}
	return 1;
}
Beispiel #8
0
static int lmtp_input_get_reply_code(const char *line, int *reply_code_r)
{
	if (!i_isdigit(line[0]) || !i_isdigit(line[1]) || !i_isdigit(line[2]))
		return -1;

	*reply_code_r = (line[0]-'0') * 100 +
		(line[1]-'0') * 10 +
		(line[2]-'0');

	if (line[3] == ' ') {
		/* final reply */
		return 1;
	} else if (line[3] == '-') {
		/* multiline reply. just ignore it. */
		return 0;
	} else {
		/* invalid input */
		return -1;
	}
}
Beispiel #9
0
static void event_received(IRC_SERVER_REC *server, const char *data,
			   const char *nick, const char *addr)
{
	if (!i_isdigit(*data)) {
		printtext(server, NULL, MSGLEVEL_CRAP, "%s", data);
		return;
	}

	/* numeric event. */
        signal_emit("default event numeric", 4, server, data, nick, addr);
}
Beispiel #10
0
static int lmtp_input_get_reply_code(const char *line, int *reply_code_r,
				     string_t *multiline)
{
	if (!i_isdigit(line[0]) || !i_isdigit(line[1]) || !i_isdigit(line[2]))
		return -1;

	*reply_code_r = (line[0]-'0') * 100 +
		(line[1]-'0') * 10 +
		(line[2]-'0');

	if (line[3] == ' ') {
		/* final reply */
		return 1;
	} else if (line[3] == '-') {
		/* multiline reply. */
		str_append(multiline, line);
		str_append_c(multiline, '\n');
		return 0;
	} else {
		/* invalid input */
		return -1;
	}
}
static int
iso8601_date_parse_secfrac(struct iso8601_date_parser *parser)
{
	/* time-secfrac    = "." 1*DIGIT

	   NOTE: Currently not applied anywhere, so fraction is just skipped.
	*/

	/* "." */
	if (parser->cur >= parser->end || parser->cur[0] != '.')
		return 0;
	parser->cur++;

	/* 1DIGIT */
	if (parser->cur >= parser->end || !i_isdigit(parser->cur[0]))
		return -1;
	parser->cur++;

	/* *DIGIT */
	while (parser->cur < parser->end && i_isdigit(parser->cur[0]))
		parser->cur++;
	return 1;
}
Beispiel #12
0
static int dbox_file_parse_header(struct dbox_file *file, const char *line)
{
	const char *const *tmp, *value;
	unsigned int pos;
	enum dbox_header_key key;

	file->file_version = *line - '0';
	if (!i_isdigit(line[0]) || line[1] != ' ' ||
	    (file->file_version != 1 && file->file_version != DBOX_VERSION)) {
		dbox_file_set_corrupted(file, "Invalid dbox version");
		return -1;
	}
	line += 2;
	pos = 2;

	file->msg_header_size = 0;

	for (tmp = t_strsplit(line, " "); *tmp != NULL; tmp++) {
		uintmax_t time;
		key = **tmp;
		value = *tmp + 1;

		switch (key) {
		case DBOX_HEADER_OLDV1_APPEND_OFFSET:
			break;
		case DBOX_HEADER_MSG_HEADER_SIZE:
			if (str_to_uint_hex(value, &file->msg_header_size) < 0) {
				dbox_file_set_corrupted(file, "Invalid message header size");
				return -1;
			}
			break;
		case DBOX_HEADER_CREATE_STAMP:
			if (str_to_uintmax_hex(value, &time) < 0) {
				dbox_file_set_corrupted(file, "Invalid create time stamp");
				return -1;
			}
			file->create_time = (time_t)time;
			break;
		}
		pos += strlen(value) + 2;
	}

	if (file->msg_header_size == 0) {
		dbox_file_set_corrupted(file, "Missing message header size");
		return -1;
	}
	return 0;
}
Beispiel #13
0
static const char *
server_redirect_get(IRC_SERVER_REC *server, const char *event,
		    const char *args, REDIRECT_REC **redirect, int *match)
{
        const char *signal;

        *redirect = NULL;
	*match = MATCH_NONE;

	if (server->redirects == NULL)
		return NULL;

	if (server->redirect_continue == NULL) {
                /* find the redirection */
		*redirect = redirect_find(server, event, args, &signal, match);
	} else {
		/* redirection is already started, now we'll just need to
		   keep redirecting until stop-event is found. */
		*redirect = server->redirect_continue;
		signal = redirect_match(*redirect, event, NULL, match);
		if (signal == NULL) {
			/* unknown event - redirect to the default signal. */
			if (strncmp(event, "event ", 6) == 0 &&
			    i_isdigit(event[6])) {
				signal = (*redirect)->default_signal;
                                if (*match == MATCH_NONE)
					*match = MATCH_START;
			} else {
				/* not a numeric, so we've lost the
				   stop event.. */
                                (*redirect)->aborted = TRUE;
				redirect_abort(server, *redirect);

                                *redirect = NULL;
				signal = NULL;
			}
		}
	}

	if (*redirect != NULL && (*redirect)->first_signal != NULL &&
	    !(*redirect)->first_signal_sent) {
		/* emit the first_signal */
                (*redirect)->first_signal_sent = TRUE;
		signal_emit((*redirect)->first_signal, 1, server);
	}

        return signal;
}
static const char *imap_parse_date_internal(const char *str, struct tm *tm)
{
	int i;

	if (str == NULL || *str == '\0')
		return NULL;

	memset(tm, 0, sizeof(struct tm));

	/* "dd-mon-yyyy [hh:mi:ss +|-zone]"
	   dd is 1-2 digits and may be prefixed with space or zero. */

	if (str[0] == ' ') {
		/* " d-..." */
		str++;
	}

	if (!(i_isdigit(str[0]) && (str[1] == '-' ||
				    (i_isdigit(str[1]) && str[2] == '-'))))
	      return NULL;

	tm->tm_mday = (str[0]-'0');
	if (str[1] == '-')
		str += 2;
	else {
		tm->tm_mday = (tm->tm_mday * 10) + (str[1]-'0');
		str += 3;
	}

	/* month name */
	for (i = 0; i < 12; i++) {
		if (strncasecmp(month_names[i], str, 3) == 0) {
			tm->tm_mon = i;
			break;
		}
	}
	if (i == 12 || str[3] != '-')
		return NULL;
	str += 4;

	/* yyyy */
	if (!i_isdigit(str[0]) || !i_isdigit(str[1]) ||
	    !i_isdigit(str[2]) || !i_isdigit(str[3]))
		return NULL;

	tm->tm_year = (str[0]-'0') * 1000 + (str[1]-'0') * 100 +
		(str[2]-'0') * 10 + (str[3]-'0') - 1900;

	str += 4;
	return str;
}
bool imap_parse_datetime(const char *str, time_t *timestamp_r,
			 int *timezone_offset_r)
{
	struct tm tm;

	str = imap_parse_date_internal(str, &tm);
	if (str == NULL)
		return FALSE;

	if (str[0] != ' ')
		return FALSE;
	str++;

	/* hh: */
	if (!i_isdigit(str[0]) || !i_isdigit(str[1]) || str[2] != ':')
		return FALSE;
	tm.tm_hour = (str[0]-'0') * 10 + (str[1]-'0');
	str += 3;

	/* mm: */
	if (!i_isdigit(str[0]) || !i_isdigit(str[1]) || str[2] != ':')
		return FALSE;
	tm.tm_min = (str[0]-'0') * 10 + (str[1]-'0');
	str += 3;

	/* ss */
	if (!i_isdigit(str[0]) || !i_isdigit(str[1]) || str[2] != ' ')
		return FALSE;
	tm.tm_sec = (str[0]-'0') * 10 + (str[1]-'0');
	str += 3;

	/* timezone */
	*timezone_offset_r = parse_timezone(str);

	tm.tm_isdst = -1;
	if (imap_mktime(&tm, timestamp_r))
		*timestamp_r -= *timezone_offset_r * 60;
	return TRUE;
}
Beispiel #16
0
/* SYNTAX: KNOCKOUT [<time>] <nicks> <reason> */
static void cmd_knockout(const char *data, IRC_SERVER_REC *server,
			 IRC_CHANNEL_REC *channel)
{
	KNOCKOUT_REC *rec;
	char *nicks, *reason, *timeoutstr, *kickcmd, *bancmd, *recoded;
        char **nicklist, *spacenicks, *banmasks;
	void *free_arg;
	int timeleft;
	GSList *ptr;

        CMD_IRC_SERVER(server);

	if (!IS_IRC_CHANNEL(channel))
		cmd_return_error(CMDERR_NOT_JOINED);
	if (!channel->wholist)
		cmd_return_error(CMDERR_CHAN_NOT_SYNCED);

	if (i_isdigit(*data)) {
		/* first argument is the timeout */
		if (!cmd_get_params(data, &free_arg, 3 | PARAM_FLAG_GETREST,
				    &timeoutstr, &nicks, &reason))
                        return;

		if (!parse_time_interval(timeoutstr, &timeleft))
			cmd_param_error(CMDERR_INVALID_TIME);
	} else {
		if (!cmd_get_params(data, &free_arg, 2 | PARAM_FLAG_GETREST,
				    &nicks, &reason))
			return;
                timeleft = settings_get_time("knockout_time");
	}

	if (*nicks == '\0') cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);

	nicklist = g_strsplit(nicks, ",", -1);
        spacenicks = g_strjoinv(" ", nicklist);
	g_strfreev(nicklist);

	banmasks = ban_get_masks(channel, spacenicks, 0);
	g_free(spacenicks);

	recoded = recode_out(SERVER(server), reason, channel->name);
	kickcmd = g_strdup_printf("%s %s %s", channel->name, nicks, recoded);
	g_free(recoded);

	bancmd = *banmasks == '\0'? NULL :
		g_strdup_printf("%s %s", channel->name, banmasks);
	
        if (settings_get_bool("kick_first_on_kickban")) {
		signal_emit("command kick", 3, kickcmd, server, channel);
		if (bancmd != NULL)
			signal_emit("command ban", 3, bancmd, server, channel);
	} else {
		if (bancmd != NULL)
			signal_emit("command ban", 3, bancmd, server, channel);
		signal_emit("command kick", 3, kickcmd, server, channel);
	}
	g_free(kickcmd);
	g_free_not_null(bancmd);

	if (*banmasks == '\0')
		g_free(banmasks);
	else {
		/* check if we already have this knockout */
		for (ptr = server->knockoutlist; ptr != NULL; ptr = ptr->next) {
			rec = ptr->data;
			if (channel == rec->channel &&
					!strcmp(rec->ban, banmasks))
				break;
		}
		if (ptr == NULL) {
			rec = g_new(KNOCKOUT_REC, 1);
			rec->channel = channel;
			rec->ban = banmasks;
			server->knockoutlist = g_slist_append(server->knockoutlist, rec);
		}
		rec->unban_time = time(NULL)+timeleft/1000;
	}

	cmd_params_free(free_arg);
}
Beispiel #17
0
static const char *redirect_match(REDIRECT_REC *redirect, const char *event,
				  const char *args, int *match)
{
	GSList *tmp, *cmdpos;
	const char *signal;
        int match_list;

	if (redirect->aborted)
                return NULL;

	/* get the signal for redirection event - if it's not found we'll
	   use the default signal */
        signal = NULL;
	for (tmp = redirect->signals; tmp != NULL; tmp = tmp->next->next) {
		if (strcmp(tmp->data, event) == 0) {
			signal = tmp->next->data;
			break;
		}
	}

	/* find the argument position */
	if (redirect->destroyed) {
		/* stop event is already found for this redirection, but
		   we'll still want to look for optional events */
		cmdpos = redirect_cmd_list_find(redirect->cmd->opt, event);
		if (cmdpos == NULL)
			return NULL;

                match_list = MATCH_STOP;
	} else {
                /* look from start/stop lists */
		cmdpos = redirect_cmd_list_find(redirect->cmd->start, event);
		if (cmdpos != NULL)
			match_list = MATCH_START;
		else {
			cmdpos = redirect_cmd_list_find(redirect->cmd->stop,
							event);
			if (cmdpos != NULL)
				match_list = MATCH_STOP;
			else if (redirect->default_signal != NULL &&
					args == NULL &&
					strncmp(event, "event ", 6) == 0 &&
					i_isdigit(event[6])) {
				/* If there is a default signal, the
				 * redirection has already started and
				 * this is a numeric, use it */
				/* XXX this should depend on the
				 * REDIRECT_CMD_REC, not REDIRECT_REC */
				if (signal == NULL)
					signal = redirect->default_signal;
				match_list = MATCH_START;
			} else {
				match_list = MATCH_NONE;
			}
		}
	}

	if (signal == NULL && cmdpos == NULL) {
		/* event not found from specified redirection events nor
		   registered command events, and no default signal */
		return NULL;
	}

	/* check that arguments match */
	if (args != NULL && redirect->arg != NULL && cmdpos != NULL &&
	    !redirect_args_match(args, redirect->arg,
				 GPOINTER_TO_INT(cmdpos->next->data)))
		return NULL;

        *match = match_list;
	return signal != NULL ? signal : redirect->default_signal;
}
Beispiel #18
0
/* expand a single {abstract ...data... } */
static char *theme_format_expand_abstract(THEME_REC *theme,
					  const char **formatp,
					  char default_fg, char default_bg,
					  int flags)
{
	GString *str;
	const char *p, *format;
	char *abstract, *data, *ret;
	int len;

	format = *formatp;

	/* get abstract name first */
	p = format;
	while (*p != '\0' && *p != ' ' &&
	       *p != '{' && *p != '}') p++;
	if (*p == '\0' || p == format)
		return NULL; /* error */

	len = (int) (p-format);
	abstract = g_strndup(format, len);

	/* skip the following space, if there's any more spaces they're
	   treated as arguments */
	if (*p == ' ') {
		len++;
		if ((flags & EXPAND_FLAG_IGNORE_EMPTY) && data_is_empty(&p)) {
			*formatp = p;
			g_free(abstract);
			return NULL;
		}
	}
	*formatp = format+len;

	/* get the abstract data */
	data = g_hash_table_lookup(theme->abstracts, abstract);
	g_free(abstract);
	if (data == NULL) {
		/* unknown abstract, just display the data */
		data = "$0-";
	}
	abstract = g_strdup(data);

	/* we'll need to get the data part. it may contain
	   more abstracts, they are _NOT_ expanded. */
	data = theme_format_expand_get(theme, formatp);
	len = strlen(data);

	if (len > 1 && i_isdigit(data[len-1]) && data[len-2] == '$') {
		/* ends with $<digit> .. this breaks things if next
		   character is digit or '-' */
                char digit, *tmp;

		tmp = data;
		digit = tmp[len-1];
		tmp[len-1] = '\0';

		data = g_strdup_printf("%s{%c}", tmp, digit);
		g_free(tmp);
	}

	ret = parse_special_string(abstract, NULL, NULL, data, NULL,
				   PARSE_FLAG_ONLY_ARGS);
	g_free(abstract);
        g_free(data);
	str = g_string_new(NULL);
	p = ret;
	while (*p != '\0') {
		if (*p == '\\') {
			int chr;
			p++;
			chr = expand_escape(&p);
			g_string_append_c(str, chr != -1 ? chr : *p);
		} else
			g_string_append_c(str, *p);
		p++;
	}
	g_free(ret);
	abstract = str->str;
	g_string_free(str, FALSE);

	/* abstract may itself contain abstracts or replaces */
	p = abstract;
	ret = theme_format_expand_data(theme, &p, default_fg, default_bg,
				       &default_fg, &default_bg,
				       flags | EXPAND_FLAG_LASTCOLOR_ARG);
	g_free(abstract);
	return ret;
}
Beispiel #19
0
static bool
message_date_parser_tokens(struct message_date_parser_context *ctx,
			   time_t *timestamp_r, int *timezone_offset_r)
{
	struct tm tm;
	const unsigned char *value;
	size_t i, len;
	int ret;

	/* [weekday_name "," ] dd month_name [yy]yy hh:mi[:ss] timezone */
	memset(&tm, 0, sizeof(tm));

        rfc822_skip_lwsp(&ctx->parser);

	/* skip the optional weekday */
	if (next_token(ctx, &value, &len) <= 0)
		return FALSE;
	if (len == 3) {
		if (*ctx->parser.data != ',')
			return FALSE;
		ctx->parser.data++;
		rfc822_skip_lwsp(&ctx->parser);

		if (next_token(ctx, &value, &len) <= 0)
			return FALSE;
	}

	/* dd */
	if (len < 1 || len > 2 || !i_isdigit(value[0]))
		return FALSE;

	tm.tm_mday = value[0]-'0';
	if (len == 2) {
		if (!i_isdigit(value[1]))
			return FALSE;
		tm.tm_mday = (tm.tm_mday * 10) + (value[1]-'0');
	}

	/* month name */
	if (next_token(ctx, &value, &len) <= 0 || len < 3)
		return FALSE;

	for (i = 0; i < 12; i++) {
		if (i_memcasecmp(month_names[i], value, 3) == 0) {
			tm.tm_mon = i;
			break;
		}
	}
	if (i == 12)
		return FALSE;

	/* [yy]yy */
	if (next_token(ctx, &value, &len) <= 0 || (len != 2 && len != 4))
		return FALSE;

	for (i = 0; i < len; i++) {
		if (!i_isdigit(value[i]))
			return FALSE;
		tm.tm_year = tm.tm_year * 10 + (value[i]-'0');
	}

	if (len == 2) {
		/* two digit year, assume 1970+ */
		if (tm.tm_year < 70)
			tm.tm_year += 100;
	} else {
		if (tm.tm_year < 1900)
			return FALSE;
		tm.tm_year -= 1900;
	}

	/* hh, allow also single digit */
	if (next_token(ctx, &value, &len) <= 0 ||
	    len < 1 || len > 2 || !i_isdigit(value[0]))
		return FALSE;
	tm.tm_hour = value[0]-'0';
	if (len == 2) {
		if (!i_isdigit(value[1]))
			return FALSE;
		tm.tm_hour = tm.tm_hour * 10 + (value[1]-'0');
	}

	/* :mm (may be the last token) */
	if (!IS_TIME_SEP(*ctx->parser.data))
		return FALSE;
	ctx->parser.data++;
	rfc822_skip_lwsp(&ctx->parser);

	if (next_token(ctx, &value, &len) < 0 || len != 2 ||
	    !i_isdigit(value[0]) || !i_isdigit(value[1]))
		return FALSE;
	tm.tm_min = (value[0]-'0') * 10 + (value[1]-'0');

	/* [:ss] */
	if (ctx->parser.data != ctx->parser.end &&
	    IS_TIME_SEP(*ctx->parser.data)) {
		ctx->parser.data++;
		rfc822_skip_lwsp(&ctx->parser);

		if (next_token(ctx, &value, &len) <= 0 || len != 2 ||
		    !i_isdigit(value[0]) || !i_isdigit(value[1]))
			return FALSE;
		tm.tm_sec = (value[0]-'0') * 10 + (value[1]-'0');
	}

	if ((ret = next_token(ctx, &value, &len)) < 0)
		return FALSE;
	if (ret == 0) {
		/* missing timezone */
		*timezone_offset_r = 0;
	} else {
		/* timezone */
		*timezone_offset_r = parse_timezone(value, len);
	}

	tm.tm_isdst = -1;
	*timestamp_r = utc_mktime(&tm);
	if (*timestamp_r == (time_t)-1)
		return FALSE;

	*timestamp_r -= *timezone_offset_r * 60;

	return TRUE;
}
Beispiel #20
0
int mbox_from_parse(const unsigned char *msg, size_t size,
		    time_t *time_r, int *tz_offset_r, char **sender_r)
{
	const unsigned char *msg_start, *sender_end, *msg_end;
	struct tm tm;
	int esc, alt_stamp, timezone_secs = 0, seen_timezone = FALSE;
	time_t t;

	*time_r = (time_t)-1;
	*sender_r = NULL;

	/* <sender> <date> <moreinfo> */
	msg_start = msg;
	msg_end = msg + size;

	/* get sender */
	if (msg < msg_end && *msg == '"') {
		/* "x y z"@domain - skip the quoted part */
		esc = FALSE;
		msg++;
		while (msg < msg_end && (*msg != '"' || esc)) {
			if (*msg == '\r' || *msg == '\n')
				return -1;
			esc = *msg == '\\';
			msg++;
		}
		msg++;
	} 

	while (msg < msg_end && *msg != ' ') {
		if (*msg == '\r' || *msg == '\n')
			return -1;
		msg++;
	}
	sender_end = msg;
	while (msg < msg_end && *msg == ' ') msg++;

	/* next 29 chars should be in the date in asctime() format, eg.
	   "Thu Nov  9 22:33:52 2001 +0300"

	   - Some put the timezone before the year
	   - Some use a named timezone before or after year, which we ignore
	   - Some don't include seconds (-3)
	   - Some don't include timezone (-5)
	*/
	if (msg+29-3-5 > msg_end)
		return -1;

	memset(&tm, 0, sizeof(tm));

	/* skip weekday */
	msg += 4;

	/* month */
	if (mbox_parse_month(msg, &tm) < 0) {
		/* Try alternate timestamp: "Thu, 9 Nov 2002 22:33:52" */
		alt_stamp = TRUE;
		msg++;

		if (!i_isdigit(msg[0]))
			return -1;
		tm.tm_mday = msg[0]-'0';
		msg++;

		if (i_isdigit(msg[0])) {
			tm.tm_mday = tm.tm_mday*10 + msg[0]-'0';
			msg++;
		}
		if (msg[0] != ' ')
			return -1;
		msg++;

		if (mbox_parse_month(msg, &tm) < 0)
			return -1;
		msg += 4;

		if (mbox_parse_year(msg, &tm) < 0)
			return -1;
		msg += 5;
	} else {
		alt_stamp = FALSE;
		msg += 4;

		/* day. single digit is usually preceded by extra space */
		if (msg[0] == ' ')
			msg++;
		if (msg[1] == ' ') {
			if (!i_isdigit(msg[0]))
				return -1;
			tm.tm_mday = msg[0]-'0';
			msg += 2;
		} else {
			if (!i_isdigit(msg[0]) || !i_isdigit(msg[1]) || msg[2] != ' ')
				return -1;
			tm.tm_mday = (msg[0]-'0') * 10 + (msg[1]-'0');
			msg += 3;
		}
	}
	if (tm.tm_mday == 0)
		tm.tm_mday = 1;

	/* hour */
	if (!i_isdigit(msg[0]) || !i_isdigit(msg[1]) || msg[2] != ':')
		return -1;
	tm.tm_hour = (msg[0]-'0') * 10 + (msg[1]-'0');
	msg += 3;

	/* minute */
	if (!i_isdigit(msg[0]) || !i_isdigit(msg[1]))
		return -1;
	tm.tm_min = (msg[0]-'0') * 10 + (msg[1]-'0');
	msg += 2;

	/* optional second */
	if (msg[0] == ':') {
		msg++;
		if (!i_isdigit(msg[0]) || !i_isdigit(msg[1]))
			return -1;
		tm.tm_sec = (msg[0]-'0') * 10 + (msg[1]-'0');
		msg += 2;

		if (!alt_stamp) {
			if (msg[0] == ' ')
				msg++;
			else
				return -1;
		}
	} else if (!alt_stamp) {
		if (msg[0] != ' ')
			return -1;
		msg++;
	}

	/* optional named timezone */
	if (alt_stamp)
		;
	else if (!i_isdigit(msg[0]) || !i_isdigit(msg[1]) ||
		 !i_isdigit(msg[2]) || !i_isdigit(msg[3])) {
		/* skip to next space */
		while (msg < msg_end && *msg != ' ') {
			if (*msg == '\r' || *msg == '\n')
				return -1;
			msg++;
		}
		if (msg+5 > msg_end)
			return -1;
		msg++;
	} else if ((msg[0] == '-' || msg[0] == '+') &&
		   i_isdigit(msg[1]) && i_isdigit(msg[2]) &&
		   i_isdigit(msg[3]) && i_isdigit(msg[4]) && msg[5] == ' ') {
		/* numeric timezone, use it */
                seen_timezone = TRUE;
		timezone_secs = (msg[1]-'0') * 10*60*60 + (msg[2]-'0') * 60*60 +
			(msg[3]-'0') * 10 + (msg[4]-'0');
		if (msg[0] == '-') timezone_secs = -timezone_secs;
		msg += 6;
	}

	if (!alt_stamp) {
		/* year */
		if (mbox_parse_year(msg, &tm) < 0)
			return -1;
		msg += 4;
	}

	tm.tm_isdst = -1;
	if (!seen_timezone && msg != msg_end &&
	    msg[0] == ' ' && (msg[1] == '-' || msg[1] == '+') &&
	    i_isdigit(msg[2]) && i_isdigit(msg[3]) &&
	    i_isdigit(msg[4]) && i_isdigit(msg[5])) {
		seen_timezone = TRUE;
		timezone_secs = (msg[2]-'0') * 10*60*60 + (msg[3]-'0') * 60*60 +
			(msg[4]-'0') * 10 + (msg[5]-'0');
		if (msg[1] == '-') timezone_secs = -timezone_secs;
	}

	if (seen_timezone) {
		t = utc_mktime(&tm);
		if (t == (time_t)-1)
			return -1;

		t -= timezone_secs;
		*time_r = t;
		*tz_offset_r = timezone_secs/60;
	} else {
		/* assume local timezone */
		*time_r = mktime(&tm);
		*tz_offset_r = utc_offset(localtime(time_r), *time_r);
	}

	*sender_r = i_strdup_until(msg_start, sender_end);
	return 0;
}
Beispiel #21
0
static int parse_timezone(const unsigned char *str, size_t len)
{
	int offset;
	char chr;

	if (len == 5 && (*str == '+' || *str == '-')) {
		/* numeric offset */
		if (!i_isdigit(str[1]) || !i_isdigit(str[2]) ||
		    !i_isdigit(str[3]) || !i_isdigit(str[4]))
			return FALSE;

		offset = ((str[1]-'0') * 10 + (str[2]-'0')) * 60  +
			(str[3]-'0') * 10 + (str[4]-'0');
		return *str == '+' ? offset : -offset;
	}

	if (len == 1) {
		/* military zone - handle them the correct way, not as
		   RFC822 says. RFC2822 though suggests that they'd be
		   considered as unspecified.. */
		chr = i_toupper(*str);
		if (chr < 'J')
			return (*str-'A'+1) * 60;
		if (chr == 'J')
			return 0;
		if (chr <= 'M')
			return (*str-'A') * 60;
		if (chr < 'Z')
			return ('M'-*str) * 60;
		return 0;
	}

	if (len == 2 && i_toupper(str[0]) == 'U' && i_toupper(str[1]) == 'T') {
		/* UT - Universal Time */
		return 0;
	}

	if (len == 3) {
		/* GMT | [ECMP][DS]T */
		if (str[2] != 'T')
			return 0;

		switch (i_toupper(*str)) {
		case 'E':
			offset = -5 * 60;
			break;
		case 'C':
			offset = -6 * 60;
			break;
		case 'M':
			offset = -7 * 60;
			break;
		case 'P':
			offset = -8 * 60;
			break;
		default:
			/* GMT and others */
			return 0;
		}

		if (i_toupper(str[1]) == 'D')
			return offset + 60;
		if (i_toupper(str[1]) == 'S')
			return offset;
	}

	return 0;
}