Exemple #1
0
static void dlr_add_mssql(struct dlr_entry *entry)
{
    Octstr *sql;
    DBPoolConn *pconn;
    debug("dlr.mssql", 0, "adding DLR entry into database");
    int res;

    pconn = dbpool_conn_consume(pool);
    /* just for sure */
    if (pconn == NULL) {
        dlr_entry_destroy(entry);
        return;
    }
    
    sql = octstr_format("INSERT INTO %S (%S, %S, %S, %S, %S, %S, %S, %S, %S) VALUES "
                "('%S', '%S', '%S', '%S', '%S', '%S', '%d', '%S', '%d')",
                fields->table, 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,
                entry->smsc, entry->timestamp, entry->source, entry->destination,
                entry->service, entry->url, entry->mask, entry->boxc_id, 0);

#if defined(DLR_TRACE)
    debug("dlr.mssql", 0, "sql: %s", octstr_get_cstr(sql));
#endif
    if ((res = dbpool_conn_update(pconn, sql, NULL)) == -1)
        error(0, "DLR: MSSQL: Error while adding dlr entry for DST<%s>", octstr_get_cstr(entry->destination));
    else if (!res)
        warning(0, "DLR: MSSQL: No dlr inserted for DST<%s>", octstr_get_cstr(entry->destination));

    dbpool_conn_produce(pconn);
    octstr_destroy(sql);
    dlr_entry_destroy(entry);
}
Exemple #2
0
static void dlr_sdb_add(struct dlr_entry *dlr)
{
    Octstr *sql;
    int	state;

    sql = octstr_format("INSERT INTO %s (%s, %s, %s, %s, %s, %s, %s, %s, %s) VALUES "
                        "('%s', '%s', '%s', '%s', '%s', '%s', '%d', '%s', '%d')",
                        octstr_get_cstr(fields->table), octstr_get_cstr(fields->field_smsc),
                        octstr_get_cstr(fields->field_ts),
                        octstr_get_cstr(fields->field_src), octstr_get_cstr(fields->field_dst),
                        octstr_get_cstr(fields->field_serv), octstr_get_cstr(fields->field_url),
                        octstr_get_cstr(fields->field_mask), octstr_get_cstr(fields->field_boxc),
                        octstr_get_cstr(fields->field_status),
                        octstr_get_cstr(dlr->smsc), octstr_get_cstr(dlr->timestamp),
                        octstr_get_cstr(dlr->source), octstr_get_cstr(dlr->destination),
                        octstr_get_cstr(dlr->service), octstr_get_cstr(dlr->url), dlr->mask,
                        octstr_get_cstr(dlr->boxc_id), 0);

#if defined(DLR_TRACE)
     debug("dlr.sdb", 0, "SDB: sql: %s", octstr_get_cstr(sql));
#endif

    state = gw_sdb_query(octstr_get_cstr(sql), NULL, NULL);
    if (state == -1)
        error(0, "SDB: error in inserting DLR for DST <%s>", octstr_get_cstr(dlr->destination));
    else if (!state)
        warning(0, "SDB: No dlr inserted for DST <%s>", octstr_get_cstr(dlr->destination));

    octstr_destroy(sql);
    dlr_entry_destroy(dlr);
}
Exemple #3
0
static void dlr_mysql_add(struct dlr_entry *entry)
{
    Octstr *sql, *os_mask;
    DBPoolConn *pconn;
    List *binds = gwlist_create();
    int res;

    debug("dlr.mysql", 0, "adding DLR entry into database");

    pconn = dbpool_conn_consume(pool);
    /* just for sure */
    if (pconn == NULL) {
        dlr_entry_destroy(entry);
        return;
    }

    sql = octstr_format("INSERT INTO `%S` (`%S`, `%S`, `%S`, `%S`, `%S`, `%S`, `%S`, `%S`, `%S`) VALUES "
                        "(?, ?, ?, ?, ?, ?, ?, ?, 0)",
                        fields->table, 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);
    os_mask = octstr_format("%d", entry->mask);
    gwlist_append(binds, entry->smsc);
    gwlist_append(binds, entry->timestamp);
    gwlist_append(binds, entry->source);
    gwlist_append(binds, entry->destination);
    gwlist_append(binds, entry->service);
    gwlist_append(binds, entry->url);
    gwlist_append(binds, os_mask);
    gwlist_append(binds, entry->boxc_id);

#if defined(DLR_TRACE)
    debug("dlr.mysql", 0, "sql: %s", octstr_get_cstr(sql));
#endif
    if ((res = dbpool_conn_update(pconn, sql, binds)) == -1)
        error(0, "DLR: MYSQL: Error while adding dlr entry for DST<%s>", octstr_get_cstr(entry->destination));
    else if (!res)
        warning(0, "DLR: MYSQL: No dlr inserted for DST<%s>", octstr_get_cstr(entry->destination));

    dbpool_conn_produce(pconn);
    octstr_destroy(sql);
    gwlist_destroy(binds, NULL);
    octstr_destroy(os_mask);
    dlr_entry_destroy(entry);
}
/* Add a new DLR entry to MongoDB */
static void dlr_mongodb_add(struct dlr_entry *entry)
{
    DBPoolConn *pconn;
    bson b;
    bson_buffer buf;
    mongo_connection *conn = NULL;

    pconn = dbpool_conn_consume(pool);
    if (pconn == NULL) {
        dlr_entry_destroy(entry);
        return;
    }
    conn = (mongo_connection*)pconn->conn;

    bson_buffer_init(&buf);
    bson_append_new_oid(&buf, "_id");

    bson_append_string(&buf, octstr_get_cstr(fields->field_smsc), octstr_get_cstr(entry->smsc));
    bson_append_string(&buf, octstr_get_cstr(fields->field_ts), octstr_get_cstr(entry->timestamp));
    bson_append_string(&buf, octstr_get_cstr(fields->field_src), octstr_get_cstr(entry->source));
    bson_append_string(&buf, octstr_get_cstr(fields->field_dst), octstr_get_cstr(entry->destination));
    bson_append_string(&buf, octstr_get_cstr(fields->field_serv), octstr_get_cstr(entry->service));
    bson_append_string(&buf, octstr_get_cstr(fields->field_url), octstr_get_cstr(entry->url));
    bson_append_string(&buf, octstr_get_cstr(fields->field_account), octstr_get_cstr(entry->account));
    bson_append_string(&buf, octstr_get_cstr(fields->field_binfo), octstr_get_cstr(entry->binfo));
    bson_append_int(&buf, octstr_get_cstr(fields->field_mask), entry->mask);
    bson_append_string(&buf, octstr_get_cstr(fields->field_boxc), octstr_get_cstr(entry->boxc_id));
    bson_append_int(&buf, octstr_get_cstr(fields->field_status), 0);

    bson_from_buffer(&b, &buf);

    /* TODO: namespace support */
    MONGO_TRY {
        mongo_insert(conn, mongodb_namespace, &b);
    } MONGO_CATCH {
        mongodb_error("dlr_mongodb_insert", conn->exception.type);
    }

    dbpool_conn_produce(pconn);

    bson_destroy(&b);
    dlr_entry_destroy(entry);
}
Exemple #5
0
static void dlr_add_oracle(struct dlr_entry *entry)
{
    Octstr *sql, *os_mask;
    DBPoolConn *pconn;
    List *binds = gwlist_create();
    debug("dlr.oracle", 0, "adding DLR entry into database");

    pconn = dbpool_conn_consume(pool);
    /* just for sure */
    if (pconn == NULL) {
        dlr_entry_destroy(entry);
        return;
    }

    sql = octstr_format("INSERT INTO %S (%S, %S, %S, %S, %S, %S, %S, %S, %S) VALUES "
                        "(:1, :2, :3, :4, :5, :6, :7, :8, 0)",
                        fields->table, 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);
    os_mask = octstr_format("%d", entry->mask);
    
    gwlist_append(binds, entry->smsc);         /* :1 */
    gwlist_append(binds, entry->timestamp);    /* :2 */
    gwlist_append(binds, entry->source);       /* :3 */
    gwlist_append(binds, entry->destination);  /* :4 */
    gwlist_append(binds, entry->service);      /* :5 */
    gwlist_append(binds, entry->url);          /* :6 */
    gwlist_append(binds, os_mask);             /* :7 */
    gwlist_append(binds, entry->boxc_id);      /* :8 */
#if defined(DLR_TRACE)
    debug("dlr.oracle", 0, "sql: %s", octstr_get_cstr(sql));
#endif
    if (dbpool_conn_update(pconn, sql, binds) == -1)
        error(0, "DLR: ORACLE: Error while adding dlr entry for DST<%s>", octstr_get_cstr(entry->destination));

    dbpool_conn_produce(pconn);
    octstr_destroy(sql);
    gwlist_destroy(binds, NULL);
    octstr_destroy(os_mask);
    dlr_entry_destroy(entry);
}
Exemple #6
0
static struct dlr_entry*  dlr_sdb_get(const Octstr *smsc, const Octstr *ts, const Octstr *dst)
{
    Octstr *sql, *like;
    int	state;
    struct dlr_entry *res = dlr_entry_create();

