?? mms_mmbox.c
字號:
/*
* Mbuni - Open Source MMS Gateway
*
* Mbuni MMBox implementation
*
* Copyright (C) 2003 - 2005, Digital Solutions Ltd. - http://www.dsmagic.com
*
* Paul Bagyenda <bagyenda@dsmagic.com>
*
* This program is free software, distributed under the terms of
* the GNU General Public License, with a few exceptions granted (see LICENSE)
*/
#include <sys/file.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <ctype.h>
#include "mms_mmbox.h"
#include "mms_util.h"
#include "gwlib/log.h"
#include "gwlib/accesslog.h"
#define MAXTRIES 10
#define MDF 'd'
#define MTF 't'
#define IDXFILE "00Index"
#define ITEM_ADD 1
#define ITEM_DEL 2
#define ITEM_MOD 3
/* Initialise the root of the mmbox. Should be called once from load settings. */
int mmbox_root_init(char *mmbox_root)
{
int i, ret;
if ((ret = mkdir(mmbox_root,
S_IRWXU|S_IRWXG)) < 0 &&
errno != EEXIST)
return errno;
for (i = 0; _TT[i]; i++) {
char fbuf[256];
sprintf(fbuf, "%.128s/%c", mmbox_root, _TT[i]);
if (mkdir(fbuf,
S_IRWXU|S_IRWXG) < 0 &&
errno != EEXIST)
return errno;
}
srandom(time(NULL)); /* we need rands below...*/
return 0;
}
/* Initialise the mmbox home of the user/msisdn.
* structure of mmbox is:
* - index file [IDXFILE]
* - directories a - z 0 - 9, which each can contain directories with two-character
* names
* on init we only create the directory itself. internal
* directory structure and index will be made by first message put in.
* return user dir, or NULL if something went wrong.
*/
static Octstr *user_mmbox_dir(char *mmbox_root, char *userid)
{
unsigned long h = _mshash(userid);
char d1[2], d2[3], fbuf[512];
Octstr *t, *s;
/* Make toplevel dir. */
d1[0] = _TT[h%_TTSIZE];
d1[1] = '\0';
/* Then lower level. */
h /= _TTSIZE;
d2[0] = _TT[h%_TTSIZE];
h /= _TTSIZE;
d2[1] = _TT[h%_TTSIZE];
d2[2] = '\0';
/* Try and create the next level dir (first level was created by root_init) */
sprintf(fbuf, "%.128s/%s/%s", mmbox_root, d1, d2);
if (mkdir(fbuf,
S_IRWXU|S_IRWXG) < 0 &&
errno != EEXIST) {
error(0, "mmbox: failed to create dir [%s] "
"while initialising mmbox for %s: %s!",
fbuf, userid, strerror(errno));
return NULL;
}
t = octstr_create(userid);
octstr_replace(t, octstr_imm("/"), octstr_imm("$")); /* XXX safe in all cases?? */
s = octstr_format("%s/%S", fbuf, t);
octstr_destroy(t);
if (mkdir(octstr_get_cstr(s),
S_IRWXU|S_IRWXG) < 0 &&
errno != EEXIST) {
error(0, "mmbox: failed to create dir [%s] "
"while initialising mmbox for %s: %s!",
octstr_get_cstr(s), userid, strerror(errno));
octstr_destroy(s);
return NULL;
}
return s;
}
/* 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);
close(fd);
fd = -1;
}
octstr_destroy(tmp);
} while (i++ < MAXTRIES && fd < 0);
return fd;
}
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) {
close(fd);
fd = -1;
}
while (i++ < MAXTRIES && fd < 0);
return fd;
}
static Octstr *linearise_string_list(List *l, char *sep)
{
int i, n;
Octstr *s = octstr_create("");
for (i = 0, n = gwlist_len(l); i < n; i++) {
Octstr *p = gwlist_get(l,i);
if (p)
octstr_format_append(s, "%s%S", (i == 0) ? "" : sep, p);
}
return s;
}
static List *parse_string_list(char *buf)
{
int i = 0;
char sbuf[128], *p = buf;
List *l = gwlist_create();
while (sscanf(p, "%s%n", sbuf, &i) > 0) {
gwlist_append(l, octstr_create(sbuf));
p += i;
}
return l;
}
static char *skip_space(char *s)
{
while (*s && isspace(*s))
s++;
return s;
}
/* 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));
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));
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);
fclose(fp);
done:
return tempfd;
}
static List *make_mm_flags(List *oflags, List *flag_cmds)
{
List *l = oflags ? oflags : gwlist_create();
int i, n;
for (i = 0, n = gwlist_len(l); i < n; i++) { /* cleanup list. */
Octstr *x = gwlist_get(l,i);
int ch = octstr_get_char(x, 0);
if (ch == '+' || ch == '-' || ch == '/')
octstr_delete(x,0,1);
}
for (i = 0, n = (flag_cmds ? gwlist_len(flag_cmds) : 0); i<n; i++) {
Octstr *x = gwlist_get(flag_cmds,i);
int ch = octstr_get_char(x, 0);
char *s = octstr_get_cstr(x);
int j, m, cmd;
if (ch == '+' || ch == '-' || ch == '/') {
s++;
cmd = ch;
} else
cmd = '+';
/* Find it in original. If existent, remove it. */
for (j = 0, m = gwlist_len(l); j < m; j++)
if (octstr_str_compare(gwlist_get(l,j),s) == 0) {
Octstr *y = gwlist_get(l,j);
gwlist_delete(l,j,1);
octstr_destroy(y);
j--;
m--;
}
if (cmd == '+' || cmd == '/')
gwlist_append(l, octstr_create(s));
}
return l;
}
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;
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -