Exemplo n.º 1
0
static struct dlr_entry *dlr_redis_get(const Octstr *smsc, const Octstr *ts, const Octstr *dst)
{
    Octstr *key, *sql;
    DBPoolConn *pconn;
    List *binds = gwlist_create();
    List *result = NULL, *row;
    struct dlr_entry *res = NULL;

    pconn = dbpool_conn_consume(pool);
    if (pconn == NULL) {
        error(0, "DLR: REDIS: No connection available");
        gwlist_destroy(binds, NULL);
        dbpool_conn_produce(pconn);
        return NULL;
    }

    /* If the destination address is not NULL, then
     * it has been shortened by the abstractive layer. */
    key = octstr_format((dst ? "%S:?:?:?" : "%S:?:?"), fields->table);

    sql = octstr_format("HMGET %S ? ? ? ? ? ?", key);
    gwlist_append(binds, (Octstr *)smsc); /* key */
    gwlist_append(binds, (Octstr *)ts); /* key */
    if (dst)
        gwlist_append(binds, (Octstr *)dst); /* key */
    gwlist_append(binds, fields->field_mask);
    gwlist_append(binds, fields->field_serv);
    gwlist_append(binds, fields->field_url);
    gwlist_append(binds, fields->field_src);
    gwlist_append(binds, fields->field_dst);
    gwlist_append(binds, fields->field_boxc);

    if (dbpool_conn_select(pconn, sql, binds, &result) != 0) {
        error(0, "DLR: REDIS: Failed to fetch DLR for %s", octstr_get_cstr(key));
        octstr_destroy(sql);
        octstr_destroy(key);
        gwlist_destroy(binds, NULL);
        dbpool_conn_produce(pconn);
        return NULL;
    }

    dbpool_conn_produce(pconn);
    octstr_destroy(sql);
    octstr_destroy(key);
    gwlist_destroy(binds, NULL);

#define LO2CSTR(r, i) octstr_get_cstr(gwlist_get(r, i))

    if (gwlist_len(result) > 0) {
        row = gwlist_extract_first(result);

        /*
         * If we get an empty set back from redis, this is
         * still an array with "" values, representing (nil).
         * If the mask is empty then this can't be a valid
         * set, therefore bail out.
         */
        if (octstr_len(gwlist_get(row, 0)) > 0) {
            res = dlr_entry_create();
            gw_assert(res != NULL);
            res->mask = atoi(octstr_get_cstr(gwlist_get(row, 0)));
            get_octstr_value(&res->service, row, 1);
            get_octstr_value(&res->url, row, 2);
            octstr_url_decode(res->url);
            get_octstr_value(&res->source, row, 3);
            get_octstr_value(&res->destination, row, 4);
            get_octstr_value(&res->boxc_id, row, 5);
            res->smsc = octstr_duplicate(smsc);

            octstr_replace(res->source, octstr_imm("__space__"), octstr_imm(" "));
            octstr_replace(res->destination, octstr_imm("__space__"), octstr_imm(" "));
        }
        gwlist_destroy(row, octstr_destroy_item);
    }
    gwlist_destroy(result, NULL);

#undef LO2CSTR

    return res;
}
Exemplo n.º 2
0
struct dlr_storage *dlr_init_redis(Cfg *cfg)
{
    CfgGroup *grp;
    List *grplist;
    Octstr *redis_host, *redis_pass, *redis_id;
    long redis_port = 0, redis_database = -1, redis_idle_timeout = -1;
    Octstr *p = NULL;
    long pool_size;
    DBConf *db_conf = NULL;

    /*
     * Check for all mandatory directives that specify the field names
     * of the used Redis key
     */
    if (!(grp = cfg_get_single_group(cfg, octstr_imm("dlr-db"))))
        panic(0, "DLR: Redis: group 'dlr-db' is not specified!");

    if (!(redis_id = cfg_get(grp, octstr_imm("id"))))
        panic(0, "DLR: Redis: directive 'id' is not specified!");

    fields = dlr_db_fields_create(grp);
    gw_assert(fields != NULL);