    gw_assert(res != NULL);

    if (dst)
        like = octstr_format("AND %S LIKE '%%%S'", fields->field_dst, dst);
    else
        like = octstr_imm("");

    sql = octstr_format("SELECT %S, %S, %S, %S, %S, %S FROM %S WHERE %S='%S' "
          "AND %S='%S' %S %s", fields->field_mask, fields->field_serv,
          fields->field_url, fields->field_src, fields->field_dst,
          fields->field_boxc, fields->table, fields->field_smsc, smsc,
          fields->field_ts, ts, like, sdb_get_limit_str());

#if defined(DLR_TRACE)
     debug("dlr.sdb", 0, "SDB: sql: %s", octstr_get_cstr(sql));
#endif

    state = gw_sdb_query(octstr_get_cstr(sql), sdb_callback_add, res);
    octstr_destroy(sql);
    octstr_destroy(like);
    if (state == -1) {
        error(0, "SDB: error in finding DLR");
        goto notfound;
    }
    else if (state == 0) {
        debug("dlr.sdb", 0, "SDB: no entry found for DST <%s>.", octstr_get_cstr(dst));
        goto notfound;
    }

    res->smsc = octstr_duplicate(smsc);

    return res;

notfound:
    dlr_entry_destroy(res);
    return NULL;
}
Exemple #7
0
static void dlr_pgsql_add(struct dlr_entry *entry)
{
    Octstr *sql;

    sql = octstr_format("INSERT INTO %s (%s, %s, %s, %s, %s, %s, %s, %s, %s) VALUES "
                        "('%s', '%s', '%s', '%s', '%s', '%s', '%d', '%s', '%d');",
                        octstr_get_cstr(fields->table), octstr_get_cstr(fields->field_smsc),
                        octstr_get_cstr(fields->field_ts),
                        octstr_get_cstr(fields->field_src), octstr_get_cstr(fields->field_dst),
                        octstr_get_cstr(fields->field_serv), octstr_get_cstr(fields->field_url),
                        octstr_get_cstr(fields->field_mask), octstr_get_cstr(fields->field_boxc),
                        octstr_get_cstr(fields->field_status),
                        octstr_get_cstr(entry->smsc), octstr_get_cstr(entry->timestamp), octstr_get_cstr(entry->source),
                        octstr_get_cstr(entry->destination), octstr_get_cstr(entry->service), octstr_get_cstr(entry->url),
                        entry->mask, octstr_get_cstr(entry->boxc_id), 0);


    pgsql_update(sql);
    
    octstr_destroy(sql);
    dlr_entry_destroy(entry);
}
Exemple #8
0
static struct dlr_entry*  dlr_sdb_get(const Octstr *smsc, const Octstr *ts, const Octstr *dst)
{
    Octstr *sql;
    int	state;
    struct dlr_entry *res = dlr_entry_create();

