static int writemmsdata(Octstr *ms, char *df, char subdir[], char *mms_queuedir) { Octstr *dfname; int fd, n, res = 0; dfname = octstr_format("%s/%s%s", mms_queuedir, subdir, df); fd = open(octstr_get_cstr(dfname), O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP); if (fd < 0) { error(0, "mms_queueadd: Failed to open data file %s: error = %s\n", octstr_get_cstr(dfname), strerror(errno)); res = -1; goto done; } n = octstr_write_to_socket(fd, ms); unlock_and_close(fd); if (n != 0) { error(0, "mms_queueadd: Failed to write data file %s: error = %s\n", octstr_get_cstr(dfname), strerror(errno)); unlink(octstr_get_cstr(dfname)); res = -1; } done: octstr_destroy(dfname); return res; }
static int free_envelope(MmsEnvelope *e, int removefromqueue) { struct qfile_t *qfs; if (e == NULL) return 0; qfs = e->qfs_data; if (removefromqueue) { /* Remove qf file */ char fname[2*QFNAMEMAX]; snprintf(fname, -1 + sizeof fname, "%s/%s%s", qfs->dir, qfs->subdir, qfs->name); debug("mms_queue.free_envelope",0,"free envelope: %s/%s%s", qfs->dir, qfs->subdir, qfs->name); unlink(fname); /* Remove df file */ qfs->name[0] = MDF; snprintf(fname, -1 + sizeof fname, "%s/%s%s", qfs->dir, qfs->subdir, qfs->name); debug("mms_queue.free_envelope",0,"free envelope: %s/%s%s", qfs->dir, qfs->subdir, qfs->name); unlink(fname); } unlock_and_close(qfs->fd); /* close and unlock now that we have deleted it. */ mms_queue_free_envelope(e); return 0; }
int mms_mmbox_count(char *mmbox_root, char *user, unsigned long *msgcount, unsigned long *byte_count) { int tmpfd = -1; FILE *fp = NULL; char linbuf[1024]; int ret = -1; Octstr *home = user_mmbox_dir(mmbox_root,user); int ifd = -1; ifd = open_mmbox_index(octstr_get_cstr(home),1); if (ifd < 0) goto done; if ((tmpfd = dup(ifd)) < 0 || (fp = fdopen(tmpfd, "r")) == NULL) { error(0, "mmbox.count: %s Failed to dup descriptor for index " "file, fp = %p: error = %s\n", octstr_get_cstr(home), fp, strerror(errno)); goto done; } *msgcount = 0; *byte_count = 0; while (fgets(linbuf, sizeof linbuf, fp) != NULL) { int size = 0; sscanf(linbuf, "%*s %*s %d", &size); ++*msgcount; *byte_count = *byte_count + size; } ret = 0; done: if (fp) unlock_and_fclose(fp); else if (tmpfd) unlock_and_close(tmpfd); if (ifd > 0) unlock_and_close(ifd); return ret; }
int mms_mmbox_delmsg(char *mmbox_root, char *user, Octstr *msgref) { Octstr *sdf = octstr_duplicate(msgref); Octstr *fname = NULL, *home = user_mmbox_dir(mmbox_root,user); Octstr *s = NULL; int res = -1; int ifd = -1, nifd; octstr_replace(sdf, octstr_imm("-"), octstr_imm("/")); if (!home) goto done; ifd = open_mmbox_index(octstr_get_cstr(home),1); if (ifd < 0) goto done; fname = octstr_format("%S/%S", home, sdf); if ((nifd = update_mmbox_index(ifd, octstr_get_cstr(home), ITEM_DEL, sdf, NULL, NULL,0)) < 0) { error(0, "mmbox.del: failed to update index file, home is %s!", octstr_get_cstr(home)); goto done; } unlink(octstr_get_cstr(fname)); ifd = nifd; res = 0; done: if (ifd > 0) unlock_and_close(ifd); if (fname) octstr_destroy(fname); if (s) octstr_destroy(s); if (home) octstr_destroy(home); return 0; }
MmsMsg *mms_mmbox_get(char *mmbox_root, char *user, Octstr *msgref, unsigned long *msize) { Octstr *sdf = octstr_duplicate(msgref); Octstr *fname = NULL, *home = user_mmbox_dir(mmbox_root,user); Octstr *s = NULL; int ifd = -1; MmsMsg *m = NULL; octstr_replace(sdf, octstr_imm("-"), octstr_imm("/")); if (!home) goto done; ifd = open_mmbox_index(octstr_get_cstr(home),1); /* Grab a lock on the index file. */ if (ifd < 0) goto done; fname = octstr_format("%S/%S", home, sdf); s = octstr_read_file(octstr_get_cstr(fname)); if (s) { if (msize) *msize = octstr_len(s); m = mms_frombinary(s, octstr_imm("anon@anon")); } else if (msize) *msize = 0; done: if (ifd > 0) unlock_and_close(ifd); if (fname) octstr_destroy(fname); if (s) octstr_destroy(s); if (home) octstr_destroy(home); return m; }
/* * To prevent after board packed, and others did not update their list. * The ent could be wrong, and the user might update the wrong .DIR entry. */ int safely_read_dir(const char *direct, int opened_fd, int ent, const FILEHEADER *ofhr, FILEHEADER *nfhr) { int fd, rtval = -1; if (opened_fd) fd = opened_fd; else fd = open_and_lock(direct); if (fd == -1) goto err_out; if (get_record_byfd(fd, nfhr, FH_SIZE, ent) == -1) goto out; if (nfhr->postno == ofhr->postno && !strcmp(nfhr->title, ofhr->title)) { /* * The ent position should be correct, * if postno and the title is the same. */ if (!(ofhr->accessed & FILE_DELE) && nfhr->accessed & FILE_DELE) goto out; rtval = 0; goto out; } /* * Search for correct record if still there. * This could spend some CPU/DISK time. */ /* * FIXME: Just returning error for now. */ out: if (!opened_fd) unlock_and_close(fd); err_out: return rtval; }
static int open_mmbox_index(char *mmbox_dir, int shouldblock) { char fbuf[256]; int i, fd; sprintf(fbuf, "%s/%s", mmbox_dir, IDXFILE); i = 0; do if ((fd = open(fbuf, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP)) < 0) { error(0, "Failed to open mmbox index file [%s], error: %s!", fbuf, strerror(errno)); break; } else if (mm_lockfile(fd, fbuf, shouldblock) != 0) { unlock_and_close(fd); fd = -1; } while (i++ < MAXTRIES && fd < 0); return fd; }
/* * To prevent after board packed, and others did not update their list. * The ent could be wrong, and the user might update the wrong .DIR entry. */ int safely_substitute_dir(const char *direct, int opened_fd, int ent, const FILEHEADER *ofhr, FILEHEADER *nfhr, unsigned char mark_unread) { int fd, rtval = -1; FILEHEADER tfhr; if (opened_fd) fd = opened_fd; else fd = open_and_lock(direct); if (fd == -1) goto err_out; if (safely_read_dir(NULL, fd, ent, ofhr, &tfhr)) goto out; if (mark_unread) { nfhr->mtime = time(NULL); get_only_postno(direct, fd, nfhr); } if (substitute_record_byfd(fd, nfhr, FH_SIZE, ent)) goto out; rtval = 0; /* * Search for correct record if still there. * This could spend some CPU/DISK time. */ /* * FIXME: Just returning error for now. */ out: if (!opened_fd) unlock_and_close(fd); err_out: return rtval; }
/* Makes a qf file in the queue directory. * Makes several attempts then fails (returns -1) if it can't, fd otherwise * puts queue file name in qf (without directory name). * It is up to the caller to lock the file descriptor if needed. */ static int mkqf(char qf[QFNAMEMAX], char subdir[64], char *mms_queuedir) { Octstr *xqf = NULL; char *ctmp; int i = 0, fd = -1; static int ect; if (!mms_queuedir) gw_panic(0, "Queue directory passed as null!"); /* First we decide the directory into which it goes... */ if ((i = random() % 3) == 0) /* toplevel. */ subdir[0] = 0; else if (i == 1) /* one in */ sprintf(subdir, "%c/", _TT[random() % _TTSIZE]); else { /* two in. */ char csubdir[QFNAMEMAX]; sprintf(subdir, "%c/%c%c/", _TT[random() % _TTSIZE], _TT[random() % _TTSIZE], _TT[random() % _TTSIZE]); sprintf(csubdir, "%s/%s", mms_queuedir, subdir); if (mkdir(csubdir, S_IRWXU|S_IRWXG) < 0 && errno != EEXIST) { error(0, "make queue file: Failed to create dir %s - %s!", csubdir, strerror(errno)); return -1; } } do { Octstr *tmp; xqf = octstr_format("%cf%ld.%d.x%d.%ld", MQF, (long)time(NULL) % 10000, (++ect % 10000), getpid()%1000, random() % 100); tmp = octstr_format("%.64s/%s%S", mms_queuedir, subdir, xqf); ctmp = octstr_get_cstr(tmp); fd = open(ctmp, O_RDWR|O_CREAT|O_EXCL, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP); if (fd >= 0 && mm_lockfile(fd,ctmp,1) != 0) { unlink(ctmp); unlock_and_close(fd); fd = -1; } octstr_destroy(tmp); if (fd >= 0) break; octstr_destroy(xqf); xqf = NULL; } while (i++ < MAXTRIES); if (fd >= 0) strncpy(qf, octstr_get_cstr(xqf), QFNAMEMAX); if (xqf) octstr_destroy(xqf); return fd; }
/* * Attempt to read an envelope from queue file: * - opens and locks the file. * - if the lock succeeds, check that file hasn't changed since opening. If it has * return NULL (i.e. file is being processed elsewhere -- race condition), otherwise read it. * - If should block is 1, then does a potentially blocking attempt to lock the file. */ static MmsEnvelope *mms_queue_readenvelope(char *qf, char *mms_queuedir, int shouldblock) { Octstr *fname; int fd; Octstr *qdata, *s; ParseContext *p; MmsEnvelope *e; int okfile = 0; char subdir[64]; char realqf[QFNAMEMAX]; char xqf[QFNAMEMAX+64]; struct qfile_t *qfs; get_subdir(qf, subdir, realqf); /* break it down... */ fname = octstr_format( "%.128s/%s%s", mms_queuedir, subdir, realqf); strncpy(xqf, octstr_get_cstr(fname), sizeof xqf); #ifdef SunOS if ((fd = open(octstr_get_cstr(fname), O_RDWR)) < 0) { #else if ((fd = open(octstr_get_cstr(fname), O_RDONLY)) < 0) { #endif debug("",0,"mms_queue_readenvelope: could not open file %s", octstr_get_cstr(fname)); octstr_destroy(fname); return NULL; } else if (mm_lockfile(fd, octstr_get_cstr(fname), shouldblock) != 0) { debug("",0,"mms_queue_readenvelope: could not lock file %s", octstr_get_cstr(fname)); unlock_and_close(fd); octstr_destroy(fname); return NULL; } debug("",0,"locked and opened file: %s", octstr_get_cstr(fname)); e = mms_queue_create_envelope(NULL, NULL, NULL, NULL, NULL, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, qf, NULL, sizeof (struct qfile_t), NULL); qfs = e->qfs_data; qfs->fd = fd; strncpy(qfs->name, realqf, sizeof qfs->name); strncpy(qfs->subdir, subdir, sizeof qfs->subdir); strncpy(qfs->dir, mms_queuedir, sizeof qfs->dir); qdata = octstr_read_file(octstr_get_cstr(fname)); octstr_destroy(fname); if (qdata == NULL) qdata = octstr_imm(""); p = parse_context_create(qdata); for (s = parse_get_line(p); s; s = parse_get_line(p)) { char *line = octstr_get_cstr(s); int ch = line[0]; char *res = line + 1; char *ptmp; switch (ch) { Octstr *t; MmsEnvelopeTo *to; case 'T': t = octstr_create(res); e->msgtype = mms_string_to_message_type(t); octstr_destroy(t); if (e->msgtype < 0) { e->msgtype = 0; error(0, "mms_queueread: Unknown MMS message type (%s) in file %s, skipped!\n", res, xqf); } break; case 'I': e->msgId = octstr_create(res); break; case 'i': strncpy(e->src_interface, res, sizeof e->src_interface); break; case 'F': e->from = octstr_create(res); if (mms_validate_address(e->from) != 0) { warning(0, "mms_queueread: Mal-formed address [%s] in file %s! " "Attempting fixup.", res, xqf); _mms_fixup_address(&e->from, NULL, NULL, 1); } break; case 'R': t = octstr_create(res); if (mms_validate_address(t) != 0) { warning(0, "mms_queueread: Mal-formed address [%s] in file %s! " "Attempting fixup.", res, xqf); _mms_fixup_address(&t, NULL, NULL, 1); } to = gw_malloc(sizeof *to); to->rcpt = t; to->process = 1; gwlist_append(e->to, to); break; case 'C': e->created = atol(res); break; case 'L': e->lasttry = atol(res); break; case 'D': e->sendt = atol(res); break; case 'X': e->expiryt = atol(res); break; case 'N': e->attempts = atol(res); break; case 'P': e->fromproxy = octstr_create(res); break; case 'M': e->mdata = octstr_create(res); break; case 'p': e->viaproxy = octstr_create(res); break; case 'S': e->msize = atol(res); break; case 's': e->subject = octstr_create(res); break; case 't': e->token = octstr_create(res); break; case 'f': e->lastaccess = atol(res); break; case 'b': e->bill.billed = 1; e->bill.amt = atof(res); break; case 'r': e->dlr = 1; break; case 'V': e->vaspid = octstr_create(res); break; case 'v': e->vasid = octstr_create(res); break; case 'U': e->url1 = octstr_create(res); break; case 'u': e->url2 = octstr_create(res); break; case 'H': if (e->hdrs == NULL) e->hdrs = http_create_empty_headers(); if ((ptmp = index(res, ':')) == NULL) error(0, "Incorrectly formatted line %s in queue file %s!", line, xqf); else { char *value = ptmp + 1; char hname[512]; int xlen = (ptmp - res < sizeof hname) ? ptmp - res : -1 + sizeof hname; strncpy(hname, res, xlen); hname[xlen] = 0; /* terminate it. */ http_header_add(e->hdrs, hname, value); } break; case '.': okfile = 1; break; default: error(0, "Unknown QF header %c in file %s!", ch, xqf); break; } octstr_destroy(s); if (okfile) break; /* We are done. */ } parse_context_destroy(p); octstr_destroy(qdata); /* We should properly validate the queue file here. */ if (!okfile) { free_envelope(e,0); e = NULL; error(0, "Corrupt queue control file: %s", xqf); } return e; } /* Updates envelope to queue file: * - opens temp file * - writes output to temp file, if not new else writes directly. * - renames temp file to queue file (if not new) * This function doesn't check that this envelope is useless (i.e. no recipients) * - If function returns -1, caller should check errno for error. */ static int writeenvelope(MmsEnvelope *e, int newenv) { Octstr *tfname = NULL; char *s; char buf[512]; int fd; int i, n; int res = 0; struct qfile_t *qfs = e ? e->qfs_data : NULL; gw_assert(e); if (newenv) fd = qfs->fd; else { tfname = octstr_format( "%s/%s%c%s.%d", qfs->dir, qfs->subdir, MTF, qfs->name + 1, random()); fd = open(octstr_get_cstr(tfname), O_RDWR|O_CREAT|O_EXCL, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP); if (fd < 0 ) { error(0, "mms_queueadd: Failed to open temp file %s: error = %s\n", octstr_get_cstr(tfname), strerror(errno)); res = -1; goto done; } else if (mm_lockfile(fd, octstr_get_cstr(tfname), 0) != 0) { /* Lock it. */ error(0, "mms_queueadd: Failed lock temp file %s: error = %s\n", octstr_get_cstr(tfname), strerror(errno)); res = -1; goto done; } } /* Write out. */ s = (char *)mms_message_type_to_cstr(e->msgtype); if (!s) { error(0, "mms_queuewrite: Unknown MMS message type %d! Skipped\n", e->msgtype); s = ""; } _putline(fd, "T", s); if (e->msgId) _putline(fd, "I", octstr_get_cstr(e->msgId)); if (e->src_interface[0]) _putline(fd, "i", e->src_interface); if (e->from) _putline(fd, "F", octstr_get_cstr(e->from)); if (e->to) n = gwlist_len(e->to); else n = 0; for (i = 0; i < n; i++) { MmsEnvelopeTo *to = gwlist_get(e->to, i); if (to->process) _putline(fd, "R", octstr_get_cstr(to->rcpt)); } /* Output headers if any. */ n = (e->hdrs) ? gwlist_len(e->hdrs) : 0; for (i = 0; i < n; i++) { Octstr *h = NULL, *v = NULL; http_header_get(e->hdrs, i, &h, &v); if (h && v) { Octstr *x = octstr_format("%s:%s", octstr_get_cstr(h), octstr_get_cstr(v)); _putline(fd, "H", octstr_get_cstr(x)); octstr_destroy(x); } if (h) octstr_destroy(h); if (v) octstr_destroy(v); } sprintf(buf, "%ld", e->created); _putline(fd, "C", buf); if (e->lasttry) { sprintf(buf, "%ld", e->lasttry); _putline(fd, "L", buf); } if (e->sendt) { sprintf(buf, "%ld", e->sendt); _putline(fd, "D", buf); } if (e->expiryt) { sprintf(buf, "%ld", e->expiryt); _putline(fd, "X", buf); } if (e->attempts) { sprintf(buf, "%ld", e->attempts); _putline(fd, "N", buf); } if (e->lastaccess) { sprintf(buf, "%ld", e->lastaccess); _putline(fd, "f", buf); } sprintf(buf, "%ld", e->msize); _putline(fd, "S", buf); if (e->fromproxy) _putline(fd, "P", octstr_get_cstr(e->fromproxy)); if (e->mdata) _putline(fd, "M", octstr_get_cstr(e->mdata)); if (e->subject) _putline(fd, "s", octstr_get_cstr(e->subject)); if (e->viaproxy) _putline(fd, "p", octstr_get_cstr(e->viaproxy)); if (e->token) _putline(fd, "t", octstr_get_cstr(e->token)); if (e->vaspid) _putline(fd, "V", octstr_get_cstr(e->vaspid)); if (e->vasid) _putline(fd, "v", octstr_get_cstr(e->vasid)); if (e->url1) _putline(fd, "U", octstr_get_cstr(e->url1)); if (e->url2) _putline(fd, "u", octstr_get_cstr(e->url2)); if (e->dlr) _putline(fd, "r", "Yes"); if (e->bill.billed) { sprintf(buf, "%.3f", e->bill.amt); _putline(fd,"b", buf); } _putline(fd, "", "."); fsync(fd); /* Sync data. */ if (!newenv) { /* An update */ Octstr *qfname; qfname = octstr_format("%s/%s%s", qfs->dir, qfs->subdir, qfs->name); if (rename(octstr_get_cstr(tfname), octstr_get_cstr(qfname)) < 0) { error(0, "mms_queuewrite: Failed to rename %s to %s: error = %s\n", octstr_get_cstr(qfname), octstr_get_cstr(tfname), strerror(errno)); unlock_and_close(fd); /* Close new one, keep old one. */ res = -1; } else { /* On success, new descriptor replaces old one and we close old one. */ unlock_and_close(qfs->fd); qfs->fd = fd; } octstr_destroy(qfname); } done: octstr_destroy(tfname); return res; }
List *mms_mmbox_search(char *mmbox_root, char *user, List *state, List *flag_cmds, int start, int limit, List *msgrefs) { int tmpfd = -1; FILE *fp = NULL; char linbuf[1024]; Octstr *home = user_mmbox_dir(mmbox_root,user); List *flags = NULL; List *dflist = NULL; int ifd = -1; int ct; ifd = open_mmbox_index(octstr_get_cstr(home),1); if (ifd < 0) goto done; if ((tmpfd = dup(ifd)) < 0 || (fp = fdopen(tmpfd, "r")) == NULL) { error(0, "mmbox.search_index: %s Failed to dup descriptor for index " "file, fp = %p: error = %s\n", octstr_get_cstr(home), fp, strerror(errno)); goto done; } flags = make_mm_flags(NULL, flag_cmds); ct = 1; dflist = gwlist_create(); while (fgets(linbuf, sizeof linbuf, fp) != NULL) { char idx[128], xstate[32]; List *xflags = NULL; int i, size; int match = (!state && (!msgrefs || gwlist_len(msgrefs) == 0) && (!xflags || gwlist_len(xflags) == 0)); sscanf(linbuf, "%s %s %d%n", idx, xstate, &size, &i); /* search: by id list if given, by states if given, by flags if given */ if (!match && state && gwlist_search(state, xstate, (gwlist_item_matches_t *)_x_octstr_str_compare) != NULL) match = 1; /* For the rest we only match if nothing else matched. Save time */ replace_slash(idx); if (!match && msgrefs && gwlist_search(msgrefs, idx, (gwlist_item_matches_t *)_x_octstr_str_compare) != NULL) match = 1; if (!match && flag_cmds && ((xflags = parse_string_list(linbuf + i)) != NULL && gwlist_search(xflags, flags, (gwlist_item_matches_t *)string_in_list) != NULL)) match = 1; if (match && ct >= start && gwlist_len(dflist) <= limit) { Octstr *x = octstr_create(idx); /* octstr_replace(x, octstr_imm("/"), octstr_imm("-")); */ gwlist_append(dflist, x); } ct++; if (xflags) gwlist_destroy(xflags, (gwlist_item_destructor_t *)octstr_destroy); } done: if (fp) unlock_and_fclose(fp); else if (tmpfd) unlock_and_close(tmpfd); if (ifd > 0) unlock_and_close(ifd); if (flags) gwlist_destroy(flags, (gwlist_item_destructor_t *)octstr_destroy); if (home) octstr_destroy(home); return dflist; }
int mms_mmbox_modmsg(char *mmbox_root, char *user, Octstr *msgref, Octstr *state, List *flag_cmds) { Octstr *sdf = octstr_duplicate(msgref); Octstr *fname = NULL, *ftmp = NULL; Octstr *home = user_mmbox_dir(mmbox_root,user); Octstr *s = NULL; List *flags = NULL; Octstr *nstate = NULL; int ifd = -1, nifd, tmpfd = -1; MmsMsg *m = NULL; int res = -1; int msize; octstr_replace(sdf, octstr_imm("-"), octstr_imm("/")); if (!home) goto done; ifd = open_mmbox_index(octstr_get_cstr(home),1); if (ifd < 0) goto done; fname = octstr_format("%S/%S", home, sdf); s = octstr_read_file(octstr_get_cstr(fname)); if ( s == NULL || octstr_len(s) == 0) { error(0, "mmbox.mod: failed to read data file [%s] - %s!", octstr_get_cstr(fname), strerror(errno)); goto done; } m = mms_frombinary(s, octstr_imm("anon@anon")); if (!m) { error(0, "mmbox.mod: failed to read data file [%s]!", octstr_get_cstr(fname)); goto done; } if (state == NULL) nstate = mms_get_header_value(m, octstr_imm("X-Mms-MM-State")); else { nstate = octstr_duplicate(state); mms_replace_header_value(m, "X-Mms-MM-State", octstr_get_cstr(nstate)); } flags = mms_get_header_values(m, octstr_imm("X-Mms-MM-Flags")); flags = make_mm_flags(flags, flag_cmds); mms_replace_header_values(m, "X-Mms-MM-Flags", flags); ftmp = octstr_format("%S.%ld.%d", fname, time(NULL), getpid()); tmpfd = open(octstr_get_cstr(ftmp), O_RDWR|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP); if (tmpfd < 0) goto done; s = mms_tobinary(m); msize = octstr_len(s); octstr_write_to_socket(tmpfd, s); rename(octstr_get_cstr(ftmp), octstr_get_cstr(fname)); unlock_and_close(tmpfd); if ((nifd = update_mmbox_index(ifd, octstr_get_cstr(home), ITEM_MOD, sdf, nstate, flags, msize)) < 0) { /* Not good, we wrote but could not update the index file. scream. */ error(0, "mmbox.mod: failed to update index file, home is %s!", octstr_get_cstr(home)); goto done; } ifd = nifd; res = 0; done: if (ifd > 0) unlock_and_close(ifd); if (fname) octstr_destroy(fname); if (ftmp) octstr_destroy(ftmp); if (sdf) octstr_destroy(sdf); if (s) octstr_destroy(s); if (home) octstr_destroy(home); if (nstate) octstr_destroy(nstate); if (flags) gwlist_destroy(flags, (gwlist_item_destructor_t *)octstr_destroy); if (m) mms_destroy(m); return res; }
Octstr *mms_mmbox_addmsg(char *mmbox_root, char *user, MmsMsg *msg, List *flag_cmds, Octstr *dfltstate) { int ifd = -1, nifd, dfd = -1; char df[128]; Octstr *home = user_mmbox_dir(mmbox_root,user); Octstr *s = octstr_create(""), *sdf = NULL; List *flags = NULL; Octstr *state = NULL; int msize; if (!home) goto done; ifd = open_mmbox_index(octstr_get_cstr(home),1); if (ifd < 0) goto done; if ((dfd = mkdf(df, octstr_get_cstr(home))) < 0) { error(0, "mmbox_add: failed to create data file, home=%s - %s!", octstr_get_cstr(home), strerror(errno)); goto done; } state = mms_get_header_value(msg, octstr_imm("X-Mms-MM-State")); flags = make_mm_flags(mms_get_header_values(msg, octstr_imm("X-Mms-MM-Flags")), flag_cmds); if (state == NULL) state = dfltstate ? octstr_duplicate(dfltstate) : octstr_create("Sent"); mms_replace_header_values(msg, "X-Mms-MM-Flags", flags); mms_replace_header_value(msg, "X-Mms-MM-State", octstr_get_cstr(state)); s = mms_tobinary(msg); msize = octstr_len(s); octstr_write_to_socket(dfd, s); sdf = octstr_create(df); if ((nifd = update_mmbox_index(ifd, octstr_get_cstr(home), ITEM_ADD, sdf, state, flags, msize)) < 0 ) { char fbuf[256]; sprintf(fbuf, "%s/%s", octstr_get_cstr(home), df); unlink(fbuf); octstr_destroy(sdf); sdf = NULL; goto done; } ifd = nifd; octstr_replace(sdf, octstr_imm("/"), octstr_imm("-")); done: if (dfd > 0) unlock_and_close(dfd); if (ifd > 0) unlock_and_close(ifd); if (s) octstr_destroy(s); if (home) octstr_destroy(home); if (state) octstr_destroy(state); if (flags) gwlist_destroy(flags, (gwlist_item_destructor_t *)octstr_destroy); return sdf; }
/* Format of Index file: * each message is described by a single line: * df state flag1 flag2 flag3 ... */ static int update_mmbox_index(int fd, char *mmbox_dir, int cmd, Octstr *df, Octstr *state, List *flags, long msgsize) { char fbuf[256], linbuf[1024]; int tempfd; FILE *fp; /* Make a temp file. */ sprintf(fbuf, "%.128s/t%s.%ld.%ld", mmbox_dir, IDXFILE, time(NULL), random() % 1000); tempfd = open(fbuf, O_RDWR|O_CREAT|O_EXCL, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP); if (tempfd < 0 ) { error(0, "mmbox.update_index: Failed to open temp file %s: error = %s\n", fbuf, strerror(errno)); goto done; } else if (mm_lockfile(tempfd, fbuf, 0) != 0) { /* Lock it. */ error(0, "mmbox.update_index: Failed lock temp file %s: error = %s\n", fbuf, strerror(errno)); unlock_and_close(tempfd); tempfd = -1; goto done; } fp = fdopen(fd, "r"); if (!fp) { error(0, "mmbox.update_index: Failed fdopen on tempfd, file %s: error = %s\n", fbuf, strerror(errno)); unlock_and_close(tempfd); tempfd = -1; goto done; } while (fgets(linbuf, sizeof linbuf, fp) != NULL) { char idx[128], xstate[32]; Octstr *outs = NULL; int i; int size; sscanf(linbuf, "%s %s %d%n", idx, xstate, &size, &i); if (df && octstr_str_compare(df, idx) == 0) if (cmd == ITEM_DEL || cmd == ITEM_ADD) goto loop; /* Skip it. */ else { /* MOD. */ Octstr *p = linearise_string_list(flags, " "); outs = octstr_format("%S %S %d %S\n", df, state, msgsize, p); octstr_destroy(p); } else { /* Copy out as-is */ char *p = skip_space(linbuf + i); outs = octstr_format("%s %s %d %s%s", idx, xstate, size, p, (strchr(p, '\n') != NULL ? "" : "\n")); } loop: if (outs) { if (octstr_len(outs) > 0) octstr_write_to_socket(tempfd, outs); octstr_destroy(outs); } } if (cmd == ITEM_ADD) { /* Finally, for ADD, just add it. */ Octstr *s, *p = linearise_string_list(flags, " "); s = octstr_format("%S %S %d %S\n", df, state, msgsize, p); octstr_destroy(p); octstr_write_to_socket(tempfd, s); octstr_destroy(s); } fsync(tempfd); sprintf(linbuf, "%.128s/%s", mmbox_dir, IDXFILE); rename(fbuf, linbuf); unlock_and_fclose(fp); done: return tempfd; }
/* Makes a file name in the nested directory structure, where we can store * data. Makes a number of tries -- similar to mkqf in queue module. */ static int mkdf(char df[64], char *mmbox_home) { int i = 0, fd = -1; static int ect; if (!mmbox_home) gw_panic(0, "Mmbox directory passed as null!"); do { char d1[2], d2[3]; Octstr *tmp; char *ctmp; d1[0] = _TT[random() % _TTSIZE]; d1[1] = '\0'; /* Make first level. */ tmp = octstr_format("%.128s/%s", mmbox_home, d1); if (mkdir(octstr_get_cstr(tmp), S_IRWXU|S_IRWXG) < 0 && errno != EEXIST) { error(0, "mmbox.mkdf: failed to create dir [%s] " " in mmbox home %s: %s!", octstr_get_cstr(tmp), mmbox_home, strerror(errno)); octstr_destroy(tmp); return -1; } octstr_destroy(tmp); d2[0] = _TT[random() % _TTSIZE]; d2[1] = _TT[random() % _TTSIZE]; d2[2] = '\0'; /* Make second level. */ tmp = octstr_format("%.128s/%s/%s", mmbox_home, d1,d2); if (mkdir(octstr_get_cstr(tmp), S_IRWXU|S_IRWXG) < 0 && errno != EEXIST) { error(0, "mmbox.mkdf: failed to create dir [%s] " " in mmbox home %s: %s!", octstr_get_cstr(tmp), mmbox_home, strerror(errno)); octstr_destroy(tmp); return -1; } octstr_destroy(tmp); /* use df[] to store candidate so when we hit success it is already there...*/ sprintf(df, "%s/%s/%cf%ld.%d.x%d%ld", d1,d2, MDF, time(NULL), ++ect, getpid(), random() % 100); tmp = octstr_format("%s/%s", mmbox_home, df); ctmp = octstr_get_cstr(tmp); fd = open(ctmp, O_RDWR|O_CREAT|O_EXCL, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP); if (fd >= 0 && mm_lockfile(fd,ctmp,1) != 0) { unlink(ctmp); unlock_and_close(fd); fd = -1; } octstr_destroy(tmp); } while (i++ < MAXTRIES && fd < 0); return fd; }