    /*
     * Escaping special quotes for field/table names
     */
    octstr_replace(fields->table, octstr_imm("`"), octstr_imm("``"));
    octstr_replace(fields->field_smsc, octstr_imm("`"), octstr_imm("``"));
    octstr_replace(fields->field_ts, octstr_imm("`"), octstr_imm("``"));
    octstr_replace(fields->field_src, octstr_imm("`"), octstr_imm("``"));
    octstr_replace(fields->field_dst, octstr_imm("`"), octstr_imm("``"));
    octstr_replace(fields->field_serv, octstr_imm("`"), octstr_imm("``"));
    octstr_replace(fields->field_url, octstr_imm("`"), octstr_imm("``"));
    octstr_replace(fields->field_mask, octstr_imm("`"), octstr_imm("``"));
    octstr_replace(fields->field_status, octstr_imm("`"), octstr_imm("``"));
    octstr_replace(fields->field_boxc, octstr_imm("`"), octstr_imm("``"));

    /*
     * Now grab the required information from the 'redis-connection' group
     * with the redis-id we just obtained.
     *
     * We have to loop through all available Redis connection definitions
     * and search for the one we are looking for.
     */
    grplist = cfg_get_multi_group(cfg, octstr_imm("redis-connection"));
    while (grplist && (grp = gwlist_extract_first(grplist)) != NULL) {
        p = cfg_get(grp, octstr_imm("id"));
        if (p != NULL && octstr_compare(p, redis_id) == 0) {
            goto found;
        }
        if (p != NULL)
            octstr_destroy(p);
    }
    panic(0, "DLR: Redis: connection settings for id '%s' are not specified!",
          octstr_get_cstr(redis_id));

found:
    octstr_destroy(p);
    gwlist_destroy(grplist, NULL);

    if (cfg_get_integer(&pool_size, grp, octstr_imm("max-connections")) == -1 || pool_size == 0)
        pool_size = 1;

    if (!(redis_host = cfg_get(grp, octstr_imm("host"))))
   	    panic(0, "DLR: Redis: directive 'host' is not specified!");
    if (cfg_get_integer(&redis_port, grp, octstr_imm("port")) == -1)
   	    panic(0, "DLR: Redis: directive 'port' is not specified!");
    redis_pass = cfg_get(grp, octstr_imm("password"));
    cfg_get_integer(&redis_database, grp, octstr_imm("database"));
    cfg_get_integer(&redis_idle_timeout, grp, octstr_imm("idle-timeout"));

    /*
     * Ok, ready to connect to Redis
     */
    db_conf = gw_malloc(sizeof(DBConf));
    gw_assert(db_conf != NULL);

    db_conf->redis = gw_malloc(sizeof(RedisConf));
    gw_assert(db_conf->redis != NULL);

    db_conf->redis->host = redis_host;
    db_conf->redis->port = redis_port;
    db_conf->redis->password = redis_pass;
    db_conf->redis->database = redis_database;
    db_conf->redis->idle_timeout = redis_idle_timeout;

    pool = dbpool_create(DBPOOL_REDIS, db_conf, pool_size);
    gw_assert(pool != NULL);

    /*
     * Panic on failure to connect. Should we just try to reconnect?
     */
    if (dbpool_conn_count(pool) == 0)
        panic(0,"DLR: Redis: database pool has no connections!");

    octstr_destroy(redis_id);