    gw_assert(res != NULL);

    sql = octstr_format("SELECT %s, %s, %s, %s, %s, %s FROM %s WHERE %s='%s' AND %s='%s' %s",
                        octstr_get_cstr(fields->field_mask), octstr_get_cstr(fields->field_serv),
                        octstr_get_cstr(fields->field_url), octstr_get_cstr(fields->field_src),
                        octstr_get_cstr(fields->field_dst), octstr_get_cstr(fields->field_boxc),
                        octstr_get_cstr(fields->table),
                        octstr_get_cstr(fields->field_smsc), octstr_get_cstr(smsc),
                        octstr_get_cstr(fields->field_ts), octstr_get_cstr(ts), sdb_get_limit_str());

#if defined(DLR_TRACE)
     debug("dlr.sdb", 0, "SDB: sql: %s", octstr_get_cstr(sql));
#endif

    state = gw_sdb_query(octstr_get_cstr(sql), sdb_callback_add, res);
    octstr_destroy(sql);
    if (state == -1) {
        error(0, "SDB: error in finding DLR");
        goto notfound;
    }
    else if (state == 0) {
        debug("dlr.sdb", 0, "SDB: no entry found for DST <%s>.", octstr_get_cstr(dst));
        goto notfound;
    }

    res->smsc = octstr_duplicate(smsc);

