Patch for CPA functionality

Phuah Yee Keat <[email protected]>
Newsgroups gmane.comp.mobile.kannel.devel
Message-ID <[email protected]>
Hi,

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
kannel_20031105_cpa.patch (text/plain, 28.7 KB)
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)
 )
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.