    return &handles;
}
Exemplo n.º 3
0
static void dlr_redis_add(struct dlr_entry *entry)
{
    Octstr *key, *sql, *os_mask;
    Octstr *dstclean, *srcclean, *tsclean;
    DBPoolConn *pconn;
    List *binds;
    int res, len;

    debug("dlr.redis", 0, "Adding DLR into keystore");

    pconn = dbpool_conn_consume(pool);
    /* just for sure */
    if (pconn == NULL) {
        error(0, "DLR: REDIS: No connection available - dropping DLR");
        dlr_entry_destroy(entry);
        return;
    }

    /*
     * This code is needed as we are mis-using the Hiredis API and
     * passing a fully-formed Redis command rather than tokenized
     * command components. Redis treats a space are a command delimiter
     * so any component that can include a space needs to be quoted.
     * Should be re-written to use the RedisCommandArgv() API.
     */

    dstclean = octstr_duplicate(entry->destination);
    octstr_replace(dstclean, octstr_imm(" "), octstr_imm("__space__"));

    srcclean = octstr_duplicate(entry->source);
    octstr_replace(srcclean, octstr_imm(" "), octstr_imm("__space__"));

    tsclean = octstr_duplicate(entry->timestamp);
    octstr_replace(tsclean, octstr_imm(" "), octstr_imm("__space__"));

    if (entry->use_dst && entry->destination) {
        Octstr *dst_min;

        /* keep a shorten version for the key part */
        dst_min = octstr_duplicate(dstclean);
        len = octstr_len(dst_min);
        if (len > MIN_DST_LEN)
            octstr_delete(dst_min, 0, len - MIN_DST_LEN);

        key = octstr_format("%S:%S:%S:%S", fields->table,
                entry->smsc,
                tsclean,
                dst_min);

        octstr_destroy(dst_min);
    } else {
        key = octstr_format("%S:%S:%S", fields->table,
                entry->smsc,
                tsclean);
    }

#ifdef REDIS_PRECHECK
    binds = gwlist_create();
    sql = octstr_format("HSETNX %S %S ?", key, fields->field_smsc);
    if (dbpool_conn_update(pconn, sql, binds) != 1) {
        error(0, "DLR: REDIS: DLR for %s already exists! Duplicate Message ID?",
              octstr_get_cstr(key));

        octstr_destroy(sql);
        octstr_destroy(key);
        octstr_destroy(tsclean);
        octstr_destroy(dstclean);
        octstr_destroy(srcclean);
        gwlist_destroy(binds, NULL);
        dbpool_conn_produce(pconn);
        return;
    }
    octstr_destroy(sql);
    gwlist_destroy(binds, NULL);
#endif

    binds = gwlist_create();
    sql = octstr_format("HMSET %S %S ? %S ? %S ? %S ? %S ? %S ? %S ? %S ? %S 0",
            key,
            fields->field_smsc,
            fields->field_ts,
            fields->field_src,
            fields->field_dst,
            fields->field_serv,
            fields->field_url,
            fields->field_mask,
            fields->field_boxc,
            fields->field_status);

    /* prepare values */
    if (entry->url) {
        octstr_url_encode(entry->url);
        octstr_replace(entry->url, octstr_imm("%"), octstr_imm("%%"));
    }
    os_mask = octstr_format("%d", entry->mask);

    gwlist_append(binds, entry->smsc);
    gwlist_append(binds, tsclean);
    gwlist_append(binds, srcclean);
    gwlist_append(binds, dstclean);
    gwlist_append(binds, entry->service);
    gwlist_append(binds, entry->url);
    gwlist_append(binds, os_mask);
    gwlist_append(binds, entry->boxc_id);

    res = dbpool_conn_update(pconn, sql, binds);

    if (res == -1) {
        error(0, "DLR: REDIS: Error while adding dlr entry %s:%s:%s:%s",
              octstr_get_cstr(fields->table),
              octstr_get_cstr(entry->smsc),
              octstr_get_cstr(tsclean),
              octstr_get_cstr(dstclean));
    }
    else  {
        /* HMSET returned OK. Set EXPIRE if applicable and then
         * increment the DLR counter */
        if (fields->ttl) {
            octstr_destroy(sql);
            sql = octstr_format("EXPIRE %S %ld", key, fields->ttl);
            res = dbpool_conn_update(pconn, sql, NULL);
        }
        /* We are not performing an 'INCR <table>:Count'
         * operation here, since we can't be accurate due
         * to TTL'ed expiration. Rather use 'DBSIZE' based
         * on seperated databases in redis. */
    }

    dbpool_conn_produce(pconn);
    octstr_destroy(os_mask);
    octstr_destroy(sql);
    octstr_destroy(key);
    octstr_destroy(tsclean);
    octstr_destroy(dstclean);
    octstr_destroy(srcclean);
    gwlist_destroy(binds, NULL);
    dlr_entry_destroy(entry);
}
Exemplo n.º 4
0
/* MT related function */
static int brunet_send_sms(SMSCConn *conn, Msg *sms)
{
    ConnData *conndata = conn->data;
    Octstr *url, *tid, *xser;
    List *headers;
    char id[UUID_STR_LEN + 1];
    int dcs;

    /*
     * Construct TransactionId.
     * Beware that brunet needs an "clean" octstr representation,
     * without the dashes in the string. So remove them.
     */
    uuid_unparse(sms->sms.id, id);
    tid = octstr_create(id);
    octstr_replace(tid, octstr_imm("-"), octstr_imm(""));

    /* form the basic URL */
    url = octstr_format("%S?MsIsdn=%E&Originator=%E",
        conndata->send_url, sms->sms.receiver, sms->sms.sender);

    /*
     * We use &binfo=<foobar> from sendsms interface to encode
     * additional paramters. If a mandatory value is not set,
     * a default value is applied
     */
    if (octstr_len(sms->sms.binfo)) {
        octstr_url_decode(sms->sms.binfo);
        octstr_format_append(url, "&%S", sms->sms.binfo);
    }
    /* CustomerId */
    if (octstr_search(url, octstr_create("CustomerId="), 0) == -1) {
        octstr_format_append(url, "&CustomerId=%S", conndata->username);
    }
    /* TransactionId */
    if (octstr_search(url, octstr_create("TransactionId="), 0) == -1) {
        octstr_format_append(url, "&TransactionId=%S", tid);
    }
    /* SMSCount */
    if (octstr_search(url, octstr_create("SMSCount="), 0) == -1) {
        octstr_format_append(url, "&%s", "SMSCount=1");
    }
    /* ActionType */
    if (octstr_search(url, octstr_create("ActionType="), 0) == -1) {
        octstr_format_append(url, "&%s", "ActionType=A");
    }
    /* ServiceDeliveryType */
    if (octstr_search(url, octstr_create("ServiceDeliveryType="), 0) == -1) {
        octstr_format_append(url, "&%s", "ServiceDeliveryType=P");
    }

    /* if coding is not set and UDH exists, assume DC_8BIT
     * else default to DC_7BIT */
    if (sms->sms.coding == DC_UNDEF)
        sms->sms.coding = octstr_len(sms->sms.udhdata) > 0 ? DC_8BIT : DC_7BIT;

    if (sms->sms.coding == DC_8BIT)
        octstr_format_append(url, "&MessageType=B&Text=%H", sms->sms.msgdata);
    else
        octstr_format_append(url, "&MessageType=S&Text=%E", sms->sms.msgdata);

    dcs = fields_to_dcs(sms,
        (sms->sms.alt_dcs != SMS_PARAM_UNDEFINED ? sms->sms.alt_dcs : 0));

    /* XSer processing */
    xser = octstr_create("");
    /* XSer DCS values */
    if (dcs != 0 && dcs != 4)
        octstr_format_append(xser, "0201%02x", dcs & 0xff);
    /* add UDH header */
    if (octstr_len(sms->sms.udhdata)) {
        octstr_format_append(xser, "01%02x%H", octstr_len(sms->sms.udhdata),
                             sms->sms.udhdata);
    }
    if (octstr_len(xser) > 0)
        octstr_format_append(url, "&XSer=%S", xser);
    octstr_destroy(xser);


    headers = http_create_empty_headers();
    debug("smsc.http.brunet", 0, "HTTP[%s]: Sending request <%s>",
          octstr_get_cstr(conn->id), octstr_get_cstr(url));

    /*
     * Brunet requires an SSL-enabled HTTP client call, this is handled
     * transparently by the Kannel HTTP layer module.
     */
    http_start_request(conndata->http_ref, HTTP_METHOD_GET, url, headers,
                       NULL, 0, sms, NULL);

    octstr_destroy(url);
    octstr_destroy(tid);
    http_destroy_headers(headers);

    return 0;
}
Exemplo n.º 5
0
struct dlr_storage *dlr_init_pgsql(Cfg *cfg)
{
    CfgGroup *grp;
    List *grplist;
    Octstr *pgsql_host, *pgsql_user, *pgsql_pass, *pgsql_db, *pgsql_id;
    long pgsql_port = 0;
    Octstr *p = NULL;
    long pool_size;
    DBConf *db_conf = NULL;

