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 org@kannel.org. 
+ * 
+ * 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 <tolj@wapme-systems.de
+ */
+
+#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);
+}
+
