static int sms_to_client(Connection *client, Msg *msg) { Octstr *line; Octstr *msgdata = NULL; /* NULL to allow octstr_destroy */ char *contents; int len; debug("bb.sms", 0, "smsc_fake: sending message to client"); // msg_dump(msg, 0); line = octstr_duplicate(msg->sms.sender); octstr_append_char(line, ' '); octstr_append(line, msg->sms.receiver); if (octstr_len(msg->sms.udhdata)) { octstr_append(line, octstr_imm(" udh ")); msgdata = octstr_duplicate(msg->sms.udhdata); octstr_url_encode(msgdata); octstr_append(line, msgdata); octstr_destroy(msgdata); octstr_append_char(line, ' '); msgdata = octstr_duplicate(msg->sms.msgdata); octstr_url_encode(msgdata); octstr_append(line, msgdata); } else { contents = octstr_get_cstr(msg->sms.msgdata); len = octstr_len(msg->sms.msgdata); while (len > 0) { len--; if (contents[len] < 32 || contents[len] > 126) { octstr_append(line, octstr_imm(" data ")); msgdata = octstr_duplicate(msg->sms.msgdata); octstr_url_encode(msgdata); octstr_append(line, msgdata); goto notelse; /* C lacks "else" clause for while loops */ } } octstr_append(line, octstr_imm(" text ")); octstr_append(line, msg->sms.msgdata); } notelse: octstr_append_char(line, 10); if (conn_write(client, line) == -1) { octstr_destroy(msgdata); octstr_destroy(line); return -1; } octstr_destroy(msgdata); octstr_destroy(line); return 1; }
static int sms_to_client(Connection *client, Msg *msg) { Octstr *line; Octstr *msgdata = NULL; /* NULL to allow octstr_destroy */ debug("bb.sms", 0, "smsc_fake: sending message to client"); /* msg_dump(msg, 0); */ line = octstr_duplicate(msg->sms.sender); octstr_append_char(line, ' '); octstr_append(line, msg->sms.receiver); if (octstr_len(msg->sms.udhdata)) { octstr_append(line, octstr_imm(" udh ")); msgdata = octstr_duplicate(msg->sms.udhdata); octstr_url_encode(msgdata); octstr_append(line, msgdata); octstr_destroy(msgdata); octstr_append(line, octstr_imm(" data ")); msgdata = octstr_duplicate(msg->sms.msgdata); octstr_url_encode(msgdata); octstr_append(line, msgdata); } else { if (msg->sms.coding == DC_8BIT) { octstr_append(line, octstr_imm(" data ")); msgdata = octstr_duplicate(msg->sms.msgdata); octstr_url_encode(msgdata); octstr_append(line, msgdata); } else if (msg->sms.coding == DC_UCS2) { octstr_append(line, octstr_imm(" ucs-2 ")); msgdata = octstr_duplicate(msg->sms.msgdata); octstr_url_encode(msgdata); octstr_append(line, msgdata); } else { octstr_append(line, octstr_imm(" text ")); octstr_append(line, msg->sms.msgdata); } } octstr_append_char(line, 10); if (conn_write(client, line) == -1) { octstr_destroy(msgdata); octstr_destroy(line); return -1; } octstr_destroy(msgdata); octstr_destroy(line); return 1; }
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); }
static void start_push(Octstr *rcpt_to, int isphonenum, MmsEnvelope *e, MmsMsg *msg) { List *pheaders; static unsigned char ct; /* Transaction counter -- do we need it? */ Octstr *to = NULL; Octstr *pduhdr = octstr_create(""); Octstr *s = NULL; info(0, "mms2mobile.startpush: notification to %s\n", octstr_get_cstr(rcpt_to)); if (!rcpt_to) { error(0, "mobilesender: Queue entry %s has no recipient address!", e->xqfname); goto done; } else to = octstr_duplicate(rcpt_to); ct++; octstr_append_char(pduhdr, ct); /* Pushd id */ octstr_append_char(pduhdr, 0x06); /* PUSH */ #if 1 octstr_append_char(pduhdr, 1 + 1 + 1); octstr_append_char(pduhdr, 0xbe); /* content type. */ #else octstr_append_char(pduhdr, 1 + 1 + sizeof "application/vnd.wap.mms-message"); /*header length. */ octstr_append_cstr(pduhdr, "application/vnd.wap.mms-message"); octstr_append_char(pduhdr, 0x0); /* string terminator. */ #endif octstr_append_char(pduhdr, 0xaf); /* push application ID header and value follows. */ octstr_append_char(pduhdr, 0x84); /* ... */ s = mms_tobinary(msg); if (isphonenum) { Octstr *url; octstr_url_encode(to); octstr_url_encode(s); #if 0 octstr_dump(pduhdr, 0); #endif octstr_url_encode(pduhdr); url = octstr_format("%S&text=%S%S&to=%S&udh=%%06%%05%%04%%0B%%84%%23%%F0", settings->sendsms_url, pduhdr, s, to); pheaders = http_create_empty_headers(); http_header_add(pheaders, "Connection", "close"); http_header_add(pheaders, "User-Agent", MM_NAME "/" MMSC_VERSION); http_start_request(httpcaller, HTTP_METHOD_GET, url, pheaders, NULL, 0, e, NULL); http_destroy_headers(pheaders); octstr_destroy(url); } else { /* An IP Address: Send packet, forget. */ Octstr *addr = udp_create_address(to, WAPPUSH_PORT); int sock = udp_client_socket(); if (sock > 0) { MmsEnvelopeTo *xto = gwlist_get(e->to,0); octstr_append(pduhdr, s); #if 0 octstr_dump(pduhdr, 0); #endif udp_sendto(sock, pduhdr, addr); close(sock); /* ?? */ mms_log2("Notify", octstr_imm("system"), to, -1, e ? e->msgId : NULL, NULL, NULL, "MM1", NULL,NULL); e = update_env_success(e, xto); } else { e = update_env_failed(e); error(0, "push to %s:%d failed: %s", octstr_get_cstr(to), WAPPUSH_PORT, strerror(errno)); } octstr_destroy(addr); if (e) settings->qfs->mms_queue_free_env(e); } done: octstr_destroy(to); octstr_destroy(pduhdr); octstr_destroy(s); }
static int sendNotify(MmsEnvelope *e) { Octstr *to; MmsMsg *msg, *smsg = NULL; MmsEnvelopeTo *xto = gwlist_get(e->to, 0); Octstr *err = NULL; time_t tnow = time(NULL); int j, k, len; Octstr *phonenum = NULL, *rcpt_ip = NULL, *msgId, *from, *fromproxy; int mtype, msize; int res = MMS_SEND_OK, dlr; time_t expiryt; char *prov_notify_event = NULL; char *rtype = NULL; if (e->lastaccess != 0) { /* This message has been fetched at least once, no more signals. */ e->sendt = e->expiryt + 3600*24*30*12; info(0, "MM1: Message [ID: %s] fetched/touched at least once. Skipping", e->xqfname); return settings->qfs->mms_queue_update(e); } if (!xto) { error(0, "mobilesender: Queue entry %s with no recipients!", e->xqfname); return 0; } msg = settings->qfs->mms_queue_getdata(e); to = octstr_duplicate(xto->rcpt); expiryt = e->expiryt; msgId = e->msgId ? octstr_duplicate(e->msgId) : NULL; from = octstr_duplicate(e->from); fromproxy = e->fromproxy ? octstr_duplicate(e->fromproxy) : NULL; msize = e->msize; dlr = e->dlr; if (e->expiryt != 0 && /* Handle message expiry. */ e->expiryt < tnow) { err = octstr_format("MMSC error: Message expired while sending to %S!", to); res = MMS_SEND_ERROR_FATAL; prov_notify_event = "failedfetch"; rtype = "Expired"; goto done; } else if (e->attempts >= settings->maxsendattempts) { err = octstr_format("MMSC error: Failed to deliver to %S after %ld attempts!", to, e->attempts); res = MMS_SEND_ERROR_FATAL; prov_notify_event = "failedfetch"; rtype = "Expired"; goto done; } j = octstr_case_search(to, octstr_imm("/TYPE=PLMN"), 0); k = octstr_case_search(to, octstr_imm("/TYPE=IPv"), 0); len = octstr_len(to); if (j > 0 && j - 1 + sizeof "/TYPE=PLMN" == len) { /* A proper number. */ phonenum = octstr_copy(to, 0, j); #if 0 normalize_number(octstr_get_cstr(settings->unified_prefix), &phonenum); #else mms_normalize_phonenum(&phonenum, octstr_get_cstr(settings->unified_prefix), settings->strip_prefixes); #endif } else if (k > 0 && k + sizeof "/TYPE=IPv" == len) rcpt_ip = octstr_copy(to, 0, k); else { /* We only handle phone numbers here. */ err = octstr_format("Unexpected recipient %s in MT queue!", octstr_get_cstr(to)); res = MMS_SEND_ERROR_FATAL; goto done; } mtype = mms_messagetype(msg); /* For phone, getting here means the message can be delivered. So: * - Check whether the recipient is provisioned, if not, wait (script called will queue creation req) * - If the recipient can't take MMS, then send SMS. */ /* We handle two types of requests: send and delivery/read notifications. * other types of messages cannot possibly be in this queue! */ if (mtype == MMS_MSGTYPE_SEND_REQ || mtype == MMS_MSGTYPE_RETRIEVE_CONF) { Octstr *url, *transid; if (phonenum) { int send_ind = mms_ind_send(settings->prov_getstatus, phonenum); if (send_ind < 0 && settings->notify_unprovisioned) send_ind = 0; if (send_ind < 0) { /* That is, recipient is not (yet) provisioned. */ res = MMS_SEND_ERROR_TRANSIENT; err = octstr_format("%S is not provisioned for MMS reception, delivery deferred!", phonenum); /* Do not increase delivery attempts counter. */ e->lasttry = tnow; e->sendt = e->lasttry + settings->send_back_off * (1 + e->attempts); if (settings->qfs->mms_queue_update(e) == 1) e = NULL; /* Queue entry gone. */ else settings->qfs->mms_queue_free_env(e); goto done; } else if (send_ind == 0) { /* provisioned but does not support */ Octstr *s = octstr_format(octstr_get_cstr(settings->mms_notify_txt), from); if (settings->notify_unprovisioned && s && octstr_len(s) > 0) { /* Only send if the string was set. */ List *pheaders; Octstr *sto = octstr_duplicate(phonenum); octstr_url_encode(s); octstr_url_encode(sto); url = octstr_format("%S&text=%S&to=%S",settings->sendsms_url,s, sto); pheaders = http_create_empty_headers(); http_header_add(pheaders, "Connection", "close"); http_header_add(pheaders, "User-Agent", MM_NAME "/" VERSION); http_start_request(httpcaller, HTTP_METHOD_GET, url, pheaders, NULL, 0, &edummy, NULL); http_destroy_headers(pheaders); octstr_destroy(url); octstr_destroy(sto); } else if (s) octstr_destroy(s); res = MMS_SEND_OK; err = octstr_imm("No MMS Ind support, sent SMS instead"); xto->process = 0; /* No more processing. */ if (settings->qfs->mms_queue_update(e) == 1) e = NULL; else settings->qfs->mms_queue_free_env(e); goto done; } } /* To get here means we can send Ind. */ url = mms_makefetchurl(e->xqfname, e->token, MMS_LOC_MQUEUE, phonenum ? phonenum : to, settings); info(0, "Preparing to notify client to fetch message at URL: %s", octstr_get_cstr(url)); transid = mms_maketransid(e->xqfname, settings->host_alias); smsg = mms_notification(msg, e->msize, url, transid, e->expiryt ? e->expiryt : tnow + settings->default_msgexpiry, settings->optimize_notification_size); octstr_destroy(transid); octstr_destroy(url); } else if (mtype == MMS_MSGTYPE_DELIVERY_IND || mtype == MMS_MSGTYPE_READ_ORIG_IND) smsg = msg; else { error(0, "Unexpected message type %s for %s found in MT queue!", mms_message_type_to_cstr(mtype), octstr_get_cstr(to)); res = MMS_SEND_ERROR_FATAL; goto done; } if (smsg) start_push(phonenum ? phonenum : rcpt_ip, phonenum ? 1 : 0, e, smsg); /* Send the message. * Don't touch 'e' after this point! * It may be freed by receive thread. */ if (smsg != msg && smsg) mms_destroy(smsg); done: if (err != NULL && res != MMS_SEND_ERROR_TRANSIENT) { /* If there was a report request and this is a legit error * queue it. */ if (dlr) { MmsMsg *m = mms_deliveryreport(msgId, to, tnow, rtype ? octstr_imm(rtype) : octstr_imm("Indeterminate")); List *l = gwlist_create(); Octstr *res; gwlist_append(l, from); /* Add to queue, switch via proxy to be from proxy. */ res = settings->qfs->mms_queue_add(to ? to : settings->system_user, l, err, NULL, fromproxy, tnow, tnow+settings->default_msgexpiry, m, NULL, NULL, NULL, NULL, NULL, NULL, 0, octstr_get_cstr(settings->mm1_queuedir), "MM2", settings->host_alias); gwlist_destroy(l, NULL); mms_destroy(m); octstr_destroy(res); } } /* Write to log */ info(0, "%s Mobile Queue MMS Send Notify: From=%s, to=%s, msgsize=%d, reason=%s", SEND_ERROR_STR(res), octstr_get_cstr(from), octstr_get_cstr(to), msize, err ? octstr_get_cstr(err) : ""); if (res == MMS_SEND_ERROR_FATAL) { xto->process = 0; /* No more attempts to deliver, delete this. */ if (settings->qfs->mms_queue_update(e) == 1) e = NULL; /* Queue entry gone. */ else settings->qfs->mms_queue_free_env(e); } /* Else queue will be updated/freed elsewhere. */ if (prov_notify_event) notify_prov_server(octstr_get_cstr(settings->prov_notify), to ? octstr_get_cstr(to) : "unknown", prov_notify_event, rtype ? rtype : "", e ? e->msgId : NULL, NULL, NULL); if (msg) mms_destroy(msg); octstr_destroy(phonenum); octstr_destroy(rcpt_ip); octstr_destroy(to); octstr_destroy(msgId); octstr_destroy(fromproxy); octstr_destroy(from); octstr_destroy(err); return 1; }
Octstr *urltrans_fill_escape_codes(Octstr *pattern, Msg *request) { Octstr *enc; Octstr *meta_group, *meta_param; int nextarg, j; struct tm tm; int num_words; List *word_list; Octstr *result; long pattern_len; long pos; int c; long i, k; Octstr *temp; result = octstr_create(""); if (request->sms.msgdata) { word_list = octstr_split_words(request->sms.msgdata); num_words = gwlist_len(word_list); } else { word_list = gwlist_create(); num_words = 0; } pattern_len = octstr_len(pattern); nextarg = 1; pos = 0; for (;;) { while (pos < pattern_len) { c = octstr_get_char(pattern, pos); if (c == '%' && pos + 1 < pattern_len) break; octstr_append_char(result, c); ++pos; } if (pos == pattern_len) break; switch (octstr_get_char(pattern, pos + 1)) { case 'a': for (j = 0; j < num_words; ++j) { enc = octstr_duplicate(gwlist_get(word_list, j)); octstr_url_encode(enc); if (j > 0) octstr_append_char(result, '+'); octstr_append(result, enc); octstr_destroy(enc); } break; case 'A': if (request->sms.msgdata) { enc = octstr_duplicate(request->sms.msgdata); octstr_url_encode(enc); octstr_append(result, enc); octstr_destroy(enc); } break; case 'b': enc = octstr_duplicate(request->sms.msgdata); octstr_url_encode(enc); octstr_append(result, enc); octstr_destroy(enc); break; case 'B': /* billing identifier/information */ if (octstr_len(request->sms.binfo)) { enc = octstr_duplicate(request->sms.binfo); octstr_url_encode(enc); octstr_append(result, enc); octstr_destroy(enc); } break; case 'c': octstr_append_decimal(result, request->sms.coding); break; case 'C': if (octstr_len(request->sms.charset)) { octstr_append(result, request->sms.charset); } else { switch (request->sms.coding) { case DC_UNDEF: case DC_7BIT: octstr_append(result, octstr_imm("UTF-8")); break; case DC_8BIT: octstr_append(result, octstr_imm("8-BIT")); break; case DC_UCS2: octstr_append(result, octstr_imm("UTF-16BE")); break; } } break; case 'd': enc = octstr_create(""); octstr_append_decimal(enc, request->sms.dlr_mask); octstr_url_encode(enc); octstr_append(result, enc); octstr_destroy(enc); break; case 'D': /* meta_data */ if (octstr_len(request->sms.meta_data)) { enc = octstr_duplicate(request->sms.meta_data); octstr_url_encode(enc); octstr_append(result, enc); octstr_destroy(enc); } break; case 'f': /* smsc number*/ if (octstr_len(request->sms.smsc_number)) { enc = octstr_duplicate(request->sms.smsc_number); octstr_url_encode(enc); octstr_append(result, enc); octstr_destroy(enc); } break; case 'F': if (request->sms.foreign_id == NULL) break; enc = octstr_duplicate(request->sms.foreign_id); octstr_url_encode(enc); octstr_append(result, enc); octstr_destroy(enc); break; case 'i': if (request->sms.smsc_id == NULL) break; enc = octstr_duplicate(request->sms.smsc_id); octstr_url_encode(enc); octstr_append(result, enc); octstr_destroy(enc); break; case 'I': if (!uuid_is_null(request->sms.id)) { char id[UUID_STR_LEN + 1]; uuid_unparse(request->sms.id, id); octstr_append_cstr(result, id); } break; case 'k': if (num_words <= 0) break; enc = octstr_duplicate(gwlist_get(word_list, 0)); octstr_url_encode(enc); octstr_append(result, enc); octstr_destroy(enc); break; case 'm': /* mclass - message class */ enc = octstr_create(""); octstr_append_decimal(enc, request->sms.mclass); octstr_url_encode(enc); octstr_append(result, enc); octstr_destroy(enc); break; case 'M': /* mwi - message waiting indicator */ enc = octstr_create(""); octstr_append_decimal(enc, request->sms.mwi); octstr_url_encode(enc); octstr_append(result, enc); octstr_destroy(enc); break; case 'n': if (request->sms.service == NULL) break; enc = octstr_duplicate(request->sms.service); octstr_url_encode(enc); octstr_append(result, enc); octstr_destroy(enc); break; case 'o': /* account information (may be operator id for aggregators */ if (octstr_len(request->sms.account)) { enc = octstr_duplicate(request->sms.account); octstr_url_encode(enc); octstr_append(result, enc); octstr_destroy(enc); } break; case 'O': /* DCS */ { int dcs; dcs = fields_to_dcs(request, request->sms.alt_dcs); octstr_format_append(result, "%02d", dcs); break; } /* NOTE: the sender and receiver is already switched in * message, so that's why we must use 'sender' when * we want original receiver and vice versa */ case 'P': enc = octstr_duplicate(request->sms.sender); octstr_url_encode(enc); octstr_append(result, enc); octstr_destroy(enc); break; case 'p': enc = octstr_duplicate(request->sms.receiver); octstr_url_encode(enc); octstr_append(result, enc); octstr_destroy(enc); break; case 'q': if (strncmp(octstr_get_cstr(request->sms.receiver),"00",2)==0) { enc = octstr_copy(request->sms.receiver, 2, octstr_len(request->sms.receiver)); octstr_url_encode(enc); octstr_format_append(result, "%%2B%S", enc); octstr_destroy(enc); } else { enc = octstr_duplicate(request->sms.receiver); octstr_url_encode(enc); octstr_append(result, enc); octstr_destroy(enc); } break; case 'Q': if (strncmp(octstr_get_cstr(request->sms.sender), "00", 2) == 0) { enc = octstr_copy(request->sms.sender, 2, octstr_len(request->sms.sender)); octstr_url_encode(enc); octstr_format_append(result, "%%2B%S", enc); octstr_destroy(enc); } else { enc = octstr_duplicate(request->sms.sender); octstr_url_encode(enc); octstr_append(result, enc); octstr_destroy(enc); } break; case 'r': for (j = nextarg; j < num_words; ++j) { enc = octstr_duplicate(gwlist_get(word_list, j)); octstr_url_encode(enc); if (j != nextarg) octstr_append_char(result, '+'); octstr_append(result, enc); octstr_destroy(enc); } break; case 'R': /* dlr_url */ if (octstr_len(request->sms.dlr_url)) { enc = octstr_duplicate(request->sms.dlr_url); octstr_url_encode(enc); octstr_append(result, enc); octstr_destroy(enc); } break; case 's': if (nextarg >= num_words) break; enc = octstr_duplicate(gwlist_get(word_list, nextarg)); octstr_url_encode(enc); octstr_append(result, enc); octstr_destroy(enc); ++nextarg; break; case 'S': if (nextarg >= num_words) break; temp = gwlist_get(word_list, nextarg); for (i = 0; i < octstr_len(temp); ++i) { if (octstr_get_char(temp, i) == '*') octstr_append_char(result, '~'); else octstr_append_char(result, octstr_get_char(temp, i)); } ++nextarg; break; case 't': tm = gw_gmtime(request->sms.time); octstr_format_append(result, "%04d-%02d-%02d+%02d:%02d:%02d", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); break; case 'T': if (request->sms.time == MSG_PARAM_UNDEFINED) break; octstr_format_append(result, "%ld", request->sms.time); break; case 'u': if(octstr_len(request->sms.udhdata)) { enc = octstr_duplicate(request->sms.udhdata); octstr_url_encode(enc); octstr_append(result, enc); octstr_destroy(enc); } break; case 'v': if (request->sms.validity != MSG_PARAM_UNDEFINED) { octstr_format_append(result, "%ld", (request->sms.validity - time(NULL)) / 60); } break; case 'V': if (request->sms.deferred != MSG_PARAM_UNDEFINED) { octstr_format_append(result, "%ld", (request->sms.deferred - time(NULL)) / 60); } break; /* * This allows to pass meta-data individual parameters into urls. * The syntax is as follows: %#group#parameter# * For example: %#smpp#my_param# would be replaced with the value * 'my_param' from the group 'smpp' coming inside the meta_data field. */ case '#': /* ASCII 0x23 == '#' */ k = octstr_search_char(pattern, 0x23, pos + 2); if (k >= 0) { pos += 2; meta_group = octstr_copy(pattern, pos, (k-pos)); pos = k + 1; k = octstr_search_char(pattern, 0x23, pos); if (k >= 0) { meta_param = octstr_copy(pattern, pos, (k-pos)); pos = k - 1; if (request->sms.meta_data != NULL) { enc = meta_data_get_value(request->sms.meta_data, octstr_get_cstr(meta_group), meta_param); octstr_url_encode(enc); octstr_append(result, enc); octstr_destroy(enc); } octstr_destroy(meta_param); } else { pos++; } octstr_destroy(meta_group); } break; /* XXX sms.parameters not present in here: * * pid - will we receive this ? * * alt-dcs - shouldn't be required unless we want to inform * which alt-dcs external server should use back * * compress - if we use compression, probably kannel would * decompress and reset this to 0. not required * * rpi - we don't receive these from smsc * * username, password, dlr-url, account - nonsense to send */ case '%': octstr_format_append(result, "%%"); break; default: octstr_format_append(result, "%%%c", octstr_get_char(pattern, pos + 1)); break; } pos += 2; } gwlist_destroy(word_list, octstr_destroy_item); return result; }
int main(int argc, char **argv) { int i, opt, num_threads; Octstr *proxy; List *exceptions; long proxy_port; int proxy_ssl = 0; Octstr *proxy_username; Octstr *proxy_password; Octstr *exceptions_regex; char *p; long threads[MAX_THREADS]; time_t start, end; double run_time; FILE *fp; int ssl = 0; gwlib_init(); proxy = NULL; proxy_port = -1; exceptions = gwlist_create(); proxy_username = NULL; proxy_password = NULL; exceptions_regex = NULL; num_threads = 1; file = 0; fp = NULL; while ((opt = getopt(argc, argv, "hv:qr:p:P:Se:t:i:a:u:sc:H:B:m:f")) != EOF) { switch (opt) { case 'v': log_set_output_level(atoi(optarg)); break; case 'q': verbose = 0; break; case 'r': max_requests = atoi(optarg); break; case 't': num_threads = atoi(optarg); if (num_threads > MAX_THREADS) num_threads = MAX_THREADS; break; case 'i': interval = atof(optarg); break; case 'u': file = 1; fp = fopen(optarg, "a"); if (fp == NULL) panic(0, "Cannot open message text file %s", optarg); msg_text = octstr_read_file(optarg); if (msg_text == NULL) panic(0, "Cannot read message text"); debug("", 0, "message text is"); octstr_dump(msg_text, 0); octstr_url_encode(msg_text); fclose(fp); break; case 'h': help(); exit(0); case 'p': proxy = octstr_create(optarg); break; case 'P': proxy_port = atoi(optarg); break; case 'S': proxy_ssl = 1; break; case 'e': p = strtok(optarg, ":"); while (p != NULL) { gwlist_append(exceptions, octstr_create(p)); p = strtok(NULL, ":"); } break; case 'E': exceptions_regex = octstr_create(optarg); break; case 'a': p = strtok(optarg, ":"); if (p != NULL) { auth_username = octstr_create(p); p = strtok(NULL, ""); if (p != NULL) auth_password = octstr_create(p); } break; case 's': ssl = 1; break; case 'c': octstr_destroy(ssl_client_certkey_file); ssl_client_certkey_file = octstr_create(optarg); break; case 'H': fp = fopen(optarg, "a"); if (fp == NULL) panic(0, "Cannot open header text file %s", optarg); extra_headers = octstr_read_file(optarg); if (extra_headers == NULL) panic(0, "Cannot read header text"); debug("", 0, "headers are"); octstr_dump(extra_headers, 0); split_headers(extra_headers, &split); fclose(fp); break; case 'B': content_file = octstr_create(optarg); break; case 'm': method_name = octstr_create(optarg); break; case 'f': follow_redirect = 0; break; case '?': default: error(0, "Invalid option %c", opt); help(); panic(0, "Stopping."); } } if (optind == argc) { help(); exit(0); } #ifdef HAVE_LIBSSL /* * check if we are doing a SSL-enabled client version here * load the required cert and key file */ if (ssl || proxy_ssl) { if (ssl_client_certkey_file != NULL) { use_global_client_certkey_file(ssl_client_certkey_file); } else { panic(0, "client certkey file need to be given!"); } } #endif if (method_name != NULL) { method = http_name2method(method_name); } if (proxy != NULL && proxy_port > 0) { http_use_proxy(proxy, proxy_port, proxy_ssl, exceptions, proxy_username, proxy_password, exceptions_regex); } octstr_destroy(proxy); octstr_destroy(proxy_username); octstr_destroy(proxy_password); octstr_destroy(exceptions_regex); gwlist_destroy(exceptions, octstr_destroy_item); urls = argv + optind; num_urls = argc - optind; time(&start); if (num_threads == 1) client_thread(http_caller_create()); else { for (i = 0; i < num_threads; ++i) threads[i] = gwthread_create(client_thread, http_caller_create()); for (i = 0; i < num_threads; ++i) gwthread_join(threads[i]); } time(&end); run_time = difftime(end, start); info(0, "%ld requests in %f seconds, %f requests/s.", (max_requests * num_threads), run_time, (max_requests * num_threads) / run_time); octstr_destroy(ssl_client_certkey_file); octstr_destroy(auth_username); octstr_destroy(auth_password); octstr_destroy(extra_headers); octstr_destroy(content_file); gwlist_destroy(split, octstr_destroy_item); gwlib_shutdown(); return 0; }
/* * Trans being NULL means that we are servicing ppg (doing dlr, but this does not * concern us here). */ Octstr *urltrans_get_pattern(URLTranslation *t, Msg *request) { Octstr *enc; int nextarg, j; struct tm tm; int num_words; List *word_list; Octstr *result, *pattern; long pattern_len; long pos; int c; long i; Octstr *temp; Octstr *url, *reply; /* For and If delivery report */ url = reply = NULL; if (request->sms.sms_type != report_mo && t->type == TRANSTYPE_SENDSMS) return octstr_create(""); if (request->sms.msgdata) { word_list = octstr_split_words(request->sms.msgdata); num_words = list_len(word_list); } else { word_list = list_create(); num_words = 0; } result = octstr_create(""); /* check if this is a delivery report message or not */ if (request->sms.sms_type != report_mo) { pattern = t->pattern; } else { /* this is a DLR message */ reply = octstr_duplicate(request->sms.msgdata); url = octstr_duplicate(request->sms.dlr_url); pattern = url; if (octstr_len(pattern) == 0) { if (t && octstr_len(t->dlr_url)) { pattern = t->dlr_url; } else { list_destroy(word_list, octstr_destroy_item); return octstr_create(""); } } } pattern_len = octstr_len(pattern); nextarg = 1; pos = 0; for (;;) { while (pos < pattern_len) { c = octstr_get_char(pattern, pos); if (c == '%' && pos + 1 < pattern_len) break; octstr_append_char(result, c); ++pos; } if (pos == pattern_len) break; switch (octstr_get_char(pattern, pos + 1)) { case 'k': if (num_words <= 0) break; enc = octstr_duplicate(list_get(word_list, 0)); octstr_url_encode(enc); octstr_append(result, enc); octstr_destroy(enc); break; case 's': if (nextarg >= num_words) break; enc = octstr_duplicate(list_get(word_list, nextarg)); octstr_url_encode(enc); octstr_append(result, enc); octstr_destroy(enc); ++nextarg; break; case 'S': if (nextarg >= num_words) break; temp = list_get(word_list, nextarg); for (i = 0; i < octstr_len(temp); ++i) { if (octstr_get_char(temp, i) == '*') octstr_append_char(result, '~'); else octstr_append_char(result, octstr_get_char(temp, i)); } ++nextarg; break; case 'r': for (j = nextarg; j < num_words; ++j) { enc = octstr_duplicate(list_get(word_list, j)); octstr_url_encode(enc); if (j != nextarg) octstr_append_char(result, '+'); octstr_append(result, enc); octstr_destroy(enc); } break; /* NOTE: the sender and receiver is already switched in * message, so that's why we must use 'sender' when * we want original receiver and vice versa */ case 'P': enc = octstr_duplicate(request->sms.sender); octstr_url_encode(enc); octstr_append(result, enc); octstr_destroy(enc); break; case 'p': enc = octstr_duplicate(request->sms.receiver); octstr_url_encode(enc); octstr_append(result, enc); octstr_destroy(enc); break; case 'Q': if (strncmp(octstr_get_cstr(request->sms.sender), "00", 2) == 0) { enc = octstr_copy(request->sms.sender, 2, octstr_len(request->sms.sender)); octstr_url_encode(enc); octstr_format_append(result, "%%2B%S", enc); octstr_destroy(enc); } else { enc = octstr_duplicate(request->sms.sender); octstr_url_encode(enc); octstr_append(result, enc); octstr_destroy(enc); } break; case 'q': if (strncmp(octstr_get_cstr(request->sms.receiver),"00",2)==0) { enc = octstr_copy(request->sms.receiver, 2, octstr_len(request->sms.receiver)); octstr_url_encode(enc); octstr_format_append(result, "%%2B%S", enc); octstr_destroy(enc); } else { enc = octstr_duplicate(request->sms.receiver); octstr_url_encode(enc); octstr_append(result, enc); octstr_destroy(enc); } break; case 'a': for (j = 0; j < num_words; ++j) { enc = octstr_duplicate(list_get(word_list, j)); octstr_url_encode(enc); if (j > 0) octstr_append_char(result, '+'); octstr_append(result, enc); octstr_destroy(enc); } break; case 'b': enc = octstr_duplicate(request->sms.msgdata); octstr_url_encode(enc); octstr_append(result, enc); octstr_destroy(enc); break; case 't': tm = gw_gmtime(request->sms.time); octstr_format_append(result, "%04d-%02d-%02d+%02d:%02d:%02d", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); break; case 'T': if (request->sms.time == MSG_PARAM_UNDEFINED) break; octstr_format_append(result, "%ld", request->sms.time); break; case 'i': if (request->sms.smsc_id == NULL) break; enc = octstr_duplicate(request->sms.smsc_id); octstr_url_encode(enc); octstr_append(result, enc); octstr_destroy(enc); break; case 'I': if (!uuid_is_null(request->sms.id)) { char id[UUID_STR_LEN + 1]; uuid_unparse(request->sms.id, id); octstr_append_cstr(result, id); } break; case 'n': if (request->sms.service == NULL) break; enc = octstr_duplicate(request->sms.service); octstr_url_encode(enc); octstr_append(result, enc); octstr_destroy(enc); break; case 'd': enc = octstr_create(""); octstr_append_decimal(enc, request->sms.dlr_mask); octstr_url_encode(enc); octstr_append(result, enc); octstr_destroy(enc); break; case 'A': if (reply) { enc = octstr_duplicate(reply); octstr_url_encode(enc); octstr_append(result, enc); octstr_destroy(enc); } break; case 'c': octstr_append_decimal(result, request->sms.coding); break; case 'C': if(octstr_len(request->sms.charset)) { octstr_append(result, request->sms.charset); } else { switch (request->sms.coding) { case DC_UNDEF: case DC_7BIT: octstr_append(result, octstr_imm("ISO-8859-1")); break; case DC_8BIT: octstr_append(result, octstr_imm("8-BIT")); break; case DC_UCS2: octstr_append(result, octstr_imm("UTF16-BE")); break; } } break; case 'u': if(octstr_len(request->sms.udhdata)) { enc = octstr_duplicate(request->sms.udhdata); octstr_url_encode(enc); octstr_append(result, enc); octstr_destroy(enc); } break; case 'B': /* billing identifier/information */ if (octstr_len(request->sms.binfo)) { enc = octstr_duplicate(request->sms.binfo); octstr_url_encode(enc); octstr_append(result, enc); octstr_destroy(enc); } break; case 'o': /* account information (may be operator id for aggregators */ if (octstr_len(request->sms.account)) { enc = octstr_duplicate(request->sms.account); octstr_url_encode(enc); octstr_append(result, enc); octstr_destroy(enc); } break; /* XXX sms.parameters not present in here: * * pid - will we receive this ? * * mwi,mclass - will we receive these bits from smsc ? * * alt-dcs - shouldn't be required unless we want to inform * which alt-dcs external server should use back * * compress - if we use compression, probably kannel would * decompress and reset this to 0. not required * * validity, deferred, rpi - we don't receive these from smsc * * username, password, dlr-url, account - nonsense to send */ case '%': octstr_format_append(result, "%%"); break; default: octstr_format_append(result, "%%%c", octstr_get_char(pattern, pos + 1)); break; } pos += 2; } /* * this SHOULD be done in smsbox, not here, but well, * much easier to do here */ if (t && (t->type == TRANSTYPE_POST_URL || t->type == TRANSTYPE_POST_XML) && t->strip_keyword) strip_keyword(request); octstr_destroy(url); octstr_destroy(reply); list_destroy(word_list, octstr_destroy_item); return result; }