    return res;

notfound:
    dlr_entry_destroy(res);
    return NULL;
}
Exemple #9
0
static void dlr_pgsql_add(struct dlr_entry *entry)
{
    Octstr *sql;

    sql = octstr_format("INSERT INTO \"%s\" (\"%s\", \"%s\", \"%s\", \"%s\", \"%s\", \"%s\", \"%s\", \"%s\", \"%s\") VALUES "
                        "('%s', '%s', '%s', '%s', '%s', '%s', '%d', '%s', '%d');",
                        octstr_get_cstr(fields->table), octstr_get_cstr(fields->field_smsc),
                        octstr_get_cstr(fields->field_ts),
                        octstr_get_cstr(fields->field_src), octstr_get_cstr(fields->field_dst),
                        octstr_get_cstr(fields->field_serv), octstr_get_cstr(fields->field_url),
                        octstr_get_cstr(fields->field_mask), octstr_get_cstr(fields->field_boxc),
                        octstr_get_cstr(fields->field_status),
                        octstr_get_cstr(entry->smsc), octstr_get_cstr(entry->timestamp), octstr_get_cstr(entry->source),
                        octstr_get_cstr(entry->destination), octstr_get_cstr(entry->service), octstr_get_cstr(entry->url),
                        entry->mask, octstr_get_cstr(entry->boxc_id), 0);


    if (!pgsql_update(sql))
       warning(0, "DLR: PGSQL: No dlr inserted for DST<%s>", octstr_get_cstr(entry->destination));
    
    octstr_destroy(sql);
    dlr_entry_destroy(entry);
}
Exemple #10
0
/*
 * Return Msg* if dlr entry found in DB, otherwise NULL.
 * NOTE: If typ is end status (e.g. DELIVERED) then dlr entry
 *       will be removed from DB.
 */
Msg *dlr_find(const Octstr *smsc, const Octstr *ts, const Octstr *dst, int typ)
{
    Msg	*msg = NULL;
    struct dlr_entry *dlr = NULL;
    
    if(octstr_len(smsc) == 0) {
	warning(0, "DLR[%s]: Can't find a dlr without smsc-id", dlr_type());
        return NULL;
    }

    /* check if we have handler registered */
    if (handles == NULL || handles->dlr_get == NULL)
        return NULL;

    debug("dlr.dlr", 0, "DLR[%s]: Looking for DLR smsc=%s, ts=%s, dst=%s, type=%d",
                                 dlr_type(), octstr_get_cstr(smsc), octstr_get_cstr(ts), octstr_get_cstr(dst), typ);

    dlr = handles->dlr_get(smsc, ts, dst);
    if (dlr == NULL)  {
        warning(0, "DLR[%s]: DLR from SMSC<%s> for DST<%s> not found.",
                dlr_type(), octstr_get_cstr(smsc), octstr_get_cstr(dst));         
        return NULL;
    }

#define O_SET(x, val) if (octstr_len(val) > 0) { x = val; val = NULL; }

    if ((typ & dlr->mask) > 0) {
        /* its an entry we are interested in */
        msg = msg_create(sms);
        msg->sms.sms_type = report_mo;
        msg->sms.dlr_mask = typ;
        O_SET(msg->sms.service, dlr->service);
        O_SET(msg->sms.smsc_id, dlr->smsc);
        O_SET(msg->sms.receiver, dlr->destination);
        O_SET(msg->sms.sender, dlr->source);
        /* if dlr_url was present, recode it here again */
        O_SET(msg->sms.dlr_url, dlr->url);
        /* add the foreign_id */
        msg->sms.foreign_id = octstr_duplicate(ts);
        /* 
         * insert original message to the data segment 
         * later in the smsc module 
         */
        msg->sms.msgdata = NULL;
        /* 
         * If a boxc_id is available, then instruct bearerbox to 
         * route this msg back to originating smsbox
         */
        O_SET(msg->sms.boxc_id, dlr->boxc_id);

        time(&msg->sms.time);
        debug("dlr.dlr", 0, "DLR[%s]: created DLR message for URL <%s>",
                      dlr_type(), (msg->sms.dlr_url?octstr_get_cstr(msg->sms.dlr_url):""));
    } else {
        debug("dlr.dlr", 0, "DLR[%s]: Ignoring DLR message because of mask type=%d dlr->mask=%d", dlr_type(), typ, dlr->mask);
        /* ok that was a status report but we where not interested in having it */
        msg = NULL;
    }

#undef O_SET
 
    /* check for end status and if so remove from storage */
    if ((typ & DLR_BUFFERED) && ((dlr->mask & DLR_SUCCESS) || (dlr->mask & DLR_FAIL))) {
        debug("dlr.dlr", 0, "DLR[%s]: DLR not destroyed, still waiting for other delivery report", dlr_type());
        /* update dlr entry status if function defined */
        if (handles != NULL && handles->dlr_update != NULL)
            handles->dlr_update(smsc, ts, dst, typ);
    } else {
        if (handles != NULL && handles->dlr_remove != NULL) {
            /* it's not good for internal storage, but better for all others */
            handles->dlr_remove(smsc, ts, dst);
        } else {
            warning(0, "DLR[%s]: Storage don't have remove operation defined", dlr_type());
        }
    }

    /* destroy struct dlr_entry */
    dlr_entry_destroy(dlr);

    return msg;
}
Exemple #11
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);
}
Exemple #12
0
/*
 * Adds a struct dlr_entry to the spool directory.
 */