    /*
     * check for all mandatory directives that specify the field names
     * of the table used
     */
    if (!(grp = cfg_get_single_group(cfg, octstr_imm("dlr-db"))))
        panic(0, "DLR: PgSQL: group 'dlr-db' is not specified!");

    if (!(pgsql_id = cfg_get(grp, octstr_imm("id"))))
   	    panic(0, "DLR: PgSQL: directive 'id' is not specified!");

    fields = dlr_db_fields_create(grp);
    gw_assert(fields != NULL);

    /*
     * Escaping special quotes for field/table names
     */
    octstr_replace(fields->table, octstr_imm("\""), octstr_imm("\"\""));
    octstr_replace(fields->field_smsc, octstr_imm("\""), octstr_imm("\"\""));
    octstr_replace(fields->field_ts, octstr_imm("\""), octstr_imm("\"\""));
    octstr_replace(fields->field_src, octstr_imm("\""), octstr_imm("\"\""));
    octstr_replace(fields->field_dst, octstr_imm("\""), octstr_imm("\"\""));
    octstr_replace(fields->field_serv, octstr_imm("\""), octstr_imm("\"\""));
    octstr_replace(fields->field_url, octstr_imm("\""), octstr_imm("\"\""));      
    octstr_replace(fields->field_mask, octstr_imm("\""), octstr_imm("\"\""));
    octstr_replace(fields->field_status, octstr_imm("\""), octstr_imm("\"\"")); 
    octstr_replace(fields->field_boxc, octstr_imm("\""), octstr_imm("\"\""));

