another round of version tag updates, along with 'show version files' pattern filtering
[asterisk/asterisk.git] / cdr / cdr_sqlite.c
1 /*
2  * Asterisk -- A telephony toolkit for Linux.
3  *
4  * Store CDR records in a SQLite database.
5  * 
6  * Copyright (C) 2004 - 2005, Holger Schurig
7  *
8  * Holger Schurig <hs4233@mail.mn-solutions.de>
9  *
10  * This program is free software, distributed under the terms of
11  * the GNU General Public License.
12  *
13  * Ideas taken from other cdr_*.c files
14  */
15
16 #include <sys/types.h>
17
18 #include <unistd.h>
19 #include <string.h>
20 #include <stdlib.h>
21 #include <sqlite.h>
22
23 #include "asterisk.h"
24
25 ASTERISK_FILE_VERSION("$Revision$")
26
27 #include "asterisk/channel.h"
28 #include "asterisk/module.h"
29 #include "asterisk/logger.h"
30 #include "asterisk/utils.h"
31
32 #define LOG_UNIQUEID    0
33 #define LOG_USERFIELD   0
34
35 /* When you change the DATE_FORMAT, be sure to change the CHAR(19) below to something else */
36 #define DATE_FORMAT "%Y-%m-%d %T"
37
38 static char *desc = "SQLite CDR Backend";
39 static char *name = "sqlite";
40 static sqlite* db = NULL;
41
42 AST_MUTEX_DEFINE_STATIC(sqlite_lock);
43
44 static char sql_create_table[] = "CREATE TABLE cdr ("
45 "       AcctId          INTEGER PRIMARY KEY,"
46 "       clid            VARCHAR(80),"
47 "       src             VARCHAR(80),"
48 "       dst             VARCHAR(80),"
49 "       dcontext        VARCHAR(80),"
50 "       channel         VARCHAR(80),"
51 "       dstchannel      VARCHAR(80),"
52 "       lastapp         VARCHAR(80),"
53 "       lastdata        VARCHAR(80),"
54 "       start           CHAR(19),"
55 "       answer          CHAR(19),"
56 "       end             CHAR(19),"
57 "       duration        INTEGER,"
58 "       billsec         INTEGER,"
59 "       disposition     INTEGER,"
60 "       amaflags        INTEGER,"
61 "       accountcode     VARCHAR(20)"
62 #if LOG_UNIQUEID
63 "       ,uniqueid       VARCHAR(32)"
64 #endif
65 #if LOG_USERFIELD
66 "       ,userfield      VARCHAR(255)"
67 #endif
68 ");";
69
70 static int sqlite_log(struct ast_cdr *cdr)
71 {
72         int res = 0;
73         char *zErr = 0;
74         struct tm tm;
75         time_t t;
76         char startstr[80], answerstr[80], endstr[80];
77         int count;
78
79         ast_mutex_lock(&sqlite_lock);
80
81         t = cdr->start.tv_sec;
82         localtime_r(&t, &tm);
83         strftime(startstr, sizeof(startstr), DATE_FORMAT, &tm);
84
85         t = cdr->answer.tv_sec;
86         localtime_r(&t, &tm);
87         strftime(answerstr, sizeof(answerstr), DATE_FORMAT, &tm);
88
89         t = cdr->end.tv_sec;
90         localtime_r(&t, &tm);
91         strftime(endstr, sizeof(endstr), DATE_FORMAT, &tm);
92
93         for(count=0; count<5; count++) {
94                 res = sqlite_exec_printf(db,
95                         "INSERT INTO cdr ("
96                                 "clid,src,dst,dcontext,"
97                                 "channel,dstchannel,lastapp,lastdata, "
98                                 "start,answer,end,"
99                                 "duration,billsec,disposition,amaflags, "
100                                 "accountcode"
101 #                               if LOG_UNIQUEID
102                                 ",uniqueid"
103 #                               endif
104 #                               if LOG_USERFIELD
105                                 ",userfield"
106 #                               endif
107                         ") VALUES ("
108                                 "'%q', '%q', '%q', '%q', "
109                                 "'%q', '%q', '%q', '%q', "
110                                 "'%q', '%q', '%q', "
111                                 "%d, %d, %d, %d, "
112                                 "'%q'"
113 #                               if LOG_UNIQUEID
114                                 ",'%q'"
115 #                               endif
116 #                               if LOG_USERFIELD
117                                 ",'%q'"
118 #                               endif
119                         ")", NULL, NULL, &zErr,
120                                 cdr->clid, cdr->src, cdr->dst, cdr->dcontext,
121                                 cdr->channel, cdr->dstchannel, cdr->lastapp, cdr->lastdata,
122                                 startstr, answerstr, endstr,
123                                 cdr->duration, cdr->billsec, cdr->disposition, cdr->amaflags,
124                                 cdr->accountcode
125 #                               if LOG_UNIQUEID
126                                 ,cdr->uniqueid
127 #                               endif
128 #                               if LOG_USERFIELD
129                                 ,cdr->userfield
130 #                               endif
131                         );
132                 if (res != SQLITE_BUSY && res != SQLITE_LOCKED)
133                         break;
134                 usleep(200);
135         }
136         
137         if (zErr) {
138                 ast_log(LOG_ERROR, "cdr_sqlite: %s\n", zErr);
139                 free(zErr);
140         }
141
142         ast_mutex_unlock(&sqlite_lock);
143         return res;
144 }
145
146
147 char *description(void)
148 {
149         return desc;
150 }
151
152 int unload_module(void)
153 {
154         if (db)
155                 sqlite_close(db);
156         ast_cdr_unregister(name);
157         return 0;
158 }
159
160 int load_module(void)
161 {
162         char *zErr;
163         char fn[PATH_MAX];
164         int res;
165
166         /* is the database there? */
167         snprintf(fn, sizeof(fn), "%s/cdr.db", ast_config_AST_LOG_DIR);
168         db = sqlite_open(fn, 0660, &zErr);
169         if (!db) {
170                 ast_log(LOG_ERROR, "cdr_sqlite: %s\n", zErr);
171                 free(zErr);
172                 return -1;
173         }
174
175         /* is the table there? */
176         res = sqlite_exec(db, "SELECT COUNT(AcctId) FROM cdr;", NULL, NULL, NULL);
177         if (res) {
178                 res = sqlite_exec(db, sql_create_table, NULL, NULL, &zErr);
179                 if (res) {
180                         ast_log(LOG_ERROR, "cdr_sqlite: Unable to create table 'cdr': %s\n", zErr);
181                         free(zErr);
182                         goto err;
183                 }
184
185                 /* TODO: here we should probably create an index */
186         }
187         
188         res = ast_cdr_register(name, desc, sqlite_log);
189         if (res) {
190                 ast_log(LOG_ERROR, "Unable to register SQLite CDR handling\n");
191                 return -1;
192         }
193         return 0;
194
195 err:
196         if (db)
197                 sqlite_close(db);
198         return -1;
199 }
200
201 int reload(void)
202 {
203         return 0;
204 }
205
206 int usecount(void)
207 {
208         return 0;
209 }
210
211 char *key()
212 {
213         return ASTERISK_GPL_KEY;
214 }