Mercurial > dovecot > original-hg > dovecot-1.2
view src/lib-index/mbox/mbox-append.c @ 10:82b7de533f98 HEAD
s/user_data/context/ and some s/Data/Context/
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Thu, 22 Aug 2002 15:48:38 +0300 |
parents | 1b34ec11fff8 |
children | a946ce1f09b7 |
line wrap: on
line source
/* Copyright (C) 2002 Timo Sirainen */ #include "lib.h" #include "mmap-util.h" #include "ioloop.h" #include "mbox-index.h" #include "mail-index-util.h" #include <time.h> #include <ctype.h> #include <unistd.h> #include <sys/mman.h> static const char *months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; static MailIndexRecord * mail_index_record_append(MailIndex *index, time_t internal_date, size_t full_virtual_size) { MailIndexRecord trec, *rec; memset(&trec, 0, sizeof(MailIndexRecord)); trec.internal_date = internal_date; trec.full_virtual_size = full_virtual_size; rec = &trec; if (!index->append(index, &rec)) return NULL; return rec; } static time_t from_line_parse_date(const char *msg, size_t size) { const char *msg_end; struct tm tm; int i; /* From <sender> <date> <moreinfo> */ if (strncmp(msg, "From ", 5) != 0) return 0; msg_end = msg + size; /* skip sender */ msg += 5; while (*msg != ' ' && msg < msg_end) msg++; while (*msg == ' ' && msg < msg_end) msg++; /* next 24 chars are the date in asctime() format, eg. "Thu Nov 29 22:33:52 2001" */ if (msg+24 > msg_end) return 0; memset(&tm, 0, sizeof(tm)); /* skip weekday */ msg += 4; /* month */ for (i = 0; i < 12; i++) { if (strncasecmp(months[i], msg, 3) == 0) { tm.tm_mon = i; break; } } if (i == 12 || msg[3] != ' ') return 0; msg += 4; /* day */ if (!i_isdigit(msg[0]) || !i_isdigit(msg[1]) || msg[2] != ' ') return 0; tm.tm_mday = (msg[0]-'0') * 10 + (msg[1]-'0'); msg += 3; /* hour */ if (!i_isdigit(msg[0]) || !i_isdigit(msg[1]) || msg[2] != ':') return 0; tm.tm_hour = (msg[0]-'0') * 10 + (msg[1]-'0'); msg += 3; /* minute */ if (!i_isdigit(msg[0]) || !i_isdigit(msg[1]) || msg[2] != ':') return 0; tm.tm_min = (msg[0]-'0') * 10 + (msg[1]-'0'); msg += 3; /* second */ if (!i_isdigit(msg[0]) || !i_isdigit(msg[1]) || msg[2] != ' ') return 0; tm.tm_sec = (msg[0]-'0') * 10 + (msg[1]-'0'); msg += 3; /* year */ if (!i_isdigit(msg[0]) || !i_isdigit(msg[1]) || !i_isdigit(msg[2]) || !i_isdigit(msg[3])) return 0; tm.tm_year = (msg[0]-'0') * 1000 + (msg[1]-'0') * 100 + (msg[2]-'0') * 10 + (msg[3]-'0') - 1900; tm.tm_isdst = -1; return mktime(&tm); } static void header_func(MessagePart *part __attr_unused__, const char *name, unsigned int name_len, const char *value, unsigned int value_len, void *context) { MailIndexRecord *rec = context; rec->msg_flags |= mbox_header_get_flags(name, name_len, value, value_len); } static int mbox_index_append_data(MailIndex *index, const char *msg, off_t offset, size_t physical_size, size_t virtual_size) { MailIndexRecord *rec; MailIndexUpdate *update; time_t internal_date; char location[MAX_INT_STRLEN]; unsigned int i; internal_date = from_line_parse_date(msg, physical_size); if (internal_date <= 0) internal_date = ioloop_time; /* skip the From-line */ for (i = 0; i < physical_size; i++) { if (msg[i] == '\n') { i++; break; } } if (i == physical_size) return FALSE; msg += i; offset += i; physical_size -= i; virtual_size -= i; if (i > 0 && msg[i-1] != '\r') virtual_size--; rec = mail_index_record_append(index, internal_date, virtual_size); if (rec == NULL) return FALSE; update = index->update_begin(index, rec); /* location = offset to beginning of message */ i_snprintf(location, sizeof(location), "%lu", (unsigned long) offset); index->update_field(update, FIELD_TYPE_LOCATION, location, 0); /* parse the header and cache wanted fields */ mail_index_update_headers(update, msg, physical_size, header_func, rec); if (!index->update_end(update)) { /* failed - delete the record */ (void)index->expunge(index, rec, 0, FALSE); return FALSE; } return TRUE; } int mbox_index_append_mmaped(MailIndex *index, const char *data, size_t data_size, off_t start_offset) { const char *data_start, *data_end, *start, *cr; size_t size, vsize; off_t pos; int missing_cr_count; /* we should start with "From ". if we don't, something's messed up and we should check the whole file instead. */ if (strncmp(data, "From ", 5) != 0) { index->set_flags |= MAIL_INDEX_FLAG_FSCK; return FALSE; } /* each message ends at "\nFrom ". first get the size of the message, then parse it. calculate the missing CR count as well. */ start = data; cr = NULL; missing_cr_count = 0; data_start = data; data_end = data + data_size; for (; data != data_end; data++) { if (*data == '\r') cr = data; else if (*data == '\n') { if (cr != data-1) missing_cr_count++; if (data+6 < data_end && data[1] == 'F' && data[2] == 'r' && data[3] == 'o' && data[4] == 'm' && data[5] == ' ') { /* end of message */ pos = (off_t) (start - data_start) + start_offset; size = (size_t) (data - start) + 1; vsize = size + missing_cr_count; if (!mbox_index_append_data(index, start, pos, size, vsize)) return FALSE; missing_cr_count = 0; start = data+1; } } } /* last message */ pos = (off_t) (start - data_start); size = (size_t) (data - start); vsize = size + missing_cr_count; return mbox_index_append_data(index, start, pos, size, vsize); } int mbox_index_append(MailIndex *index, int fd, const char *path) { void *mmap_base; size_t mmap_length; off_t pos, end_pos; int ret; /* get our current position */ pos = lseek(fd, 0, SEEK_CUR); /* get the size of the file */ end_pos = lseek(fd, 0, SEEK_END); if (pos == -1 || end_pos == -1) { index_set_error(index, "lseek() failed with mbox file %s: %m", path); return FALSE; } if (pos == end_pos) { /* no new data */ return TRUE; } if (!index->set_lock(index, MAIL_LOCK_EXCLUSIVE)) return FALSE; /* mmap() the file */ mmap_length = end_pos-pos; mmap_base = mmap(NULL, mmap_length, PROT_READ, MAP_SHARED, fd, pos); if (mmap_base == MAP_FAILED) { index_set_error(index, "mmap() failed with mbox file %s: %m", path); return FALSE; } (void)madvise(mmap_base, mmap_length, MADV_SEQUENTIAL); ret = mbox_index_append_mmaped(index, mmap_base, mmap_length, pos); (void)munmap(mmap_base, mmap_length); return ret; }