    /*
     * now grap the required information from the 'pgsql-connection' group
     * with the pgsql-id we just obtained
     *
     * we have to loop through all available PostgreSQL connection definitions
     * and search for the one we are looking for
     */

    grplist = cfg_get_multi_group(cfg, octstr_imm("pgsql-connection"));
    while (grplist && (grp = gwlist_extract_first(grplist)) != NULL) {
        p = cfg_get(grp, octstr_imm("id"));
        if (p != NULL && octstr_compare(p, pgsql_id) == 0) {
            goto found;
        }
        if (p != NULL) 
            octstr_destroy(p);
    }
    panic(0, "DLR: PgSQL: connection settings for id '%s' are not specified!",
          octstr_get_cstr(pgsql_id));

found:
    octstr_destroy(p);
    gwlist_destroy(grplist, NULL);

    if (cfg_get_integer(&pool_size, grp, octstr_imm("max-connections")) == -1 || pool_size == 0)
        pool_size = 1;

    if (!(pgsql_host = cfg_get(grp, octstr_imm("host"))))
   	    panic(0, "DLR: PgSQL: directive 'host' is not specified!");
    if (!(pgsql_user = cfg_get(grp, octstr_imm("username"))))
   	    panic(0, "DLR: PgSQL: directive 'username' is not specified!");
    if (!(pgsql_pass = cfg_get(grp, octstr_imm("password"))))
   	    panic(0, "DLR: PgSQL: directive 'password' is not specified!");
    if (!(pgsql_db = cfg_get(grp, octstr_imm("database"))))
   	    panic(0, "DLR: PgSQL: directive 'database' is not specified!");
    cfg_get_integer(&pgsql_port, grp, octstr_imm("port"));  /* optional */

    /*
     * ok, ready to connect to the database
     */
    db_conf = gw_malloc(sizeof(DBConf));
    gw_assert(db_conf != NULL);

    db_conf->pgsql = gw_malloc(sizeof(PgSQLConf));
    gw_assert(db_conf->pgsql != NULL);

    db_conf->pgsql->host = pgsql_host;
    db_conf->pgsql->port = pgsql_port;
    db_conf->pgsql->username = pgsql_user;
    db_conf->pgsql->password = pgsql_pass;
    db_conf->pgsql->database = pgsql_db;

    pool = dbpool_create(DBPOOL_PGSQL, db_conf, pool_size);
    gw_assert(pool != NULL);

    /*
     * XXX should a failing connect throw panic?!
     */
    if (dbpool_conn_count(pool) == 0)
        panic(0,"DLR: PgSQL: database pool has no connections!");

    octstr_destroy(pgsql_id);

    return &handles;
}
Exemplo n.º 6
0
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;
}
Exemplo n.º 7
0
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;
}