bearerbox.c
上传用户:gzpyjq
上传日期:2013-01-31
资源大小:1852k
文件大小:18k
源码类别:

手机WAP编程

开发平台:

WINDOWS

  1. /*
  2.  * bearerbox.c
  3.  * 
  4.  * this is the core module of the bearerbox. It starts everything and
  5.  * listens to HTTP requests and traps signals.
  6.  * All started modules are responsible for the rest.
  7.  *
  8.  * Kalle Marjola <rpr@wapit.com> 2000 for project Kannel
  9.  */
  10. #include <errno.h>
  11. #include <stdlib.h>
  12. #include <stdio.h>
  13. #include <time.h>
  14. #include <string.h>
  15. #include <signal.h>
  16. #include <unistd.h>
  17. #include "gwlib/gwlib.h"
  18. #include "msg.h"
  19. #include "bearerbox.h"
  20. #include "shared.h"
  21. #include "dlr.h"
  22. /* global variables; included to other modules as needed */
  23. List *incoming_sms;
  24. List *outgoing_sms;
  25. List *incoming_wdp;
  26. List *outgoing_wdp;
  27. Counter *incoming_sms_counter;
  28. Counter *outgoing_sms_counter;
  29. Counter *incoming_wdp_counter;
  30. Counter *outgoing_wdp_counter;
  31. /* this is not a list of items; instead it is used as
  32.  * indicator to note how many threads we have.
  33.  * ALL flow threads must exit before we may safely change
  34.  * bb_status from BB_SHUTDOWN to BB_DEAD
  35.  *
  36.  * XXX: prehaps we could also have items in this list, as
  37.  *     descriptors of each thread?
  38.  */
  39. List *flow_threads;
  40. /* and still more abuse; we use this list to put us into
  41.  * 'suspend' state - if there are any producers (only core adds/removes them)
  42.  * receiver/sender systems just sit, blocked in list_consume
  43.  */
  44. List *suspended;
  45. /* this one is like 'suspended', but only for receiving UDP/SMSC
  46.  * (suspended state puts producers for both lists)
  47.  */
  48. List *isolated;
  49. volatile sig_atomic_t bb_status;
  50. /* own global variables */
  51. static Mutex *status_mutex;
  52. Mutex *boxid_mutex;
  53. static time_t start_time;
  54. /* to avoid copied code */
  55. static void set_shutdown_status(void)
  56. {
  57.     sig_atomic_t old = bb_status;
  58.     bb_status = BB_SHUTDOWN;
  59.     
  60.     if (old == BB_SUSPENDED)
  61. list_remove_producer(suspended);
  62.     if (old == BB_SUSPENDED || old == BB_ISOLATED)
  63. list_remove_producer(isolated);
  64. }
  65. /*-------------------------------------------------------
  66.  * signals
  67.  */
  68. static void signal_handler(int signum)
  69. {
  70.     /* On some implementations (i.e. linuxthreads), signals are delivered
  71.      * to all threads.  We only want to handle each signal once for the
  72.      * entire box, and we let the gwthread wrapper take care of choosing
  73.      * one.
  74.      */
  75.     if (!gwthread_shouldhandlesignal(signum))
  76. return;
  77.     switch (signum) {
  78.         case SIGINT:
  79.         case SIGTERM:
  80.             mutex_lock(status_mutex);
  81.             if (bb_status != BB_SHUTDOWN && bb_status != BB_DEAD) {
  82.                 warning(0, "Killing signal received, shutting down...");
  83.                 mutex_unlock(status_mutex);
  84.                 bb_shutdown();
  85.                 return;
  86.             } 
  87.             else if (bb_status == BB_SHUTDOWN) {
  88.                 warning(0, "New killing signal received, killing neverthless...");
  89.                 bb_status = BB_DEAD;
  90.             }
  91.             else if (bb_status == BB_DEAD) {
  92.                 panic(0, "cannot die by its own will");
  93.             }
  94.             mutex_unlock(status_mutex);
  95.             break;
  96.         case SIGHUP:
  97.             warning(0, "SIGHUP received, catching and re-opening logs");
  98.             log_reopen();
  99.             alog_reopen();
  100.             store_load();
  101.             break;
  102.         
  103.         /* 
  104.          * It would be more proper to use SIGUSR1 for this, but on some
  105.          * platforms that's reserved by the pthread support. 
  106.          */
  107.         case SIGQUIT:
  108.        warning(0, "SIGQUIT received, reporting memory usage.");
  109.        gw_check_leaks();
  110.        break;
  111.     }
  112. }
  113. static void setup_signal_handlers(void)
  114. {
  115.     struct sigaction act;
  116.     act.sa_handler = signal_handler;
  117.     sigemptyset(&act.sa_mask);
  118.     act.sa_flags = 0;
  119.     sigaction(SIGINT, &act, NULL);
  120.     sigaction(SIGTERM, &act, NULL);
  121.     sigaction(SIGQUIT, &act, NULL);
  122.     sigaction(SIGHUP, &act, NULL);
  123.     sigaction(SIGPIPE, &act, NULL);
  124. }
  125. /*--------------------------------------------------------
  126.  * functions to start/init sub-parts of the bearerbox
  127.  *
  128.  * these functions are NOT thread safe but they have no need to be,
  129.  * as there is only one core bearerbox thread
  130.  */
  131. static int start_smsc(Cfg *cfg)
  132. {
  133.     static int started = 0;
  134.     if (started) return 0;
  135.     smsbox_start(cfg);
  136.     smsc2_start(cfg);
  137.     started = 1;
  138.     return 0;
  139. }
  140. static void wdp_router(void *arg)
  141. {
  142.     Msg *msg;
  143.     list_add_producer(flow_threads);
  144.     
  145.     while(bb_status != BB_DEAD) {
  146. if ((msg = list_consume(outgoing_wdp)) == NULL)
  147.     break;
  148. gw_assert(msg_type(msg) == wdp_datagram);
  149. // if (msg->list == sms)
  150. // smsc_addwdp(msg);
  151. // else
  152. udp_addwdp(msg);
  153.     }
  154.     udp_die();
  155.     // smsc_endwdp();
  156.     list_remove_producer(flow_threads);
  157. }
  158. static int start_wap(Cfg *cfg)
  159. {
  160.     static int started = 0;
  161.     if (started) return 0;
  162.     
  163.     wapbox_start(cfg);
  164.     debug("bb", 0, "starting WDP router");
  165.     if (gwthread_create(wdp_router, NULL) == -1)
  166. panic(0, "Failed to start a new thread for WDP routing");
  167.     started = 1;
  168.     return 0;
  169. }
  170. static int start_udp(Cfg *cfg)
  171. {
  172.     static int started = 0;
  173.     if (started) return 0;
  174.     udp_start(cfg);
  175.     start_wap(cfg);
  176.     started = 1;
  177.     return 0;
  178. }
  179. /*
  180.  * check that there is basic thingies in configuration
  181.  */
  182. static int check_config(Cfg *cfg)
  183. {
  184.     CfgGroup *grp;
  185.     long smsp, wapp;
  186.     grp = cfg_get_single_group(cfg, octstr_imm("core"));
  187.     if (grp == NULL)
  188.      return -1;
  189.     if (cfg_get_integer(&smsp, grp, octstr_imm("smsbox-port")) == -1)
  190.      smsp = -1;
  191.     if (cfg_get_integer(&wapp, grp, octstr_imm("wapbox-port")) == -1)
  192.      wapp = -1;
  193.     
  194. #ifndef KANNEL_NO_SMS    
  195.     grp = cfg_get_single_group(cfg, octstr_imm("smsbox"));
  196.     if (smsp != -1 && grp == NULL) {
  197. error(0, "No 'smsbox' group in configuration, but smsbox-port set");
  198. return -1;
  199.     }
  200. #endif
  201.     
  202. #ifndef KANNEL_NO_WAP
  203.     grp = cfg_get_single_group(cfg, octstr_imm("wapbox"));
  204.     if (wapp != -1 && grp == NULL) {
  205. error(0, "No 'wapbox' group in configuration, but wapbox-port set");
  206. return -1;
  207.     }
  208. #endif
  209.     
  210.     return 0;
  211. }
  212. /*
  213.  * check our own variables
  214.  */
  215. static int check_args(int i, int argc, char **argv) {
  216.     if (strcmp(argv[i], "-S")==0 || strcmp(argv[i], "--suspended")==0)
  217. bb_status = BB_SUSPENDED;
  218.     else if (strcmp(argv[i], "-I")==0 || strcmp(argv[i], "--isolated")==0)
  219. bb_status = BB_ISOLATED;
  220.     else
  221. return -1;
  222.     return 0;
  223. static Cfg *init_bearerbox(Cfg *cfg)
  224. {
  225.     CfgGroup *grp;
  226.     Octstr *log, *val;
  227.     long loglevel;
  228. #ifdef HAVE_LIBSSL
  229.     Octstr *ssl_server_cert_file;
  230.     Octstr *ssl_server_key_file;
  231.     int ssl_enabled = 0;
  232. #endif /* HAVE_LIBSSL */
  233.  
  234.     grp = cfg_get_single_group(cfg, octstr_imm("core"));
  235.     log = cfg_get(grp, octstr_imm("log-file"));
  236.     if (log != NULL) {
  237. if (cfg_get_integer(&loglevel, grp, octstr_imm("log-level")) == -1)
  238.     loglevel = 0;
  239. log_open(octstr_get_cstr(log), loglevel);
  240. octstr_destroy(log);
  241.     }
  242.     if (check_config(cfg) == -1)
  243. panic(0, "Cannot start with corrupted configuration");
  244.     log = cfg_get(grp, octstr_imm("access-log"));
  245.     if (log != NULL) {
  246. alog_open(octstr_get_cstr(log), 1);
  247. /* use localtime; XXX let user choose that */
  248. octstr_destroy(log);
  249.     }
  250.     log = cfg_get(grp, octstr_imm("store-file"));
  251.     if (log != NULL) {
  252. store_init(log);
  253. octstr_destroy(log);
  254.     }
  255.     conn_config_ssl (grp);
  256.     /* 
  257.      * Make sure we have "ssl-server-cert-file" and "ssl-server-key-file" specified
  258.      * in the core group since we need it to run SSL-enabled internal box 
  259.      * connections configured via "smsbox-port-ssl = yes" and "wapbox-port-ssl = yes".
  260.      * Check only these, because for "admin-port-ssl" and "sendsms-port-ssl" for the 
  261.      * SSL-enabled HTTP servers are probed within gw/bb_http.c:httpadmin_start()
  262.      */
  263. #ifdef HAVE_LIBSSL
  264.     ssl_server_cert_file = cfg_get(grp, octstr_imm("ssl-server-cert-file"));
  265.     ssl_server_key_file = cfg_get(grp, octstr_imm("ssl-server-key-file"));
  266.     if (ssl_server_cert_file != NULL && ssl_server_key_file != NULL) {
  267.        /* we are fine, at least files are specified in the configuration */
  268.     } else {
  269.         cfg_get_bool(&ssl_enabled, grp, octstr_imm("smsbox-port-ssl"));
  270.         cfg_get_bool(&ssl_enabled, grp, octstr_imm("wapbox-port-ssl"));
  271.         if (ssl_enabled) {
  272.        panic(0, "You MUST specify cert and key files within core group for SSL-enabled inter-box connections!");
  273.         }
  274.     }
  275.     octstr_destroy(ssl_server_cert_file);
  276.     octstr_destroy(ssl_server_key_file);
  277. #endif /* HAVE_LIBSSL */
  278.     /* if all seems to be OK by the first glimpse, real start-up */
  279.     
  280.     outgoing_sms = list_create();
  281.     incoming_sms = list_create();
  282.     outgoing_wdp = list_create();
  283.     incoming_wdp = list_create();
  284.     outgoing_sms_counter = counter_create();
  285.     incoming_sms_counter = counter_create();
  286.     outgoing_wdp_counter = counter_create();
  287.     incoming_wdp_counter = counter_create();
  288.     
  289.     status_mutex = mutex_create();
  290.     boxid_mutex = mutex_create();
  291.     setup_signal_handlers();
  292.     
  293.     /* http-admin is REQUIRED */
  294.     httpadmin_start(cfg);
  295. #ifndef KANNEL_NO_SMS    
  296.     {
  297. List *list;
  298. list = cfg_get_multi_group(cfg, octstr_imm("smsc"));
  299. if (list != NULL) {
  300.     start_smsc(cfg);
  301.     list_destroy(list, NULL);
  302. }
  303.     }
  304. #endif
  305.     
  306. #ifndef KANNEL_NO_WAP
  307.     grp = cfg_get_single_group(cfg, octstr_imm("core"));
  308.     val = cfg_get(grp, octstr_imm("wdp-interface-name"));
  309.     if (val != NULL && octstr_len(val) > 0)
  310. start_udp(cfg);
  311.     octstr_destroy(val);
  312.     if (cfg_get_single_group(cfg, octstr_imm("wapbox")) != NULL)
  313. start_wap(cfg);
  314. #endif
  315.     
  316.     return cfg;
  317. }
  318. static void empty_msg_lists(void)
  319. {
  320.     Msg *msg;
  321. #ifndef KANNEL_NO_WAP
  322.     if (list_len(incoming_wdp) > 0 || list_len(outgoing_wdp) > 0)
  323. warning(0, "Remaining WDP: %ld incoming, %ld outgoing",
  324.       list_len(incoming_wdp), list_len(outgoing_wdp));
  325.     info(0, "Total WDP messages: received %ld, sent %ld",
  326.  counter_value(incoming_wdp_counter),
  327.  counter_value(outgoing_wdp_counter));
  328. #endif
  329.     
  330.     while((msg = list_extract_first(incoming_wdp))!=NULL)
  331. msg_destroy(msg);
  332.     while((msg = list_extract_first(outgoing_wdp))!=NULL)
  333. msg_destroy(msg);
  334.     list_destroy(incoming_wdp, NULL);
  335.     list_destroy(outgoing_wdp, NULL);
  336.     counter_destroy(incoming_wdp_counter);
  337.     counter_destroy(outgoing_wdp_counter);
  338.     
  339.     
  340. #ifndef KANNEL_NO_SMS
  341.     /* XXX we should record these so that they are not forever lost...
  342.      */
  343.     if (list_len(incoming_sms) > 0 || list_len(outgoing_sms) > 0)
  344. debug("bb", 0, "Remaining SMS: %ld incoming, %ld outgoing",
  345.       list_len(incoming_sms), list_len(outgoing_sms));
  346.     info(0, "Total SMS messages: received %ld, sent %ld",
  347.  counter_value(incoming_sms_counter),
  348.  counter_value(outgoing_sms_counter));
  349. #endif
  350.     list_destroy(incoming_sms, msg_destroy_item);
  351.     list_destroy(outgoing_sms, msg_destroy_item);
  352.     
  353.     counter_destroy(incoming_sms_counter);
  354.     counter_destroy(outgoing_sms_counter);
  355. }
  356. int main(int argc, char **argv)
  357. {
  358.     int cf_index;
  359.     Cfg *cfg;
  360.     Octstr *filename;
  361.     bb_status = BB_RUNNING;
  362.     
  363.     gwlib_init();
  364.     start_time = time(NULL);
  365.     suspended = list_create();
  366.     isolated = list_create();
  367.     list_add_producer(suspended);
  368.     list_add_producer(isolated);
  369.     cf_index = get_and_set_debugs(argc, argv, check_args);
  370.     if (argv[cf_index] == NULL)
  371.         filename = octstr_create("kannel.conf");
  372.     else
  373.         filename = octstr_create(argv[cf_index]);
  374.     cfg = cfg_create(filename); 
  375.     
  376.     if (cfg_read(cfg) == -1)
  377.         panic(0, "Couldn't read configuration from `%s'.", octstr_get_cstr(filename));
  378.     
  379.     octstr_destroy(filename);
  380.     dlr_init(cfg);
  381.     
  382.     report_versions("bearerbox");
  383.     flow_threads = list_create();
  384.     
  385.     init_bearerbox(cfg);
  386.     info(0, "----------------------------------------");
  387.     info(0, GW_NAME " bearerbox II version %s starting", VERSION);
  388.     gwthread_sleep(5.0); /* give time to threads to register themselves */
  389.     if (store_load()== -1)
  390. panic(0, "Cannot start with store-file failing");
  391.     
  392.     info(0, "MAIN: Start-up done, entering mainloop");
  393.     if (bb_status == BB_SUSPENDED) {
  394. info(0, "Gateway is now SUSPENDED by startup arguments");
  395.     } else if (bb_status == BB_ISOLATED) {
  396. info(0, "Gateway is now ISOLATED by startup arguments");
  397. list_remove_producer(suspended);
  398.     } else {
  399. smsc2_resume();
  400. list_remove_producer(suspended);
  401. list_remove_producer(isolated);
  402.     }
  403.     /* wait until flow threads exit */
  404.     while(list_consume(flow_threads)!=NULL)
  405. ;
  406.     info(0, "All flow threads have died, killing core");
  407.     bb_status = BB_DEAD;
  408.     httpadmin_stop();
  409.     boxc_cleanup();
  410.     smsc2_cleanup();
  411.     empty_msg_lists();
  412.     list_destroy(flow_threads, NULL);
  413.     list_destroy(suspended, NULL);
  414.     list_destroy(isolated, NULL);
  415.     mutex_destroy(status_mutex);
  416.     mutex_destroy(boxid_mutex);
  417.     alog_close(); /* if we have any */
  418.     cfg_destroy(cfg);
  419.     dlr_shutdown();
  420.     gwlib_shutdown();
  421.     return 0;
  422. }
  423. /*----------------------------------------------------------------
  424.  * public functions used via HTTP adminstration interface/module
  425.  */
  426. int bb_shutdown(void)
  427. {
  428.     static int called = 0;
  429.     
  430.     mutex_lock(status_mutex);
  431.     
  432.     if (called) {
  433. mutex_unlock(status_mutex);
  434. return -1;
  435.     }
  436.     debug("bb", 0, "Shutting down " GW_NAME "...");
  437.     called = 1;
  438.     set_shutdown_status();
  439.     store_shutdown();
  440.     mutex_unlock(status_mutex);
  441. #ifndef KANNEL_NO_SMS
  442.     debug("bb", 0, "shutting down smsc");
  443.     smsc2_shutdown();
  444. #endif
  445. #ifndef KANNEL_NO_WAP
  446.     debug("bb", 0, "shutting down udp");
  447.     udp_shutdown();
  448. #endif
  449.     
  450.     return 0;
  451. }
  452. int bb_isolate(void)
  453. {
  454.     mutex_lock(status_mutex);
  455.     if (bb_status != BB_RUNNING && bb_status != BB_SUSPENDED) {
  456. mutex_unlock(status_mutex);
  457. return -1;
  458.     }
  459.     if (bb_status == BB_RUNNING) {
  460. smsc2_suspend();
  461. list_add_producer(isolated);
  462.     } else
  463. list_remove_producer(suspended);
  464.     bb_status = BB_ISOLATED;
  465.     mutex_unlock(status_mutex);
  466.     return 0;
  467. }
  468. int bb_suspend(void)
  469. {
  470.     mutex_lock(status_mutex);
  471.     if (bb_status != BB_RUNNING && bb_status != BB_ISOLATED) {
  472. mutex_unlock(status_mutex);
  473. return -1;
  474.     }
  475.     if (bb_status != BB_ISOLATED) {
  476. smsc2_suspend();
  477. list_add_producer(isolated);
  478.     }
  479.     bb_status = BB_SUSPENDED;
  480.     list_add_producer(suspended);
  481.     mutex_unlock(status_mutex);
  482.     return 0;
  483. }
  484. int bb_resume(void)
  485. {
  486.     mutex_lock(status_mutex);
  487.     if (bb_status != BB_SUSPENDED && bb_status != BB_ISOLATED) {
  488. mutex_unlock(status_mutex);
  489. return -1;
  490.     }
  491.     if (bb_status == BB_SUSPENDED)
  492. list_remove_producer(suspended);
  493.     smsc2_resume();
  494.     bb_status = BB_RUNNING;
  495.     list_remove_producer(isolated);
  496.     mutex_unlock(status_mutex);
  497.     return 0;
  498. }
  499. int bb_flush_dlr(void)
  500. {
  501.     /* beware that mutex locking is done in dlr_foobar() routines */
  502.     if (bb_status != BB_SUSPENDED) {
  503. return -1;
  504.     }
  505.     dlr_flush();
  506.     return 0;
  507. }
  508. int bb_stop_smsc(Octstr *id)
  509. {
  510.     return smsc2_stop_smsc(id);
  511. }
  512. int bb_restart_smsc(Octstr *id)
  513. {
  514.     return smsc2_restart_smsc(id);
  515. }
  516. int bb_restart(void)
  517. {
  518.     return -1;
  519. }
  520. #define append_status(r, s, f, x) { s = f(x); octstr_append(r, s); 
  521.                                  octstr_destroy(s); }
  522. Octstr *bb_print_status(int status_type)
  523. {
  524.     char *s, *lb;
  525.     char *frmt, *footer;
  526.     char buf[1024];
  527.     Octstr *ret, *str, *version;
  528.     time_t t;
  529.     if ((lb = bb_status_linebreak(status_type))==NULL)
  530. return octstr_create("Un-supported format");
  531.     t = time(NULL) - start_time;
  532.     
  533.     if (bb_status == BB_RUNNING)
  534. s = "running";
  535.     else if (bb_status == BB_ISOLATED)
  536. s = "isolated";
  537.     else if (bb_status == BB_SUSPENDED)
  538. s = "suspended";
  539.     else if (bb_status == BB_FULL)
  540.         s = "filled";
  541.     else
  542. s = "going down";
  543.     version = version_report_string("bearerbox");
  544.     if (status_type == BBSTATUS_HTML) {
  545. frmt = "%s</p>nn"
  546.     " <p>Status: %s, uptime %ldd %ldh %ldm %lds</p>nn"
  547.     " <p>WDP: received %ld (%ld queued), sent %ld "
  548.     "(%ld queued)</p>nn"
  549.     " <p>SMS: received %ld (%ld queued), sent %ld "
  550.     "(%ld queued), store size %ld</p>n"
  551.         " <p>SMS: inbound %.2f msg/sec, outbound %.2f msg/sec</p>nn"
  552.         " <p>DLR: %ld queued, using %s storage</p>nn";
  553. footer = "<p>";
  554.     } else if (status_type == BBSTATUS_WML) {
  555. frmt = "%s</p>nn"
  556.     "   <p>Status: %s, uptime %ldd %ldh %ldm %lds</p>nn"
  557.     "   <p>WDP: received %ld (%ld queued)<br/>n"
  558.     "      WDP: sent %ld (%ld queued)</p>nn"
  559.     "   <p>SMS: received %ld (%ld queued)<br/>n"
  560.     "      SMS: sent %ld (%ld queued)<br/>n"
  561.         "      SMS: store size %ld<br/>n"
  562.         "      SMS: inbound %.2f msg/sec<br/>n"
  563.         "      SMS: outbound %.2f msg/sec</p>nn"
  564.         "   <p>DLR: %ld queued<br/>n"
  565.         "      DLR: using %s storage</p>nn";
  566. footer = "<p>";
  567.     } else if (status_type == BBSTATUS_XML) {
  568. frmt = "<version>%s</version>n"
  569.     "<status>%s, uptime %ldd %ldh %ldm %lds</status>n"
  570.     "t<wdp>ntt<received><total>%ld</total><queued>%ld</queued></received>ntt<sent><total>%ld"
  571.     "</total><queued>%ld</queued></sent>nt</wdp>n"
  572.     "t<sms>ntt<received><total>%ld</total><queued>%ld</queued></received>ntt<sent><total>%ld"
  573.     "</total><queued>%ld</queued></sent>ntt<storesize>%ld</storesize>ntt"
  574.         "<inbound>%.2f</inbound>ntt<outbound>%.2f</outbound>nt</sms>n"
  575.     "t<dlr>ntt<queued>%ld</queued>ntt<storage>%s</storage>nt</dlr>n";
  576. footer = "";
  577.     } else {
  578. frmt = "%snnStatus: %s, uptime %ldd %ldh %ldm %ldsnn"
  579.     "WDP: received %ld (%ld queued), sent %ld (%ld queued)nn"
  580.     "SMS: received %ld (%ld queued), sent %ld (%ld queued), store size %ldn"
  581.         "SMS: inbound %.2f msg/sec, outbound %.2f msg/secnn"
  582.         "DLR: %ld queued, using %s storagenn";
  583. footer = "";
  584.     }
  585.     
  586.     sprintf(buf, frmt,
  587.     octstr_get_cstr(version),
  588.     s, t/3600/24, t/3600%24, t/60%60, t%60,
  589.     counter_value(incoming_wdp_counter),
  590.     list_len(incoming_wdp) + boxc_incoming_wdp_queue(),
  591.     counter_value(outgoing_wdp_counter),
  592.     list_len(outgoing_wdp) + udp_outgoing_queue(),
  593.     counter_value(incoming_sms_counter),
  594.     list_len(incoming_sms),
  595.     counter_value(outgoing_sms_counter),
  596.     list_len(outgoing_sms),
  597.     store_messages(),
  598.         (float)counter_value(incoming_sms_counter)/t,
  599.         (float)counter_value(outgoing_sms_counter)/t,
  600.         dlr_messages(),
  601.         octstr_get_cstr(dlr_type));
  602.     octstr_destroy(version);
  603.     ret = octstr_create(buf);
  604.     
  605.     append_status(ret, str, boxc_status, status_type);
  606.     append_status(ret, str, smsc2_status, status_type);
  607.     octstr_append_cstr(ret, footer);
  608.     
  609.     return ret;
  610. }
  611. char *bb_status_linebreak(int status_type)
  612. {
  613.     switch(status_type) {
  614.     case BBSTATUS_HTML:
  615. return "<br>n";
  616.     case BBSTATUS_WML:
  617. return "<br/>n";
  618.     case BBSTATUS_TEXT:
  619. return "n";
  620.     case BBSTATUS_XML:
  621. return "n";
  622.     default:
  623. return NULL;
  624.     }
  625. }