static void dlr_spool_add(struct dlr_entry *dlr)
{
	Msg *msg;
	Octstr *os, *hash, *dir, *filename;
    int fd;
    size_t wrc;

#define MAP(to, from) \
	to = from; \
	from = NULL;

	/* create a common message structure to contain our values */
	msg = msg_create(sms);
	msg->sms.sms_type = report_mt;
	MAP(msg->sms.smsc_id, dlr->smsc);
	MAP(msg->sms.foreign_id, dlr->timestamp);
	MAP(msg->sms.sender, dlr->source);
	MAP(msg->sms.receiver, dlr->destination);
	MAP(msg->sms.service, dlr->service);
	MAP(msg->sms.dlr_url, dlr->url);
	MAP(msg->sms.boxc_id, dlr->boxc_id);
	msg->sms.dlr_mask = dlr->mask;

	/* we got all values, destroy the structure now */
	dlr_entry_destroy(dlr);

	/* create hash value */
	os = octstr_duplicate(msg->sms.smsc_id);
	octstr_append(os, msg->sms.foreign_id);
	hash = our_hash_func(os);
	octstr_destroy(os);

	/* target directory */
    dir = octstr_format("%S/%ld", spool_dir, octstr_hash_key(hash) % MAX_DIRS);
    if (mkdir(octstr_get_cstr(dir), S_IRUSR|S_IWUSR|S_IXUSR) == -1 && errno != EEXIST) {
        error(errno, "Could not create directory `%s'.", octstr_get_cstr(dir));
        octstr_destroy(dir);
        octstr_destroy(hash);
        return;
    }

    /*
     * Now also add the hex value of the destination.
     * This will be the part we look later into while
     * DLR resolving.
     */
    os = octstr_duplicate(msg->sms.receiver);
    octstr_binary_to_hex(os, 0);
    octstr_append(hash, os);
    octstr_destroy(os);

    /* target file */
    filename = octstr_format("%S/%S", dir, hash);
    octstr_destroy(dir);
    octstr_destroy(hash);
    if ((fd = open(octstr_get_cstr(filename), O_CREAT|O_EXCL|O_WRONLY, S_IRUSR|S_IWUSR)) == -1) {
        error(errno, "Could not open file `%s'.", octstr_get_cstr(filename));
        octstr_destroy(filename);
        return;
    }

    /* pack and write content to file */
    os = store_msg_pack(msg);
    msg_destroy(msg);
    for (wrc = 0; wrc < octstr_len(os); ) {
        size_t rc = write(fd, octstr_get_cstr(os) + wrc, octstr_len(os) - wrc);
        if (rc == -1) {
            /* remove file */
            error(errno, "Could not write DLR message to `%s'.", octstr_get_cstr(filename));
            close(fd);
            if (unlink(octstr_get_cstr(filename)) == -1)
                error(errno, "Oops, Could not remove failed file `%s'.", octstr_get_cstr(filename));
            octstr_destroy(os);
            octstr_destroy(filename);
            return;
        }
        wrc += rc;
    }
    close(fd);
    counter_increase(counter);
    octstr_destroy(filename);
    octstr_destroy(os);
}