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; }
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; }
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; }
/* 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; }
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; }
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; } }
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); }
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; }
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; }
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; }
/* 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); }
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; }
/* 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; }
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; }
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; }
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; }