[PATCH] custom access-log format
Stipe Tolj <[email protected]>
| Newsgroups | gmane.comp.mobile.kannel.devel |
|---|---|
| Organization | Wapme Systems AG |
| Message-ID | <[email protected]> |
Hi list, the attached patches is a feature add in terms of customizing the access-log format for bearerbox. This will allow to use custom format access-log lines using escape codes (commonly known from the sms-service groups). Here are the changes: * gw/bb_alog.c: handles the custom bearerbox access-log formating * gw/bb_smscconn.c: moved log_sms() to gw/bb_alog.c:bb_alog_sms() * gw/bearerbox.h: added bb_alog_ prototypes * gw/[sms|wap]box.c: harmonized access-log config directive reading * gwlib/accesslog.[ch]: alog_open() changed to indicate if markers should be written to access-log file. If no markers are set, then the default timestamp prefix is not written, allowing users to individually set the timestamp in their custom access-log format. * gwlib/cfg.def: added config directives 'access-log-time' to indicate if localtime or gmt should be used within access-log, 'access-log-format' holding the escape code formated line to log, 'access-log-clean' (boolean) indicating if standard markers shoould be avoided and hence the access-log should be "clean". Which means you can use this core group for bearerbox in your configuration: group = core admin-port = 13000 smsbox-port = 13001 admin-password = bar ... access-log = "/var/log/kannel/access.log" access-log-clean = yes #access-log-time = gmt access-log-format = "%t %l [SMSC:%i] [SVC:%n] [ACT:%A] [BINF:%B] [from:%p] [to:%P] [flags:%m:%c:%M:%C:%d] [msg:%L:%b] [udh:%U:%u]" ... store-file = "/var/log/kannel/kannel.store" which would cause bearerbox to log in our "default" access-log style. Please try and have a vote on it. If no vetos occur, I'll commit this to cvs. Stipe mailto:[email protected] ------------------------------------------------------------------- Wapme Systems AG Münsterstr. 248 40470 Düsseldorf, NRW, Germany phone: +49.211.74845.0 fax: +49.211.74845.299 mailto:[email protected] http://www.wapme-systems.de/ ------------------------------------------------------------------- -----BEGIN PGP PUBLIC KEY BLOCK----- Version: GnuPG v1.2.2 (Cygwin) mIsEP6mcYwEEAMDnUiUwrbb+xwTFWN6TxF2+XZu7/alwJMeCwMBRvXtPZqfjpPhS OkBpU0F4TrVuugz1HINTSaJTYq10AzDQXp5NkyWgckqW79nPAWuOX0dicbJk+cN2 nM2TI4KaxUDe6u8hghNEnH/i2lXsUu9apnP/iixzV81VC2je3uc9hZpnAAYptEVT dGlwZSBUb2xqIChUZWNobm9sb2d5IENlbnRlciAmIFJlc2VhcmNoIExhYikgPHRv bGpAd2FwbWUtc3lzdGVtcy5kZT6ItAQTAQIAHgUCP6mcYwIbAwYLCQgHAwIDFQID AxYCAQIeAQIXgAAKCRABV0w1BqPYRuSqA/wPzsQxao2YePENCtgRTrO86U6zg3sl OcS6CJFI4FZP5h/xD3GRsNH1+MPSvZlomDdpFnr547DGz/Kq9MXuQwVvlVig5yWZ K5dtKp1r5YLhxJQBhfirZbRFFnYmf19f18J8OoS28tuFVftDl1AIwJS3HLyBTv6H g2HyLAEKQIp30Q== =aYCI -----END PGP PUBLIC KEY BLOCK-----
access-log-format.patch
(application/x-unknown-content-type-patch_auto_file, 25.2 KB)
diff -ur ./gw/bb_smscconn.c ../../cvs/gateway/gw/bb_smscconn.c
--- ./gw/bb_smscconn.c 2003-11-24 15:18:32.248534400 +0100
+++ ../../cvs/gateway/gw/bb_smscconn.c 2003-11-21 16:01:02.626726100 +0100
@@ -118,34 +118,6 @@
int route_incoming_to_boxc(Msg *sms);
static int route_incoming_to_smsc(SMSCConn *conn, Msg *msg);
-static void log_sms(SMSCConn *conn, Msg *sms, char *message)
-{
- Octstr *text, *udh;
-
- text = sms->sms.msgdata ? octstr_duplicate(sms->sms.msgdata) : octstr_create("");
- udh = sms->sms.udhdata ? octstr_duplicate(sms->sms.udhdata) : octstr_create("");
- if ((sms->sms.coding == DC_8BIT || sms->sms.coding == DC_UCS2))
- octstr_binary_to_hex(text, 1);
- octstr_binary_to_hex(udh, 1);
-
- alog("%s [SMSC:%s] [SVC:%s] [ACT:%s] [BINF:%s] [from:%s] [to:%s] [flags:%d:%d:%d:%d:%d] [msg:%d:%s]"
- " [udh:%d:%s]",
- message,
- conn ? (smscconn_id(conn) ? octstr_get_cstr(smscconn_id(conn)) : "")
- : "",
- sms->sms.service ? octstr_get_cstr(sms->sms.service) : "",
- sms->sms.account ? octstr_get_cstr(sms->sms.account) : "",
- sms->sms.binfo ? octstr_get_cstr(sms->sms.binfo) : "",
- sms->sms.sender ? octstr_get_cstr(sms->sms.sender) : "",
- sms->sms.receiver ? octstr_get_cstr(sms->sms.receiver) : "",
- sms->sms.mclass, sms->sms.coding, sms->sms.mwi, sms->sms.compress,
- sms->sms.dlr_mask,
- octstr_len(sms->sms.msgdata), octstr_get_cstr(text),
- octstr_len(sms->sms.udhdata), octstr_get_cstr(udh)
- );
- octstr_destroy(udh);
- octstr_destroy(text);
-}
/*---------------------------------------------------------------------------
* CALLBACK FUNCTIONS
@@ -194,7 +166,7 @@
(void) store_save(mack);
msg_destroy(mack);
- log_sms(conn, sms, "Sent SMS");
+ bb_alog_sms(conn, sms, "Sent SMS");
/* generate relay confirmancy message */
if (DLR_IS_SMSC_SUCCESS(sms->sms.dlr_mask)) {
@@ -240,9 +212,9 @@
if (conn) counter_increase(conn->failed);
if (reason == SMSCCONN_FAILED_DISCARDED)
- log_sms(conn, sms, "DISCARDED SMS");
+ bb_alog_sms(conn, sms, "DISCARDED SMS");
else
- log_sms(conn, sms, "FAILED Send SMS");
+ bb_alog_sms(conn, sms, "FAILED Send SMS");
/* generate relay confirmancy message */
if (DLR_IS_SMSC_FAIL(sms->sms.dlr_mask) ||
@@ -285,7 +257,7 @@
numhash_find_number(white_list, sms->sms.sender) < 1) {
info(0, "Number <%s> is not in white-list, message discarded",
octstr_get_cstr(sms->sms.sender));
- log_sms(conn, sms, "REJECTED - not white-listed SMS");
+ bb_alog_sms(conn, sms, "REJECTED - not white-listed SMS");
msg_destroy(sms);
return SMSCCONN_FAILED_REJECTED;
}
@@ -293,7 +265,7 @@
numhash_find_number(black_list, sms->sms.sender) == 1) {
info(0, "Number <%s> is in black-list, message discarded",
octstr_get_cstr(sms->sms.sender));
- log_sms(conn, sms, "REJECTED - black-listed SMS");
+ bb_alog_sms(conn, sms, "REJECTED - black-listed SMS");
msg_destroy(sms);
return SMSCCONN_FAILED_REJECTED;
}
@@ -323,9 +295,9 @@
if (route_incoming_to_boxc(copy) == -1) {
warning(0, "incoming messages queue too long, dropping a message.");
if (sms->sms.sms_type == report)
- log_sms(conn, sms, "DROPPED Received DLR");
+ bb_alog_sms(conn, sms, "DROPPED Received DLR");
else
- log_sms(conn, sms, "DROPPED Received SMS");
+ bb_alog_sms(conn, sms, "DROPPED Received SMS");
msg_destroy(copy);
/* put nack into store-file */
copy = msg_create(ack);
@@ -342,9 +314,9 @@
}
if (sms->sms.sms_type != report)
- log_sms(conn, sms, "Receive SMS");
+ bb_alog_sms(conn, sms, "Receive SMS");
else
- log_sms(conn, sms, "DLR SMS");
+ bb_alog_sms(conn, sms, "DLR SMS");
counter_increase(incoming_sms_counter);
if (conn != NULL) counter_increase(conn->received);
diff -ur ./gw/bearerbox.c ../../cvs/gateway/gw/bearerbox.c
--- ./gw/bearerbox.c 2003-11-24 15:18:32.278577600 +0100
+++ ../../cvs/gateway/gw/bearerbox.c 2003-11-21 16:01:05.951506900 +0100
@@ -351,12 +351,15 @@
CfgGroup *grp;
Octstr *log, *val;
long loglevel;
+ int lf, m;
#ifdef HAVE_LIBSSL
Octstr *ssl_server_cert_file;
Octstr *ssl_server_key_file;
int ssl_enabled = 0;
#endif /* HAVE_LIBSSL */
+ /* defaults: use localtime and markers for access-log */
+ lf = m = 1;
grp = cfg_get_single_group(cfg, octstr_imm("core"));
@@ -369,14 +372,27 @@
}
if (check_config(cfg) == -1)
- panic(0, "Cannot start with corrupted configuration");
+ panic(0, "Cannot start with corrupted configuration");
- log = cfg_get(grp, octstr_imm("access-log"));
- if (log != NULL) {
- alog_open(octstr_get_cstr(log), 1);
- /* use localtime; XXX let user choose that */
+ /* determine which timezone we use for access logging */
+ if ((log = cfg_get(grp, octstr_imm("access-log-time"))) != NULL) {
+ lf = (octstr_case_compare(log, octstr_imm("gmt")) == 0) ? 0 : 1;
+ octstr_destroy(log);
+ }
- octstr_destroy(log);
+ /* should predefined markers be used, ie. prefixing timestamp */
+ cfg_get_bool(&m, grp, octstr_imm("access-log-clean"));
+
+ /* custom access-log format */
+ if ((log = cfg_get(grp, octstr_imm("access-log-format"))) != NULL) {
+ bb_alog_init(log);
+ octstr_destroy(log);
+ }
+
+ /* open access-log file */
+ if ((log = cfg_get(grp, octstr_imm("access-log"))) != NULL) {
+ alog_open(octstr_get_cstr(log), lf, m ? 0 : 1);
+ octstr_destroy(log);
}
log = cfg_get(grp, octstr_imm("store-file"));
diff -ur ./gw/bearerbox.h ../../cvs/gateway/gw/bearerbox.h
--- ./gw/bearerbox.h 2003-11-24 15:18:32.288592000 +0100
+++ ../../cvs/gateway/gw/bearerbox.h 2003-11-21 16:17:27.623081300 +0100
@@ -62,6 +62,8 @@
#include "gwlib/gwlib.h"
#include "msg.h"
+#include "smscconn.h"
+
/* general bearerbox state */
@@ -196,6 +198,19 @@
/* return all containing messages in the current store */
Octstr *store_status(int status_type);
+
+/*-----------------
+ * bb_alog.c (Custom access-log format handling)
+ */
+
+/* passes the access-log-format string from config to the module */
+void bb_alog_init(Octstr *format);
+
+/* called from bb_smscconn.c to log the various access-log events */
+void bb_alog_sms(SMSCConn *conn, Msg *sms, char *message);
+
+
+
/*----------------------------------------------------------------
* Core bearerbox public functions;
* used only via HTTP adminstration
diff -ur ./gw/smsbox.c ../../cvs/gateway/gw/smsbox.c
--- ./gw/smsbox.c 2003-11-24 15:18:32.308620800 +0100
+++ ../../cvs/gateway/gw/smsbox.c 2003-11-21 15:11:03.674444500 +0100
@@ -3076,12 +3076,14 @@
Octstr *http_proxy_username = NULL;
Octstr *http_proxy_password = NULL;
int ssl = 0;
+ int lf, m;
bb_port = BB_DEFAULT_SMSBOX_PORT;
bb_ssl = 0;
bb_host = octstr_create(BB_DEFAULT_HOST);
logfile = NULL;
lvl = 0;
+ lf = m = 1;
/*
* first we take the port number in bearerbox and other values from the
@@ -3199,12 +3201,20 @@
octstr_get_cstr(global_sender));
}
- p = cfg_get(grp, octstr_imm("access-log"));
- if (p != NULL) {
- info(0, "Logging accesses to '%s'.", octstr_get_cstr(p));
- alog_open(octstr_get_cstr(p), 1);
- /* XXX should be able to use gmtime, too */
- octstr_destroy(p);
+ /* determine which timezone we use for access logging */
+ if ((p = cfg_get(grp, octstr_imm("access-log-time"))) != NULL) {
+ lf = (octstr_case_compare(p, octstr_imm("gmt")) == 0) ? 0 : 1;
+ octstr_destroy(p);
+ }
+
+ /* should predefined markers be used, ie. prefixing timestamp */
+ cfg_get_bool(&m, grp, octstr_imm("access-log-clean"));
+
+ /* open access-log file */
+ if ((p = cfg_get(grp, octstr_imm("access-log"))) != NULL) {
+ info(0, "Logging accesses to '%s'.", octstr_get_cstr(p));
+ alog_open(octstr_get_cstr(p), lf, m ? 0 : 1);
+ octstr_destroy(p);
}
/* HTTP queueing values */
diff -ur ./gw/wapbox.c ../../cvs/gateway/gw/wapbox.c
--- ./gw/wapbox.c 2003-11-24 15:18:32.328649600 +0100
+++ ../../cvs/gateway/gw/wapbox.c 2003-11-21 15:11:08.641586900 +0100
@@ -124,6 +124,9 @@
CfgGroup *grp;
Octstr *s;
Octstr *logfile;
+ int lf, m;
+
+ lf = m = 1;
cfg_dump(cfg);
@@ -179,14 +182,21 @@
log_set_syslog(NULL, 0);
debug("wap", 0, "no syslog parameter");
}
- s = cfg_get(grp, octstr_imm("access-log"));
- if (s != NULL) {
+
+ /* determine which timezone we use for access logging */
+ if ((s = cfg_get(grp, octstr_imm("access-log-time"))) != NULL) {
+ lf = (octstr_case_compare(s, octstr_imm("gmt")) == 0) ? 0 : 1;
+ octstr_destroy(s);
+ }
+
+ /* should predefined markers be used, ie. prefixing timestamp */
+ cfg_get_bool(&m, grp, octstr_imm("access-log-clean"));
+
+ /* open access-log file */
+ if ((s = cfg_get(grp, octstr_imm("access-log"))) != NULL) {
info(0, "Logging accesses to '%s'.", octstr_get_cstr(s));
- alog_open(octstr_get_cstr(s), 1);
- /* XXX should be able to use gmtime, too */
+ alog_open(octstr_get_cstr(s), lf, m ? 0 : 1);
octstr_destroy(s);
- } else {
- debug("wap", 0, "Could not open access-log");
}
/* configure the 'wtls' group */
diff -ur ./gwlib/accesslog.c ../../cvs/gateway/gwlib/accesslog.c
--- ./gwlib/accesslog.c 2003-11-24 15:18:32.348678400 +0100
+++ ../../cvs/gateway/gwlib/accesslog.c 2003-11-21 15:27:16.843793300 +0100
@@ -74,8 +74,8 @@
static FILE *file = NULL;
static char filename[FILENAME_MAX + 1]; /* to allow re-open */
-
static int use_localtime;
+static int markers = 1; /* can be turned-off by 'access-log-clean = yes' */
/*
* Reopen/rotate lock.
@@ -87,7 +87,8 @@
if (file == NULL)
return;
- alog("Log ends");
+ if (markers)
+ alog("Log ends");
list_lock(writers);
/* wait for writers to complete */
@@ -99,10 +100,11 @@
list_unlock(writers);
if (file == NULL) {
- error(errno, "Couldn't re-open access logfile `%s'.",
- filename);
- } else
- alog("Log begins");
+ error(errno, "Couldn't re-open access logfile `%s'.", filename);
+ }
+ else if (markers) {
+ alog("Log begins");
+ }
}
@@ -110,12 +112,13 @@
{
if (file != NULL) {
- alog("Log ends");
+ if (markers)
+ alog("Log ends");
list_lock(writers);
/* wait for writers to complete */
list_consume(writers);
- fclose(file);
- file = NULL;
+ fclose(file);
+ file = NULL;
list_unlock(writers);
list_destroy(writers, NULL);
writers = NULL;
@@ -123,17 +126,20 @@
}
-void alog_open(char *fname, int use_localtm)
+void alog_open(char *fname, int use_localtm, int use_markers)
{
FILE *f;
+ use_localtime = use_localtm;
+ markers = use_markers;
+
if (file != NULL) {
- warning(0, "Opening an already opened access log");
- alog_close();
+ warning(0, "Opening an already opened access log");
+ alog_close();
}
if (strlen(fname) > FILENAME_MAX) {
- error(0, "Access Log filename too long: `%s', cannot open.", fname);
- return;
+ error(0, "Access Log filename too long: `%s', cannot open.", fname);
+ return;
}
if (writers == NULL)
@@ -141,14 +147,14 @@
f = fopen(fname, "a");
if (f == NULL) {
- error(errno, "Couldn't open logfile `%s'.", fname);
- return;
+ error(errno, "Couldn't open logfile `%s'.", fname);
+ return;
}
file = f;
strcpy(filename, fname);
info(0, "Started access logfile `%s'.", filename);
- use_localtime = use_localtm;
- alog("Log begins");
+ if (markers)
+ alog("Log begins");
}
@@ -157,11 +163,13 @@
use_localtime = 1;
}
+
void alog_use_gmtime(void)
{
use_localtime = 0;
}
+
#define FORMAT_SIZE (10*1024)
static void format(char *buf, const char *fmt)
{
@@ -170,23 +178,29 @@
char *p, prefix[1024];
p = prefix;
- time(&t);
- if (use_localtime)
- tm = gw_localtime(t);
- else
- tm = gw_gmtime(t);
-
- sprintf(p, "%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);
+
+ if (markers) {
+ time(&t);
+ if (use_localtime)
+ tm = gw_localtime(t);
+ else
+ tm = gw_gmtime(t);
+
+ sprintf(p, "%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);
+ } else {
+ sprintf(p, "");
+ }
if (strlen(prefix) + strlen(fmt) > FORMAT_SIZE / 2) {
- sprintf(buf, "%s <OUTPUT message too long>\n", prefix);
- return;
+ sprintf(buf, "%s <OUTPUT message too long>\n", prefix);
+ return;
}
sprintf(buf, "%s%s\n", prefix, fmt);
}
+
/* XXX should we also log automatically into main log, too? */
void alog(const char *fmt, ...)
@@ -195,7 +209,7 @@
va_list args;
if (file == NULL)
- return;
+ return;
buf = gw_malloc(FORMAT_SIZE + 1);
format(buf, fmt);
@@ -213,3 +227,4 @@
va_end(args);
gw_free(buf);
}
+
diff -ur ./gwlib/accesslog.h ../../cvs/gateway/gwlib/accesslog.h
--- ./gwlib/accesslog.h 2003-11-24 15:18:32.368707200 +0100
+++ ../../cvs/gateway/gwlib/accesslog.h 2003-11-21 14:30:53.578897300 +0100
@@ -75,7 +75,7 @@
/* open access log with filename fname. if use_localtime != 0 then
* all events are logged with localtime, not GMT
*/
-void alog_open(char *fname, int use_localtime);
+void alog_open(char *fname, int use_localtime, int use_markers);
/* close access log. Do nothing if no open file */
void alog_close(void);
diff -ur ./gwlib/cfg.def ../../cvs/gateway/gwlib/cfg.def
--- ./gwlib/cfg.def 2003-11-24 15:18:32.378721600 +0100
+++ ../../cvs/gateway/gwlib/cfg.def 2003-11-21 14:47:42.830129300 +0100
@@ -94,6 +94,9 @@
OCTSTR(log-file)
OCTSTR(log-level)
OCTSTR(access-log)
+ OCTSTR(access-log-time)
+ OCTSTR(access-log-format)
+ OCTSTR(access-log-clean)
OCTSTR(store-file)
OCTSTR(unified-prefix)
OCTSTR(white-list)
diff -urN ./gw/bb_alog.c ../../cvs/gateway/gw/bb_alog.c
--- ./gw/bb_alog.c 1970-01-01 01:00:00.000000000 +0100
+++ ../../cvs/gateway/gw/bb_alog.c 2003-11-24 15:32:59.816035200 +0100
@@ -0,0 +1,368 @@
+/* ====================================================================
+ * The Kannel Software License, Version 1.0
+ *
+ * Copyright (c) 2001-2003 Kannel Group
+ * Copyright (c) 1998-2001 WapIT Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Kannel Group (http://www.kannel.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Kannel" and "Kannel Group" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please
+ * contact [email protected].
+ *
+ * 5. Products derived from this software may not be called "Kannel",
+ * nor may "Kannel" appear in their name, without prior written
+ * permission of the Kannel Group.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Kannel Group. For more information on
+ * the Kannel Group, please see <http://www.kannel.org/>.
+ *
+ * Portions of this software are based upon software originally written at
+ * WapIT Ltd., Helsinki, Finland for the Kannel project.
+ */
+
+/*
+ * gw/bb_alog.c -- encapsulate custom access log logic and escape code parsing
+ *
+ * Stipe Tolj <[email protected]
+ */
+
+#include "gwlib/gwlib.h"
+#include "msg.h"
+#include "sms.h"
+#include "bearerbox.h"
+#include "smscconn.h"
+
+static Octstr *custom_log_format = NULL;
+
+
+/********************************************************************
+ * Routine to escape the values into the custom log format.
+ *
+ * The following escape code values are acceptable within the
+ * 'access-log-format' config directive of bearerbox:
+ *
+ * %l - log message
+ * %i - smsc-id
+ * %n - service-name (for MO) or sendsms-user (for MT)
+ * %A - account
+ * %B - billing identifier/information
+ * %p - sender (from)
+ * %P - receiver (to)
+ * %m - message class (mclass)
+ * %c - coding
+ * %M - message waiting indicator (mwi)
+ * %C - compress indicator
+ * %d - dlr_mask
+ * %a - the orginal SMS message, spaces squeezed
+ * %u - UDH data (in escaped form)
+ * %U - length of UDH data
+ * %k - the keyword in the SMS request (the first word in the SMS message)
+ * %s - next word from the SMS message, starting with the second one
+ * %S - same as %s, but '*' is converted to '~'
+ * %r - words not yet used by %s
+ * %b - the orginal SMS message
+ * %L - length of SMS message
+ * %t - the time of the message, formatted as "YYYY-MM-DD HH:MM:SS"
+ * %T - the time of the message, in UNIX epoch timestamp format
+ * %I - the internal message ID
+ *
+ * Most escape codes should be compatibel with escape codes used in
+ * sms-service groups.
+ *
+ * The default access-log-format would look like this (if access-log-clean is true):
+ * "%t %l [SMSC:%i] [SVC:%n] [ACT:%A] [BINF:%B] [from:%p] [to:%P] \
+ * [flags:%m:%c:%M:%C:%d] [msg:%L:%b] [udh:%U:%u]"
+ */
+
+static Octstr *get_pattern(SMSCConn *conn, Msg *msg, char *message)
+{
+ 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, *text, *udh;
+
+ text = msg->sms.msgdata ? octstr_duplicate(msg->sms.msgdata) : octstr_create("");
+ udh = msg->sms.udhdata ? octstr_duplicate(msg->sms.udhdata) : octstr_create("");
+ if ((msg->sms.coding == DC_8BIT || msg->sms.coding == DC_UCS2))
+ octstr_binary_to_hex(text, 1);
+ octstr_binary_to_hex(udh, 1);
+
+ if (octstr_len(text)) {
+ word_list = octstr_split_words(text);
+ num_words = list_len(word_list);
+ } else {
+ word_list = list_create();
+ num_words = 0;
+ }
+
+ result = octstr_create("");
+ pattern = octstr_duplicate(custom_log_format);
+
+ 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;
+ octstr_append(result, list_get(word_list, 0));
+ break;
+
+ case 's':
+ if (nextarg >= num_words)
+ break;
+ octstr_append(result, list_get(word_list, nextarg));
+ ++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) {
+ if (j != nextarg)
+ octstr_append_char(result, '+');
+ octstr_append(result, list_get(word_list, j));
+ }
+ break;
+
+ case 'l':
+ octstr_append_cstr(result, message);
+ break;
+
+ case 'P':
+ octstr_append(result, msg->sms.receiver);
+ break;
+
+ case 'p':
+ octstr_append(result, msg->sms.sender);
+ break;
+
+ case 'a':
+ for (j = 0; j < num_words; ++j) {
+ if (j > 0)
+ octstr_append_char(result, ' ');
+ octstr_append(result, list_get(word_list, j));
+ }
+ break;
+
+ case 'b':
+ octstr_append(result, text);
+ break;
+
+ case 'L':
+ octstr_append_decimal(result, octstr_len(msg->sms.msgdata));
+ break;
+
+ case 't':
+ tm = gw_gmtime(msg->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 (msg->sms.time == -1)
+ break;
+ octstr_format_append(result, "%ld", msg->sms.time);
+ break;
+
+ case 'i':
+ if (msg->sms.smsc_id == NULL)
+ break;
+ octstr_append(result, msg->sms.smsc_id);
+ break;
+
+ case 'I':
+ if (msg->sms.id == -1)
+ break;
+ octstr_format_append(result, "%ld", msg->sms.id);
+ break;
+
+ case 'n':
+ if (msg->sms.service == NULL)
+ break;
+ octstr_append(result, msg->sms.service);
+ break;
+
+ case 'd':
+ octstr_append_decimal(result, msg->sms.dlr_mask);
+ break;
+
+ case 'c':
+ octstr_append_decimal(result, msg->sms.coding);
+ break;
+
+ case 'm':
+ octstr_append_decimal(result, msg->sms.mclass);
+ break;
+
+ case 'C':
+ octstr_append_decimal(result, msg->sms.compress);
+ break;
+
+ case 'M':
+ octstr_append_decimal(result, msg->sms.mwi);
+ break;
+
+ case 'u':
+ if (octstr_len(udh)) {
+ octstr_append(result, udh);
+ }
+ break;
+
+ case 'U':
+ octstr_append_decimal(result, octstr_len(msg->sms.udhdata));
+ break;
+
+ case 'B': /* billing identifier/information */
+ if (octstr_len(msg->sms.binfo)) {
+ octstr_append(result, msg->sms.binfo);
+ }
+ break;
+
+ case 'A': /* account */
+ if (octstr_len(msg->sms.account)) {
+ octstr_append(result, msg->sms.account);
+ }
+ break;
+
+ /* XXX add more here if needed */
+
+ case '%':
+ octstr_format_append(result, "%%");
+ break;
+
+ default:
+ octstr_format_append(result, "%%%c",
+ octstr_get_char(pattern, pos + 1));
+ break;
+ }
+
+ pos += 2;
+ }
+
+ list_destroy(word_list, octstr_destroy_item);
+
+ return result;
+}
+
+
+/********************************************************************
+ *
+ */
+
+void bb_alog_init(Octstr *format)
+{
+ gw_assert(format != NULL);
+
+ custom_log_format = octstr_duplicate(format);
+}
+
+
+void bb_alog_sms(SMSCConn *conn, Msg *sms, char *message)
+{
+ Octstr *text, *udh;
+
+ text = udh = NULL;
+
+ /* if we don't have any custom log, then use our "default" one */
+
+ if (custom_log_format == NULL) {
+ text = sms->sms.msgdata ? octstr_duplicate(sms->sms.msgdata) : octstr_create("");
+ udh = sms->sms.udhdata ? octstr_duplicate(sms->sms.udhdata) : octstr_create("");
+ if ((sms->sms.coding == DC_8BIT || sms->sms.coding == DC_UCS2))
+ octstr_binary_to_hex(text, 1);
+ octstr_binary_to_hex(udh, 1);
+
+ alog("%s [SMSC:%s] [SVC:%s] [ACT:%s] [BINF:%s] [from:%s] [to:%s] [flags:%d:%d:%d:%d:%d] "
+ "[msg:%d:%s] [udh:%d:%s]",
+ message,
+ conn ? (smscconn_id(conn) ? octstr_get_cstr(smscconn_id(conn)) : "") : "",
+ sms->sms.service ? octstr_get_cstr(sms->sms.service) : "",
+ sms->sms.account ? octstr_get_cstr(sms->sms.account) : "",
+ sms->sms.binfo ? octstr_get_cstr(sms->sms.binfo) : "",
+ sms->sms.sender ? octstr_get_cstr(sms->sms.sender) : "",
+ sms->sms.receiver ? octstr_get_cstr(sms->sms.receiver) : "",
+ sms->sms.mclass, sms->sms.coding, sms->sms.mwi, sms->sms.compress,
+ sms->sms.dlr_mask,
+ octstr_len(sms->sms.msgdata), octstr_get_cstr(text),
+ octstr_len(sms->sms.udhdata), octstr_get_cstr(udh)
+ );
+
+ } else {
+ text = get_pattern(conn, sms, message);
+ alog("%s", octstr_get_cstr(text));
+ }
+
+ octstr_destroy(udh);
+ octstr_destroy(text);
+}
+