Main Page | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

bb_alog.c

Go to the documentation of this file.
00001 /* ==================================================================== 
00002  * The Kannel Software License, Version 1.0 
00003  * 
00004  * Copyright (c) 2001-2008 Kannel Group  
00005  * Copyright (c) 1998-2001 WapIT Ltd.   
00006  * All rights reserved. 
00007  * 
00008  * Redistribution and use in source and binary forms, with or without 
00009  * modification, are permitted provided that the following conditions 
00010  * are met: 
00011  * 
00012  * 1. Redistributions of source code must retain the above copyright 
00013  *    notice, this list of conditions and the following disclaimer. 
00014  * 
00015  * 2. Redistributions in binary form must reproduce the above copyright 
00016  *    notice, this list of conditions and the following disclaimer in 
00017  *    the documentation and/or other materials provided with the 
00018  *    distribution. 
00019  * 
00020  * 3. The end-user documentation included with the redistribution, 
00021  *    if any, must include the following acknowledgment: 
00022  *       "This product includes software developed by the 
00023  *        Kannel Group (http://www.kannel.org/)." 
00024  *    Alternately, this acknowledgment may appear in the software itself, 
00025  *    if and wherever such third-party acknowledgments normally appear. 
00026  * 
00027  * 4. The names "Kannel" and "Kannel Group" must not be used to 
00028  *    endorse or promote products derived from this software without 
00029  *    prior written permission. For written permission, please  
00030  *    contact org@kannel.org. 
00031  * 
00032  * 5. Products derived from this software may not be called "Kannel", 
00033  *    nor may "Kannel" appear in their name, without prior written 
00034  *    permission of the Kannel Group. 
00035  * 
00036  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED 
00037  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 
00038  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
00039  * DISCLAIMED.  IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS 
00040  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,  
00041  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  
00042  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR  
00043  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,  
00044  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE  
00045  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,  
00046  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
00047  * ==================================================================== 
00048  * 
00049  * This software consists of voluntary contributions made by many 
00050  * individuals on behalf of the Kannel Group.  For more information on  
00051  * the Kannel Group, please see <http://www.kannel.org/>. 
00052  * 
00053  * Portions of this software are based upon software originally written at  
00054  * WapIT Ltd., Helsinki, Finland for the Kannel project.  
00055  */ 
00056 
00057 /*
00058  * gw/bb_alog.c -- encapsulate custom access log logic and escape code parsing
00059  *
00060  * Stipe Tolj <stolj@wapme.de>
00061  * Alexander Malysh <a.malysh@centrium.de>
00062  */
00063 
00064 #include "gwlib/gwlib.h"
00065 #include "msg.h"
00066 #include "sms.h"
00067 #include "bearerbox.h"
00068 #include "smscconn.h"
00069 
00070 static Octstr *custom_log_format = NULL;
00071 
00072 
00073 /********************************************************************
00074  * Routine to escape the values into the custom log format.
00075  *
00076  * The following escape code values are acceptable within the 
00077  * 'access-log-format' config directive of bearerbox:
00078  *
00079  *   %l - log message
00080  *   %i - smsc-id
00081  *   %n - service-name (for MO) or sendsms-user (for MT)
00082  *   %A - account
00083  *   %B - billing identifier/information
00084  *   %p - sender (from) 
00085  *   %P - receiver (to)
00086  *   %m - message class (mclass)
00087  *   %c - coding
00088  *   %M - message waiting indicator (mwi)
00089  *   %C - compress indicator
00090  *   %d - dlr_mask
00091  *   %a - the original SMS message, spaces squeezed
00092  *   %u - UDH data (in escaped form)
00093  *   %U - length of UDH data
00094  *   %k - the keyword in the SMS request (the first word in the SMS message) 
00095  *   %s - next word from the SMS message, starting with the second one
00096  *   %S - same as %s, but '*' is converted to '~' 
00097  *   %r - words not yet used by %s
00098  *   %b - the original SMS message
00099  *   %L - length of SMS message
00100  *   %t - the time of the message, formatted as "YYYY-MM-DD HH:MM:SS"
00101  *   %T - the time of the message, in UNIX epoch timestamp format
00102  *   %I - the internal message ID
00103  *
00104  * Most escape codes should be compatible with escape codes used in
00105  * sms-service groups.
00106  *
00107  * The default access-log-format would look like this (if access-log-clean is true):
00108  *   "%t %l [SMSC:%i] [SVC:%n] [ACT:%A] [BINF:%B] [from:%p] [to:%P] \
00109  *    [flags:%m:%c:%M:%C:%d] [msg:%L:%b] [udh:%U:%u]"
00110  */
00111   
00112 static Octstr *get_pattern(SMSCConn *conn, Msg *msg, const char *message)
00113 {
00114     int nextarg, j;
00115     struct tm tm;
00116     int num_words;
00117     List *word_list;
00118     Octstr *result;
00119     const char *pattern;
00120     Octstr *temp, *text, *udh;
00121     size_t n;
00122     long i;
00123  
00124     text = msg->sms.msgdata ? octstr_duplicate(msg->sms.msgdata) : octstr_create("");
00125     udh = msg->sms.udhdata ? octstr_duplicate(msg->sms.udhdata) : octstr_create("");
00126     if ((msg->sms.coding == DC_8BIT || msg->sms.coding == DC_UCS2))
00127         octstr_binary_to_hex(text, 1);
00128     else
00129         octstr_convert_printable(text);
00130     octstr_binary_to_hex(udh, 1);
00131 
00132     if (octstr_len(text)) {
00133         word_list = octstr_split_words(text);
00134         num_words = gwlist_len(word_list);
00135     } else {
00136         word_list = gwlist_create();
00137         num_words = 0;
00138     }
00139 
00140     result = octstr_create("");
00141     pattern = octstr_get_cstr(custom_log_format);
00142 
00143     nextarg = 1;
00144 
00145     while(*pattern != '\0') {
00146         n = strcspn(pattern, "%");
00147         octstr_append_data(result, pattern, n);
00148         pattern += n;
00149         gw_assert(*pattern == '%' || *pattern == '\0');
00150         if (*pattern == '\0')
00151             break;
00152 
00153         pattern++;
00154         
00155         switch (*pattern) {
00156     case 'k':
00157         if (num_words <= 0)
00158                 break;
00159         octstr_append(result, gwlist_get(word_list, 0));
00160         break;
00161 
00162     case 's':
00163         if (nextarg >= num_words)
00164                 break;
00165         octstr_append(result, gwlist_get(word_list, nextarg));
00166         ++nextarg;
00167         break;
00168 
00169     case 'S':
00170         if (nextarg >= num_words)
00171                 break;
00172         temp = gwlist_get(word_list, nextarg);
00173         for (i = 0; i < octstr_len(temp); ++i) {
00174         if (octstr_get_char(temp, i) == '*')
00175             octstr_append_char(result, '~');
00176         else
00177             octstr_append_char(result, octstr_get_char(temp, i));
00178         }
00179         ++nextarg;
00180         break;
00181 
00182     case 'r':
00183         for (j = nextarg; j < num_words; ++j) {
00184         if (j != nextarg)
00185             octstr_append_char(result, '+');
00186         octstr_append(result, gwlist_get(word_list, j));
00187         }
00188         break;
00189     
00190     case 'l':
00191             if (message)
00192             octstr_append_cstr(result, message);
00193         break;
00194 
00195     case 'P':
00196             if (msg->sms.receiver)
00197             octstr_append(result, msg->sms.receiver);
00198         break;
00199 
00200     case 'p':
00201             if (msg->sms.sender)
00202             octstr_append(result, msg->sms.sender);
00203         break;
00204 
00205     case 'a':
00206         for (j = 0; j < num_words; ++j) {
00207                 if (j > 0)
00208                     octstr_append_char(result, ' ');
00209                 octstr_append(result, gwlist_get(word_list, j));
00210             }
00211             break;
00212 
00213     case 'b':
00214             if (text)
00215             octstr_append(result, text);
00216         break;
00217 
00218     case 'L':
00219         octstr_append_decimal(result, octstr_len(msg->sms.msgdata));
00220         break;
00221 
00222     case 't':
00223         tm = gw_gmtime(msg->sms.time);
00224         octstr_format_append(result, "%04d-%02d-%02d %02d:%02d:%02d",
00225                  tm.tm_year + 1900,
00226                  tm.tm_mon + 1,
00227                  tm.tm_mday,
00228                  tm.tm_hour,
00229                  tm.tm_min,
00230                  tm.tm_sec);
00231         break;
00232 
00233     case 'T':
00234         if (msg->sms.time != MSG_PARAM_UNDEFINED)
00235             octstr_format_append(result, "%ld", msg->sms.time);
00236         break;
00237 
00238     case 'i':
00239         if (conn && smscconn_id(conn))
00240             octstr_append(result, smscconn_id(conn));
00241         else if (conn && smscconn_name(conn))
00242             octstr_append(result, smscconn_name(conn));
00243         else if (msg->sms.smsc_id)
00244             octstr_append(result, msg->sms.smsc_id);
00245         break;
00246 
00247     case 'I':
00248         if (!uuid_is_null(msg->sms.id)) {
00249                 char id[UUID_STR_LEN + 1];
00250                 uuid_unparse(msg->sms.id, id);
00251             octstr_append_cstr(result, id);
00252             }
00253         break;
00254 
00255     case 'n':
00256         if (msg->sms.service != NULL)
00257             octstr_append(result, msg->sms.service);
00258         break;
00259 
00260     case 'd':
00261         octstr_append_decimal(result, msg->sms.dlr_mask);
00262         break;
00263 
00264     case 'c':
00265         octstr_append_decimal(result, msg->sms.coding);
00266         break;
00267 
00268     case 'm':
00269         octstr_append_decimal(result, msg->sms.mclass);
00270         break;
00271 
00272     case 'C':
00273         octstr_append_decimal(result, msg->sms.compress);
00274         break;
00275 
00276     case 'M':
00277         octstr_append_decimal(result, msg->sms.mwi);
00278         break;
00279 
00280     case 'u':
00281         if (octstr_len(udh)) {
00282                 octstr_append(result, udh);
00283         }
00284         break;
00285 
00286     case 'U':
00287         octstr_append_decimal(result, octstr_len(msg->sms.udhdata));
00288         break;
00289 
00290     case 'B':  /* billing identifier/information */
00291         if (octstr_len(msg->sms.binfo)) {
00292                 octstr_append(result, msg->sms.binfo);
00293             }
00294             break;
00295 
00296     case 'A':  /* account */
00297         if (octstr_len(msg->sms.account)) {
00298                 octstr_append(result, msg->sms.account);
00299             }
00300             break;
00301 
00302         /* XXX add more here if needed */
00303 
00304     case '%':
00305         octstr_format_append(result, "%%");
00306         break;
00307 
00308     default:
00309         warning(0, "Unknown escape code (%%%c) within custom-log-format, skipping!", *pattern);
00310             octstr_format_append(result, "%%%c", *pattern);
00311         break;
00312         } /* switch(...) */
00313     
00314         pattern++;
00315     } /* for ... */
00316 
00317     gwlist_destroy(word_list, octstr_destroy_item);
00318 
00319     return result;
00320 }
00321 
00322 
00323 /********************************************************************
00324  * 
00325  */
00326 
00327 void bb_alog_init(const Octstr *format)
00328 {
00329     gw_assert(format != NULL);
00330 
00331     custom_log_format = octstr_duplicate(format);
00332 }
00333 
00334 
00335 void bb_alog_shutdown(void)
00336 {
00337     octstr_destroy(custom_log_format);
00338     custom_log_format = NULL;
00339 }
00340 
00341 
00342 void bb_alog_sms(SMSCConn *conn, Msg *msg, const char *message)
00343 {
00344     Octstr *text = NULL;
00345     
00346     gw_assert(msg_type(msg) == sms);
00347 
00348     /* if we don't have any custom log, then use our "default" one */
00349     
00350     if (custom_log_format == NULL) {
00351         Octstr *udh;
00352         const Octstr *cid;
00353 
00354         text = msg->sms.msgdata ? octstr_duplicate(msg->sms.msgdata) : octstr_create("");
00355         udh = msg->sms.udhdata ? octstr_duplicate(msg->sms.udhdata) : octstr_create("");
00356 
00357         if (conn && smscconn_id(conn))
00358             cid = smscconn_id(conn);
00359         else if (conn && smscconn_name(conn))
00360             cid = smscconn_name(conn);
00361         else if (msg->sms.smsc_id)
00362             cid = msg->sms.smsc_id;
00363         else
00364             cid = octstr_imm("");
00365 
00366         if ((msg->sms.coding == DC_8BIT || msg->sms.coding == DC_UCS2))
00367             octstr_binary_to_hex(text, 1);
00368         else
00369             octstr_convert_printable(text);
00370         octstr_binary_to_hex(udh, 1);
00371 
00372         alog("%s [SMSC:%s] [SVC:%s] [ACT:%s] [BINF:%s] [from:%s] [to:%s] [flags:%ld:%ld:%ld:%ld:%ld] "
00373              "[msg:%ld:%s] [udh:%ld:%s]",
00374              message,
00375              octstr_get_cstr(cid),
00376              msg->sms.service ? octstr_get_cstr(msg->sms.service) : "",
00377              msg->sms.account ? octstr_get_cstr(msg->sms.account) : "",
00378              msg->sms.binfo ? octstr_get_cstr(msg->sms.binfo) : "",
00379              msg->sms.sender ? octstr_get_cstr(msg->sms.sender) : "",
00380              msg->sms.receiver ? octstr_get_cstr(msg->sms.receiver) : "",
00381              msg->sms.mclass, msg->sms.coding, msg->sms.mwi, msg->sms.compress,
00382              msg->sms.dlr_mask, 
00383              octstr_len(msg->sms.msgdata), octstr_get_cstr(text),
00384              octstr_len(msg->sms.udhdata), octstr_get_cstr(udh)
00385         );
00386 
00387         octstr_destroy(udh);
00388     } else {
00389         text = get_pattern(conn, msg, message);
00390         alog("%s", octstr_get_cstr(text));
00391     }
00392 
00393     octstr_destroy(text);
00394 }
00395 
00396 
See file LICENSE for details about the license agreement for using, modifying, copying or deriving work from this software.