The patch is based on snapshot version 20031105.
So tell me what do I need to do in order to get the patch committed? Updated User manual? Sample configuration files?
Cheers, Phuah Yee Keat
diff -Naur kannel-snapshot/gw/smsc/smsc_cpa.c kannel-snapshot-cpa/gw/smsc/smsc_cpa.c
--- kannel-snapshot/gw/smsc/smsc_cpa.c 1970-01-01 07:30:00.000000000 +0730
+++ kannel-snapshot-cpa/gw/smsc/smsc_cpa.c 2004-01-14 11:42:29.000000000 +0800
@@ -0,0 +1,745 @@
+/*
+ * smsc_cpa.c - interface to DIGI CPA
+ *
+ * this file is copied and modified from smsc_http
+ * coz we need to add a couple of stuffs to the ConnData
+ * and a couple of additional configuration parameters too!
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#include <errno.h>
+#include <time.h>
+#include <limits.h>
+
+#include "gwlib/gwlib.h"
+#include "smscconn.h"
+#include "smscconn_p.h"
+#include "bb_smscconn_cb.h"
+#include "msg.h"
+#include "sms.h"
+#include "dlr.h"
+
+/****
+ * Start of CPA stuffs
+ ****/
+typedef struct {
+ HTTPCaller *http_ref;
+ long receive_thread;
+ long send_cb_thread;
+ long login_cb_thread;
+ long login_thread;
+ long http_result_thread;
+ int shutdown;
+ int port; /* port for receiving SMS'es */
+ Octstr *receive_host;
+ Octstr *allow_ip;
+ Octstr *send_url;
+ Octstr *login_url;
+ long open_sends;
+ Octstr *username; /* if needed */
+ Octstr *password; /* as said */
+ Octstr *cp_id;
+ Octstr *service_id;
+ Octstr *short_code;
+ Octstr *session_id;
+ Octstr *prepaid_price_code;
+ Octstr *postpaid_price_code;
+ Octstr *charge_party;
+ int elapse_time; /* number of minutes, before we need to relogin */
+ int logged_in;
+
+ int no_sender; /* ditto */
+ int no_coding; /* this, too */
+ int no_sep; /* not to mention this */
+
+ /* callback functions set by HTTP-SMSC type */
+ void (*send_sms) (SMSCConn *conn, Msg *msg);
+ void (*parse_reply) (SMSCConn *conn, Msg *msg, int status,
+ List *headers, Octstr *body);
+ void (*receive_sms) (SMSCConn *conn, HTTPClient *client,
+ List *headers, Octstr *body, List *cgivars);
+} CPA;
+
+static void cpa_destroy(CPA *cpa)
+{
+ if (cpa == NULL)
+ return;
+ if (cpa->http_ref)
+ http_caller_destroy(cpa->http_ref);
+ octstr_destroy(cpa->receive_host);
+ octstr_destroy(cpa->allow_ip);
+ octstr_destroy(cpa->send_url);
+ octstr_destroy(cpa->login_url);
+ octstr_destroy(cpa->username);
+ octstr_destroy(cpa->password);
+ octstr_destroy(cpa->cp_id);
+ octstr_destroy(cpa->service_id);
+ octstr_destroy(cpa->short_code);
+ octstr_destroy(cpa->session_id);
+ octstr_destroy(cpa->prepaid_price_code);
+ octstr_destroy(cpa->postpaid_price_code);
+ octstr_destroy(cpa->charge_party);
+
+ gw_free(cpa);
+}
+
+typedef enum { TYPE_LOGIN, TYPE_SENDSMS } CPAType;
+
+typedef struct {
+ CPAType type;
+ /* here are a couple of stuffs, only to be used for the appropriate type */
+ Msg *msg; /* type == TYPE_SENDSMS */
+} CPAResponse;
+
+static void send_login(CPA *cpa)
+{
+ Octstr *response_url;
+ List *headers;
+ CPAResponse *cpa_response;
+
+ response_url = octstr_format("http://%S:%d/login_rsp", cpa->receive_host,
cpa->port);
+ octstr_url_encode(response_url);
+
+ headers = http_create_empty_headers();
+ http_header_add(headers, "cpa_login_name", octstr_get_cstr(cpa->username));
+ http_header_add(headers, "cpa_password", octstr_get_cstr(cpa->password));
+ http_header_add(headers, "cpa_cp_id", octstr_get_cstr(cpa->cp_id));
+ http_header_add(headers, "cpa_cp_response_url", octstr_get_cstr(response_url));
+
+ cpa_response = gw_malloc(sizeof(CPAResponse));
+ cpa_response->type = TYPE_LOGIN;
+ cpa_response->msg = NULL;
+
+ http_start_request(cpa->http_ref, HTTP_METHOD_GET, cpa->login_url, headers,
+ NULL, 0, cpa_response, NULL);
+
+ octstr_destroy(response_url);
+ http_destroy_headers(headers);
+}
+
+static void cpa_http_receive_result(void *arg)
+{
+ SMSCConn *conn = arg;
+ CPA *cpa = conn->data;
+ int status;
+ List *headers;
+ Octstr *final_url, *body;
+ CPAResponse *cpa_response;
+
+ while (cpa->shutdown == 0) {
+ cpa_response = http_receive_result(cpa->http_ref, &status,
+ &final_url, &headers, &body);
+
+ //http_header_dump(headers);
+
+ /* we have no use for these! clean them up so we can have mutliple exit
points */
+ http_destroy_headers(headers);
+ octstr_destroy(final_url);
+ octstr_destroy(body);
+
+ if (cpa_response == NULL) {
+ break;
+ }
+
+ if (cpa->shutdown == 1) {
+ /* duh, we have waited too long, until we are supposed to shutdown! */
+ break;
+ }
+
+ if (status == -1) {
+ /* something is terribly wrong with the connection */
+ /* TODO : if we get status = -1 more than 3 times, declare disconnected
and try to relogin */
+ }
+
+ switch (cpa_response->type) {
+ case TYPE_LOGIN:
+ if (status!=HTTP_OK) {
+ error(0, "CPA[%s]: received http_status [%d] for login request",
+ octstr_get_cstr(conn->id), status);
+ conn->status = SMSCCONN_RECONNECTING;
+ /* login_manager will relogin for us */
+ cpa->logged_in = 0;
+ } else {
+ debug("smsc.cpa", 0, "CPA[%s]: received HTTP_OK for login
request, "
+ "but doesn't mean that we are successfully logged in!",
+ octstr_get_cstr(conn->id));
+ }
+ break;
+ case TYPE_SENDSMS:
+ if (status!=HTTP_OK) {
+ error(0, "CPA[%s]: received http_status [%d] for sendsms request",
+ octstr_get_cstr(conn->id), status);
+
+ /*
+ * be a bit gentle to the smsc, and sleep
+ * this will block this whole thread, even the login_response
+ * but what the heck, if the smsc is not replying HTTP_OK
+ * something is terribly wrong with it! (probably some java
error! keke)
+ */
+ gwthread_sleep(conn->reconnect_delay);
+ debug("smsc.cpa", 0, "CPA[%s]: Re-queuing message",
+ octstr_get_cstr(conn->id));
+
+ bb_smscconn_send_failed(conn, cpa_response->msg,
SMSCCONN_FAILED_TEMPORARILY, NULL);
+ } else {
+ debug("smsc.cpa", 0, "CPA[%s]: received HTTP_OK for sendsms
request, "
+ "but doesn't mean that we have successfully sent the
message!",
+ octstr_get_cstr(conn->id));
+ info(0, "CPA[%s]: since CPA did not send a usable id for matching
sendsms request, "
+ " we would have to settle for a sending success upon
receving HTTP_OK, "
+ " and just ignore the http_response!",
+ octstr_get_cstr(conn->id));
+ bb_smscconn_sent(conn, cpa_response->msg, NULL);
+ }
+ break;
+ }
+
+ gw_free(cpa_response);
+ }
+
+ debug("smsc.cpa", 0, "CPA[%s]: cpa_http_receive_result dying",
+ octstr_get_cstr(conn->id));
+ cpa->shutdown = 1;
+
+ if (cpa->open_sends) {
+ warning(0, "CPA[%s]: Shutdown while <%ld> requests are pending.",
+ octstr_get_cstr(conn->id), cpa->open_sends);
+ }
+
+ gwthread_join(cpa->receive_thread);
+
+ conn->data = NULL;
+ cpa_destroy(cpa);
+
+ conn->status = SMSCCONN_DEAD;
+ bb_smscconn_killed();
+}
+
+static void cpa_send_sms(SMSCConn *conn, Msg *sms)
+{
+ CPA *cpa = conn->data;
+ Octstr *response_url;
+ List *headers;
+ CPAResponse *cpa_response;
+
+ /* msg_dump(sms, 0); */
+ headers = list_create();
+
+ response_url = octstr_format("http://%S:%d/txn_rsp", cpa->receive_host,
cpa->port);
+
+ http_header_add(headers, "cpa_cp_id", octstr_get_cstr(cpa->cp_id));
+ http_header_add(headers, "cpa_cp_response_url", octstr_get_cstr(response_url));
+ http_header_add(headers, "cpa_cp_session_id", octstr_get_cstr(cpa->session_id));
+ http_header_add(headers, "cpa_short_code", octstr_get_cstr(cpa->short_code));
+
+ http_header_add(headers, "cpa_service_id", octstr_get_cstr(cpa->service_id));
+
+ /* sms push does not have transaction id */
+ /* XXX : does sms reply goes thru here also? if it does, we need to keep some
states! */
+ http_header_add(headers, "cpa_transaction_id", "");
+
+ /* told by CPA to set the source_mobtel to destination_mobtel */
+ http_header_add(headers, "cpa_source_mobtel", octstr_get_cstr(sms->sms.receiver));
+ http_header_add(headers, "cpa_destination_mobtel",
octstr_get_cstr(sms->sms.receiver));
+
+ http_header_add(headers, "cpa_charge_party", octstr_get_cstr(cpa->charge_party));
+
+ http_header_add(headers, "cpa_delivery_channel", "SMS");
+
+ http_header_add(headers, "cpa_prepaid_price_code",
octstr_get_cstr(cpa->prepaid_price_code));
+ http_header_add(headers, "cpa_postpaid_price_code",
octstr_get_cstr(cpa->postpaid_price_code));
+
+ http_header_add(headers, "cpa_interactive_push_session", "N");
+ http_header_add(headers, "cpa_terminate_interactive_sesion", "N");
+ http_header_add(headers, "cpa_status", "1");
+ http_header_add(headers, "cpa_content_sequence", "1");
+ http_header_add(headers, "cpa_max_content", "1");
+ http_header_add(headers, "cpa_content", octstr_get_cstr(sms->sms.msgdata));
+
+ debug("smsc.cpa", 0, "CPA[%s]: Start request",
+ octstr_get_cstr(conn->id));
+
+ cpa_response = gw_malloc(sizeof(CPAResponse));
+ cpa_response->type = TYPE_SENDSMS;
+ cpa_response->msg = msg_duplicate(sms);
+
+ //http_header_dump(headers);
+
+ http_start_request(cpa->http_ref, HTTP_METHOD_GET, cpa->send_url, headers,
+ NULL, 0, cpa_response, NULL);
+
+ octstr_destroy(response_url);
+ http_destroy_headers(headers);
+}
+
+static void cpa_receive_sms(SMSCConn *conn, HTTPClient *client,
+ List *headers, Octstr *body, List *cgivars)
+{
+ CPA *cpa = conn->data;
+ Octstr *retmsg;
+ List *reply_headers;
+ Octstr *cpa_short_code, *cpa_keyword, *cpa_service_id, *cpa_transaction_id,
*cpa_source_mobtel, *cpa_delivery_channel, *cpa_content, *cpa_sms_datacoding_id;
+ int ret;
+
+ //http_header_dump(headers);
+
+ cpa_short_code = http_header_value(headers, octstr_imm("cpa_short_code"));
+ cpa_keyword = http_header_value(headers, octstr_imm("cpa_keyword"));
+ cpa_service_id = http_header_value(headers, octstr_imm("cpa_service_id"));
+ cpa_transaction_id = http_header_value(headers,
octstr_imm("cpa_transaction_id"));
+ cpa_source_mobtel = http_header_value(headers, octstr_imm("cpa_source_mobtel"));
+ cpa_delivery_channel = http_header_value(headers,
octstr_imm("cpa_delivery_channel"));
+ cpa_content = http_header_value(headers, octstr_imm("cpa_content"));
+ cpa_sms_datacoding_id = http_header_value(headers,
octstr_imm("cpa_sms_datacoding_id"));
+
+ /* dump the response, so we can see more clearly from the logs! ;^) */
+ debug("smsc.cpa", 0, "CPA receive_sms response dump:");
+ debug("smsc.cpa", 0, " cpa_short_code: %s", octstr_get_cstr(cpa_short_code));
+ debug("smsc.cpa", 0, " cpa_keyword: %s", octstr_get_cstr(cpa_keyword));
+ debug("smsc.cpa", 0, " cpa_service_id: %s", octstr_get_cstr(cpa_service_id));
+ debug("smsc.cpa", 0, " cpa_transaction_id: %s",
octstr_get_cstr(cpa_transaction_id));
+ debug("smsc.cpa", 0, " cpa_source_mobtel: %s",
octstr_get_cstr(cpa_source_mobtel));
+ debug("smsc.cpa", 0, " cpa_delivery_channel: %s",
octstr_get_cstr(cpa_delivery_channel));
+ debug("smsc.cpa", 0, " cpa_content: %s", octstr_get_cstr(cpa_content));
+ debug("smsc.cpa", 0, " cpa_sms_datacoding_id: %s",
octstr_get_cstr(cpa_sms_datacoding_id));
+ debug("smsc.cpa", 0, "CPA receive_sms response dump ends.");
+
+ Msg *msg;
+ msg = msg_create(sms);
+
+ msg->sms.sender = octstr_duplicate(cpa_source_mobtel);
+ /* assume that the receiver is the short code value */
+ msg->sms.receiver = octstr_duplicate(cpa_short_code);
+ msg->sms.msgdata = octstr_duplicate(cpa_content);
+
+ msg->sms.smsc_id = octstr_duplicate(conn->id);
+ msg->sms.time = time(NULL);
+
+ ret = bb_smscconn_receive(conn, msg);
+
+ if (ret != SMSCCONN_SUCCESS) {
+ error(0, "CPA[%s]: bb_smscconn_receive failed.", octstr_get_cstr(conn->id));
+ }
+
+ retmsg = octstr_create("Ok.");
+
+ reply_headers = list_create();
+ http_header_add(reply_headers, "Content-Type", "text/plain");
+ debug("smsc.cpa", 0, "CPA[%s]: Sending reply",
+ octstr_get_cstr(conn->id));
+ http_send_reply(client, HTTP_OK, reply_headers, retmsg);
+
+ octstr_destroy(retmsg);
+ http_destroy_headers(reply_headers);
+
+ octstr_destroy(cpa_short_code);
+ octstr_destroy(cpa_keyword);
+ octstr_destroy(cpa_service_id);
+ octstr_destroy(cpa_transaction_id);
+ octstr_destroy(cpa_source_mobtel);
+ octstr_destroy(cpa_delivery_channel);
+ octstr_destroy(cpa_content);
+ octstr_destroy(cpa_sms_datacoding_id);
+}
+
+static void cpa_process_response(SMSCConn *conn, HTTPClient *client,
+ List *headers, Octstr *body, List *cgivars)
+{
+ CPA *cpa = conn->data;
+ Octstr *retmsg;
+ Octstr *cpa_service_id, *cpa_transaction_id, *cpa_destination_mobtel,
*cpa_charge_party, *cpa_status, *cpa_error_code;
+
+ List *reply_headers;
+
+ //http_header_dump(headers);
+
+ cpa_service_id = http_header_value(headers, octstr_imm("cpa_service_id"));
+ cpa_transaction_id = http_header_value(headers,
octstr_imm("cpa_transaction_id"));
+ cpa_destination_mobtel = http_header_value(headers,
octstr_imm("cpa_destination_mobtel"));
+ cpa_charge_party = http_header_value(headers, octstr_imm("cpa_charge_party"));
+ cpa_status = http_header_value(headers, octstr_imm("cpa_status"));
+ cpa_error_code = http_header_value(headers, octstr_imm("cpa_error_code"));
+
+ /* dump the response, so we can see more clearly from the logs! ;^) */
+ debug("smsc.cpa", 0, "CPA sendsms_response dump:");
+ debug("smsc.cpa", 0, " cpa_service_id: %s", octstr_get_cstr(cpa_service_id));
+ debug("smsc.cpa", 0, " cpa_transaction_id: %s",
octstr_get_cstr(cpa_transaction_id));
+ debug("smsc.cpa", 0, " cpa_destination_mobtel: %s",
octstr_get_cstr(cpa_destination_mobtel));
+ debug("smsc.cpa", 0, " cpa_charge_party: %s", octstr_get_cstr(cpa_charge_party));
+ debug("smsc.cpa", 0, " cpa_status: %s", octstr_get_cstr(cpa_status));
+ debug("smsc.cpa", 0, " cpa_error_code: %s", octstr_get_cstr(cpa_error_code));
+ debug("smsc.cpa", 0, "CPA sendsms_response dump ends.");
+
+ if (octstr_str_compare(cpa_status, "1")==0) {
+ info(0, "CPA[%s]: Message accepted", octstr_get_cstr(conn->id));
+ } else {
+ warning(0, "CPA[%s]: sendsms denied with status [%s] error_code [%s]",
+ octstr_get_cstr(conn->id),
+ octstr_get_cstr(cpa_status),
+ octstr_get_cstr(cpa_error_code));
+ }
+
+ retmsg = octstr_create("Ok.");
+
+ reply_headers = list_create();
+ http_header_add(reply_headers, "Content-Type", "text/plain");
+ debug("smsc.cpa", 0, "CPA[%s]: Sending reply",
+ octstr_get_cstr(conn->id));
+ http_send_reply(client, HTTP_OK, reply_headers, retmsg);
+
+ octstr_destroy(retmsg);
+ http_destroy_headers(reply_headers);
+
+ octstr_destroy(cpa_service_id);
+ octstr_destroy(cpa_transaction_id);
+ octstr_destroy(cpa_destination_mobtel);
+ octstr_destroy(cpa_charge_party);
+ octstr_destroy(cpa_status);
+ octstr_destroy(cpa_error_code);
+}
+
+static void cpa_process_login_response(SMSCConn *conn, HTTPClient *client,
+ List *headers, Octstr *body, List *cgivars)
+{
+ CPA *cpa = conn->data;
+ Octstr *retmsg;
+ Octstr *cpa_status, *cpa_error_code;
+ Octstr *tmp_string;
+ List *reply_headers;
+
+ cpa->session_id = http_header_value(headers, octstr_imm("cpa_cp_session_id"));
+ if (!cpa->session_id) {
+ error(0, "session_id not found in login-rsp");
+ }
+
+ tmp_string = http_header_value(headers,
octstr_imm("cpa_cp_session_elapse_time"));
+ if(tmp_string) {
+ sscanf(octstr_get_cstr(tmp_string),"%d", &cpa->elapse_time);
+ octstr_destroy(tmp_string);
+ } else {
+ error(0, "elapse_time not found in login-rsp");
+ }
+
+ cpa_status = http_header_value(headers, octstr_imm("cpa_status"));
+ cpa_error_code = http_header_value(headers, octstr_imm("cpa_error_code"));
+
+ /* dump the response, so we can see more clearly from the logs! ;^) */
+ debug("smsc.cpa", 0, "CPA login response dump:");
+ debug("smsc.cpa", 0, " cpa_cp_session_id: %s", octstr_get_cstr(cpa->session_id));
+ debug("smsc.cpa", 0, " cpa_cp_session_elapse_time: %d", cpa->elapse_time);
+ debug("smsc.cpa", 0, " cpa_status: %s", octstr_get_cstr(cpa_status));
+ debug("smsc.cpa", 0, " cpa_error_code: %s", octstr_get_cstr(cpa_error_code));
+ debug("smsc.cpa", 0, "CPA login response dump ends.");
+
+ if (octstr_str_compare(cpa_status, "1")==0) {
+ info(0, "CPA[%s]: Login accepted", octstr_get_cstr(conn->id));
+ conn->status = SMSCCONN_ACTIVE;
+ conn->connect_time = time(NULL);
+ bb_smscconn_connected(conn);
+
+ /* tell our login_manager to stop trying, ;-) */
+ cpa->logged_in = 1;
+ } else {
+ warning(0, "CPA[%s]: Login denied with status [%s] error_code [%s]",
+ octstr_get_cstr(conn->id),
+ octstr_get_cstr(cpa_status),
+ octstr_get_cstr(cpa_error_code));
+ }
+
+ retmsg = octstr_create("Ok.");
+
+ reply_headers = list_create();
+ http_header_add(reply_headers, "Content-Type", "text/plain");
+ debug("smsc.cpa", 0, "CPA[%s]: Sending reply",
+ octstr_get_cstr(conn->id));
+ http_send_reply(client, HTTP_OK, reply_headers, retmsg);
+
+ octstr_destroy(retmsg);
+ http_destroy_headers(reply_headers);
+
+ octstr_destroy(cpa_status);
+ octstr_destroy(cpa_error_code);
+}
+
+static void cpa_receiver(void *arg)
+{
+ SMSCConn *conn = arg;
+ CPA *cpa = conn->data;
+ HTTPClient *client;
+ Octstr *ip, *url, *body;
+ List *headers, *cgivars;
+
+ ip = url = body = NULL;
+ headers = cgivars = NULL;
+
+ /* Make sure we log into our own log-file if defined */
+ log_thread_to(conn->log_idx);
+
+ while (cpa->shutdown == 0) {
+
+ /* XXX if conn->is_stopped, do not receive new messages.. */
+
+ client = http_accept_request(cpa->port, &ip, &url,
+ &headers, &body, &cgivars);
+ if (client == NULL)
+ break;
+
+ debug("smsc.cpa", 0, "CPA[%s]: Got request `%s'",
+ octstr_get_cstr(conn->id), octstr_get_cstr(url));
+
+ if (connect_denied(cpa->allow_ip, ip)) {
+ info(0, "CPA[%s]: Connection `%s' tried from denied "
+ "host %s, ignored", octstr_get_cstr(conn->id),
+ octstr_get_cstr(url), octstr_get_cstr(ip));
+ http_close_client(client);
+ } else {
+ if (octstr_str_compare(url, "/txn_rsp")==0) {
+ cpa_process_response(conn, client, headers, body, cgivars);
+ } else if (octstr_str_compare(url, "/login_rsp")==0) {
+ cpa_process_login_response(conn, client, headers, body, cgivars);
+ } else if (octstr_str_compare(url, "/txn")==0) {
+ cpa_receive_sms(conn, client, headers, body, cgivars);
+ } else {
+ warning(0, "CPA[%s]: Invalid request", octstr_get_cstr(conn->id));
+ }
+ }
+
+ debug("smsc.cpa", 0, "CPA[%s]: Destroying client information",
+ octstr_get_cstr(conn->id));
+ octstr_destroy(url);
+ octstr_destroy(ip);
+ octstr_destroy(body);
+ http_destroy_headers(headers);
+ http_destroy_cgiargs(cgivars);
+ }
+ debug("smsc.cpa", 0, "CPA[%s]: httpsmsc_receiver dying",
+ octstr_get_cstr(conn->id));
+
+ cpa->shutdown = 1;
+ http_close_port(cpa->port);
+
+ /* unblock http_receive_result() if there are no open sends */
+ if (cpa->open_sends == 0)
+ http_caller_signal_shutdown(cpa->http_ref);
+}
+
+/* this handles the login and session
+ * will attempt to connect if not connected
+ * will attempt to connect again after elapse_time
+ * will set the session_id for use in sending MT messsages
+ */
+static void login_manager(void *arg)
+{
+ SMSCConn *conn = arg;
+ CPA *cpa = conn->data;
+
+ /* we will sleep this amount of time one time */
+ int sleep_seconds = 10;
+
+ /* this will keep track of how many seconds have we passed, since the last login
success */
+ int elapse_time_counter = 0;
+
+ debug("smsc.cpa", 0, "CPA[%s]: login manager started", octstr_get_cstr(conn->id));
+
+ /* TODO : tackle reconnect_delay config param */
+ while (cpa->shutdown == 0) {
+ if (! cpa->logged_in) {
+ /* we are not logged in, try to log in */
+ debug("smsc.cpa", 0, "CPA[%s]: not logged in, attempt to log in",
octstr_get_cstr(conn->id));
+ send_login(cpa);
+
+ /* this should actually be set after we receive the login-rsp, but that's
another thread,
+ * should be ok if we set it here */
+ elapse_time_counter = 0;
+ } else {
+ /* we are logged in, check if we need to reconnect */
+ if (elapse_time_counter >= (cpa->elapse_time * 60)) {
+ debug("smsc.cpa", 0, "CPA[%s]: session timed out",
octstr_get_cstr(conn->id));
+ /* let the code above do the logging in */
+ cpa->logged_in = 0;
+
+ conn->status = SMSCCONN_RECONNECTING;
+ continue;
+ }
+ elapse_time_counter += sleep_seconds;
+ }
+ gwthread_sleep(sleep_seconds);
+ }
+}
+
+/****
+ * Functions called by smscconn.c via SMSCConn function pointers
+ ****/
+
+static long queued_cb(SMSCConn *conn)
+{
+ CPA *cpa = conn->data;
+
+ return (cpa ? (conn->status != SMSCCONN_DEAD ?
+ cpa->open_sends : 0) : 0);
+}
+
+static int cpa_send_msg(SMSCConn *conn, Msg *msg)
+{
+ CPA *cpa = conn->data;
+ Msg *sms = msg_duplicate(msg);
+ double delay = 0;
+
+ if (conn->throughput) {
+ delay = 1.0 / conn->throughput;
+ }
+
+ cpa->open_sends++;
+
+ cpa_send_sms(conn, sms);
+
+ /* obey throughput speed limit, if any */
+ if (conn->throughput)
+ gwthread_sleep(delay);
+
+ return 0;
+}
+
+/* TODO */
+static int shutdown_cb(SMSCConn *conn, int finish_sending)
+{
+
+}
+
+int smsc_cpa_create(SMSCConn *conn, CfgGroup *cfg)
+{
+ CPA *cpa = NULL;
+ long portno; /* has to be long because of cfg_get_integer */
+ int ssl = 0; /* indicate if SSL-enabled server should be used */
+ Octstr *smsc_id;
+
+ /* NOTE: httpsmsc incorrectly use the config param "port"
+ * in my view, "port" is to represent the smsc side
+ * "receive-port" is to represent our side
+ * so I change the param to "receive-port"
+ */
+ if (cfg_get_integer(&portno, cfg, octstr_imm("receive-port")) == -1) {
+ error(0, "CPA[%s]: 'receive-port' invalid in smsc 'cpa' record.",
+ octstr_get_cstr(conn->id));
+ return -1;
+ }
+
+ smsc_id = cfg_get(cfg, octstr_imm("smsc-id"));
+ if (smsc_id == NULL)
+ smsc_id = octstr_duplicate(conn->name);
+
+ cpa = gw_malloc(sizeof(CPA));
+ cpa->http_ref = NULL;
+
+ cpa->allow_ip = cfg_get(cfg, octstr_imm("connect-allow-ip"));
+ cpa->send_url = cfg_get(cfg, octstr_imm("send-url"));
+ cpa->login_url = cfg_get(cfg, octstr_imm("login-url"));
+ cpa->username = cfg_get(cfg, octstr_imm("smsc-username"));
+ cpa->password = cfg_get(cfg, octstr_imm("smsc-password"));
+ cpa->cp_id = cfg_get(cfg, octstr_imm("cp-id"));
+ cpa->service_id = cfg_get(cfg, octstr_imm("service-id"));
+ cpa->short_code = cfg_get(cfg, octstr_imm("short-code"));
+ cpa->receive_host = cfg_get(cfg, octstr_imm("receive-host"));
+ cpa->prepaid_price_code = cfg_get(cfg, octstr_imm("prepaid-price-code"));
+ cpa->postpaid_price_code = cfg_get(cfg, octstr_imm("postpaid-price-code"));
+ cpa->charge_party = cfg_get(cfg, octstr_imm("charge-party"));
+ cpa->session_id = NULL;
+ cpa->elapse_time = 0;
+
+ if (cpa->send_url == NULL)
+ panic(0, "CPA[%s]: Sending not allowed. No 'send-url' specified.",
+ octstr_get_cstr(conn->id));
+
+ if (cpa->username == NULL)
+ panic(0, "CPA[%s]: No smsc-username specified",
+ octstr_get_cstr(conn->id));
+
+ if (cpa->password == NULL)
+ panic(0, "CPA[%s]: No smsc-password specified",
+ octstr_get_cstr(conn->id));
+
+ if (cpa->cp_id == NULL)
+ panic(0, "CPA[%s]: No cp-id specified",
+ octstr_get_cstr(conn->id));
+
+ if (cpa->service_id == NULL)
+ panic(0, "CPA[%s]: No service-id specified",
+ octstr_get_cstr(conn->id));
+
+ if (cpa->short_code == NULL)
+ panic(0, "CPA[%s]: No short-code specified",
+ octstr_get_cstr(conn->id));
+
+ if (cpa->receive_host == NULL)
+ panic(0, "CPA[%s]: No short-code specified",
+ octstr_get_cstr(conn->id));
+
+ if (cpa->prepaid_price_code == NULL)
+ panic(0, "CPA[%s]: No prepaid-price-code specified",
+ octstr_get_cstr(conn->id));
+
+ if (cpa->postpaid_price_code == NULL)
+ panic(0, "CPA[%s]: No postpaid-price-code specified",
+ octstr_get_cstr(conn->id));
+
+ if (cpa->charge_party == NULL)
+ panic(0, "CPA[%s]: No charge-party specified",
+ octstr_get_cstr(conn->id));
+
+ /* url-encode the stuffs that we are sending over in HTTP header */
+ octstr_url_encode(cpa->username);
+ octstr_url_encode(cpa->password);
+ octstr_url_encode(cpa->cp_id);
+ octstr_url_encode(cpa->prepaid_price_code);
+ octstr_url_encode(cpa->postpaid_price_code);
+
+ cpa->open_sends = 0;
+ cpa->logged_in = 0;
+ cpa->http_ref = http_caller_create();
+
+ conn->data = cpa;
+ conn->name = octstr_format("CPA");
+ conn->status = SMSCCONN_CONNECTING;
+ conn->connect_time = -1;
+
+ conn->shutdown = shutdown_cb;
+ conn->queued = queued_cb;
+ conn->send_msg = cpa_send_msg;
+
+ if (http_open_port_if(portno, ssl, conn->our_host)==-1)
+ goto error;
+
+ cpa->port = portno;
+ cpa->shutdown = 0;
+
+ if ((cpa->login_thread =
+ gwthread_create(login_manager, conn)) == -1)
+ goto error;
+
+ if ((cpa->receive_thread =
+ gwthread_create(cpa_receiver, conn)) == -1)
+ goto error;
+
+ if ((cpa->http_result_thread =
+ gwthread_create(cpa_http_receive_result, conn)) == -1)
+ goto error;
+
+ info(0, "CPA[%s]: Initiated and ready", octstr_get_cstr(conn->id));
+
+ return 0;
+
+error:
+ error(0, "CPA[%s]: Failed to create http smsc connection",
+ octstr_get_cstr(conn->id));
+
+ conn->data = NULL;
+ cpa_destroy(cpa);
+ conn->why_killed = SMSCCONN_KILLED_CANNOT_CONNECT;
+ conn->status = SMSCCONN_DEAD;
+ return -1;
+}
+
+/* vim: ts=4 expandtab sw=4
+ */
diff -Naur kannel-snapshot/gw/smscconn.c kannel-snapshot-cpa/gw/smscconn.c
--- kannel-snapshot/gw/smscconn.c 2003-09-12 05:47:04.000000000 +0800
+++ kannel-snapshot-cpa/gw/smscconn.c 2003-11-18 09:41:57.000000000 +0800
@@ -181,6 +181,8 @@
ret = smsc_cgw_create(conn,grp);
else if (octstr_compare(smsc_type, octstr_imm("smasi")) == 0)
ret = smsc_smasi_create(conn, grp);
+ else if (octstr_compare(smsc_type, octstr_imm("cpa")) == 0)
+ ret = smsc_cpa_create(conn, grp);
else
ret = smsc_wrapper_create(conn, grp);
diff -Naur kannel-snapshot/gw/smscconn_p.h kannel-snapshot-cpa/gw/smscconn_p.h
--- kannel-snapshot/gw/smscconn_p.h 2003-07-27 22:45:38.000000000 +0800
+++ kannel-snapshot-cpa/gw/smscconn_p.h 2003-11-18 09:42:22.000000000 +0800
@@ -215,6 +215,9 @@
/* Responsible file: smsc/smsc_smasi.c */
int smsc_smasi_create(SMSCConn *conn, CfgGroup *cfg);
+/* Responsible file: smsc/smsc_cpa.c */
+int smsc_cpa_create(SMSCConn *conn, CfgGroup *cfg);
+
/* ADD NEW CREATE FUNCTIONS HERE
*
* int smsc_xxx_create(SMSCConn *conn, CfgGroup *cfg);
diff -Naur kannel-snapshot/gwlib/cfg.def kannel-snapshot-cpa/gwlib/cfg.def
--- kannel-snapshot/gwlib/cfg.def 2003-10-31 03:20:30.000000000 +0800
+++ kannel-snapshot-cpa/gwlib/cfg.def 2004-01-13 16:41:10.000000000 +0800
@@ -279,6 +279,15 @@
OCTSTR(msg-id-type)
OCTSTR(no-dlr)
OCTSTR(connection-timeout)
+/* CPA stuffs */
+ OCTSTR(login-url)
+ OCTSTR(cp-id)
+ OCTSTR(service-id)
+ OCTSTR(short-code)
+ OCTSTR(receive-host)
+ OCTSTR(prepaid-price-code)
+ OCTSTR(postpaid-price-code)
+ OCTSTR(charge-party)
)
