2 * libsql database service
4 * Part of Gammu project
6 * Copyright (C) 2009-2011 Michal Čihař
7 * (c) 2010 Miloslav Semler
9 * Licensed under GNU GPL version 2 or later
16 #include "../../helper/strptime.h"
30 #include "../../helper/string.h"
32 /* FIXME: I know this is broken, need to figure out better way */
33 const char now_plus_odbc
[] = "{fn CURRENT_TIMESTAMP()} + INTERVAL %d SECOND";
34 const char now_plus_mysql
[] = "(NOW() + INTERVAL %d SECOND) + 0";
35 const char now_plus_pgsql
[] = "now() + interval '%d seconds'";
36 const char now_plus_sqlite
[] = "datetime('now', '+%d seconds')";
37 const char now_plus_freetds
[] = "DATEADD('second', %d, CURRENT_TIMESTAMP)";
38 const char now_plus_access
[] = "now()+#00:00:%d#";
39 const char now_plus_fallback
[] = "NOW() + INTERVAL %d SECOND";
41 /* configurable SQL queries */
42 char * SMSDSQL_queries
[SQL_QUERY_LAST_NO
];
44 static const char *SMSDSQL_NowPlus(GSM_SMSDConfig
* Config
, int seconds
)
46 const char *driver_name
;
47 static char result
[100];
49 if (Config
->sql
!= NULL
) {
50 driver_name
= Config
->sql
;
52 driver_name
= Config
->driver
;
55 if (strcasecmp(driver_name
, "mysql") == 0 || strcasecmp(driver_name
, "native_mysql") == 0) {
56 sprintf(result
, now_plus_mysql
, seconds
);
57 } else if (strcasecmp(driver_name
, "pgsql") == 0 || strcasecmp(driver_name
, "native_pgsql") == 0) {
58 sprintf(result
, now_plus_pgsql
, seconds
);
59 } else if (strncasecmp(driver_name
, "sqlite", 6) == 0) {
60 sprintf(result
, now_plus_sqlite
, seconds
);
61 } else if (strcasecmp(driver_name
, "freetds") == 0) {
62 sprintf(result
, now_plus_freetds
, seconds
);
63 } else if (strcasecmp(driver_name
, "access") == 0) {
64 sprintf(result
, now_plus_access
, seconds
);
65 } else if (strcasecmp(driver_name
, "odbc") == 0) {
66 sprintf(result
, now_plus_odbc
, seconds
);
68 sprintf(result
, now_plus_fallback
, seconds
);
73 const char escape_char_odbc
[] = "";
74 const char escape_char_mysql
[] = "`";
75 const char escape_char_pgsql
[] = "\"";
76 const char escape_char_sqlite
[] = "";
77 const char escape_char_freetds
[] = "";
78 const char escape_char_fallback
[] = "";
80 static const char *SMSDSQL_EscapeChar(GSM_SMSDConfig
* Config
)
82 const char *driver_name
;
84 if (Config
->sql
!= NULL
) {
85 driver_name
= Config
->sql
;
87 driver_name
= Config
->driver
;
90 if (strcasecmp(driver_name
, "mysql") == 0 || strcasecmp(driver_name
, "native_mysql") == 0) {
91 return escape_char_mysql
;
92 } else if (strcasecmp(driver_name
, "pgsql") == 0 || strcasecmp(driver_name
, "native_pgsql") == 0) {
93 return escape_char_pgsql
;
94 } else if (strncasecmp(driver_name
, "sqlite", 6) == 0) {
95 return escape_char_sqlite
;
96 } else if (strcasecmp(driver_name
, "freetds") == 0 || strcasecmp(driver_name
, "mssql") == 0 || strcasecmp(driver_name
, "sybase") == 0) {
97 return escape_char_freetds
;
98 } else if (strcasecmp(Config
->driver
, "odbc") == 0) {
99 return escape_char_odbc
;
101 return escape_char_fallback
;
105 const char top_clause_access
[] = "TOP";
106 const char top_clause_fallback
[] = "";
108 static const char *SMSDSQL_TopClause(GSM_SMSDConfig
* Config
, const char *count
)
110 const char *driver_name
;
111 static char result
[100];
113 if (Config
->sql
!= NULL
) {
114 driver_name
= Config
->sql
;
116 driver_name
= Config
->driver
;
119 if (strcasecmp(driver_name
, "access") == 0) {
120 strcpy(result
, top_clause_access
);
122 strcat(result
, count
);
125 return top_clause_fallback
;
129 const char limit_clause_access
[] = "";
130 const char limit_clause_fallback
[] = "LIMIT";
132 static const char *SMSDSQL_LimitClause(GSM_SMSDConfig
* Config
, const char *count
)
134 const char *driver_name
;
135 static char result
[100];
137 if (Config
->sql
!= NULL
) {
138 driver_name
= Config
->sql
;
140 driver_name
= Config
->driver
;
143 if (strcasecmp(driver_name
, "access") == 0) {
144 return limit_clause_access
;
146 strcpy(result
, limit_clause_fallback
);
148 strcat(result
, count
);
153 const char now_odbc
[] = "{fn CURRENT_TIMESTAMP()}";
154 const char now_mysql
[] = "NOW()";
155 const char now_pgsql
[] = "now()";
156 const char now_sqlite
[] = "datetime('now')";
157 const char now_freetds
[] = "CURRENT_TIMESTAMP";
158 const char now_access
[] = "now()";
159 const char now_fallback
[] = "NOW()";
161 const char currtime_odbc
[] = "{fn CURTIME()}";
162 const char currtime_mysql
[] = "CURTIME()";
163 const char currtime_pgsql
[] = "localtime";
164 const char currtime_sqlite
[] = "time('now')";
165 const char currtime_freetds
[] = "CURRENT_TIME";
166 const char currtime_fallback
[] = "CURTIME()";
168 static const char *SMSDSQL_CurrentTime(GSM_SMSDConfig
* Config
)
170 const char *driver_name
;
172 if (Config
->sql
!= NULL
) {
173 driver_name
= Config
->sql
;
175 driver_name
= Config
->driver
;
178 if (strcasecmp(driver_name
, "mysql") == 0 || strcasecmp(driver_name
, "native_mysql") == 0) {
179 return currtime_mysql
;
180 } else if (strcasecmp(driver_name
, "pgsql") == 0 || strcasecmp(driver_name
, "native_pgsql") == 0) {
181 return currtime_pgsql
;
182 } else if (strncasecmp(driver_name
, "sqlite", 6) == 0) {
183 return currtime_sqlite
;
184 } else if (strcasecmp(driver_name
, "freetds") == 0 || strcasecmp(driver_name
, "mssql") == 0 || strcasecmp(driver_name
, "sybase") == 0) {
185 return currtime_freetds
;
186 } else if (strcasecmp(Config
->driver
, "odbc") == 0) {
187 return currtime_odbc
;
189 return currtime_fallback
;
192 static const char *SMSDSQL_Now(GSM_SMSDConfig
* Config
)
194 const char *driver_name
;
196 if (Config
->sql
!= NULL
) {
197 driver_name
= Config
->sql
;
199 driver_name
= Config
->driver
;
202 if (strcasecmp(driver_name
, "mysql") == 0 || strcasecmp(driver_name
, "native_mysql") == 0) {
204 } else if (strcasecmp(driver_name
, "pgsql") == 0 || strcasecmp(driver_name
, "native_pgsql") == 0) {
206 } else if (strncasecmp(driver_name
, "sqlite", 6) == 0) {
208 } else if (strcasecmp(driver_name
, "freetds") == 0 || strcasecmp(driver_name
, "mssql") == 0 || strcasecmp(driver_name
, "sybase") == 0) {
210 } else if (strcasecmp(Config
->driver
, "access") == 0) {
212 } else if (strcasecmp(Config
->driver
, "odbc") == 0) {
218 static GSM_Error
SMSDSQL_Query(GSM_SMSDConfig
* Config
, const char *query
, SQL_result
* res
)
222 struct GSM_SMSDdbobj
*db
= Config
->db
;
224 for (attempts
= 1; attempts
< Config
->backend_retries
; attempts
++) {
225 SMSD_Log(DEBUG_SQL
, Config
, "Execute SQL: %s", query
);
226 error
= db
->Query(Config
, query
, res
);
230 if (error
!= SQL_TIMEOUT
){
231 SMSD_Log(DEBUG_INFO
, Config
, "SQL failure: %d", error
);
232 sleep(attempts
* attempts
);
236 SMSD_Log(DEBUG_INFO
, Config
, "SQL failed (timeout): %s", query
);
237 if (attempts
>= Config
->backend_retries
) {
240 /* We will try to reconnect */
241 SMSD_Log(DEBUG_INFO
, Config
, "reconnecting to database!");
243 while (error
!= SQL_OK
&& attempts
<= Config
->backend_retries
) {
244 SMSD_Log(DEBUG_INFO
, Config
, "Reconnecting after %d seconds...", attempts
* attempts
);
245 sleep(attempts
* attempts
);
247 error
= db
->Connect(Config
);
254 void SMSDSQL_Time2String(GSM_SMSDConfig
* Config
, time_t timestamp
, char *static_buff
, size_t size
)
256 struct tm
*timestruct
;
257 const char *driver_name
;
259 if (Config
->sql
!= NULL
) {
260 driver_name
= Config
->sql
;
262 driver_name
= Config
->driver
;
265 if (timestamp
== -2) {
266 strcpy(static_buff
, "0000-00-00 00:00:00");
267 } else if (strcasecmp(driver_name
, "pgsql") == 0 || strcasecmp(driver_name
, "native_pgsql") == 0) {
268 timestruct
= gmtime(×tamp
);
269 strftime(static_buff
, size
, "%Y-%m-%d %H:%M:%S GMT", timestruct
);
270 } else if (strcasecmp(driver_name
, "access") == 0) {
271 timestruct
= gmtime(×tamp
);
272 strftime(static_buff
, size
, "'%Y-%m-%d %H:%M:%S'", timestruct
);
273 } else if (strcasecmp(Config
->driver
, "odbc") == 0) {
274 timestruct
= gmtime(×tamp
);
275 strftime(static_buff
, size
, "{ ts '%Y-%m-%d %H:%M:%S' }", timestruct
);
277 timestruct
= localtime(×tamp
);
278 strftime(static_buff
, size
, "%Y-%m-%d %H:%M:%S", timestruct
);
282 static GSM_Error
SMSDSQL_NamedQuery(GSM_SMSDConfig
* Config
, const char *sql_query
, GSM_SMSMessage
*sms
,
283 const SQL_Var
*params
, SQL_result
* res
)
285 char buff
[65536], *ptr
, c
, static_buff
[8192];
287 const char *to_print
, *q
= sql_query
;
291 struct GSM_SMSDdbobj
*db
= Config
->db
;
293 if (params
!= NULL
) {
294 while (params
[argc
].type
!= SQL_TYPE_NONE
) argc
++;
305 if( c
>= '0' && c
<= '9'){
306 n
= strtoul(q
, &end
, 10) - 1;
307 if (n
< argc
&& n
>= 0) {
308 switch(params
[n
].type
){
310 ptr
+= sprintf(ptr
, "%i", params
[n
].v
.i
);
312 case SQL_TYPE_STRING
:
313 buffer2
= db
->QuoteString(Config
, params
[n
].v
.s
);
314 memcpy(ptr
, buffer2
, strlen(buffer2
));
315 ptr
+= strlen(buffer2
);
319 SMSD_Log(DEBUG_ERROR
, Config
, "SQL: unknown type: %i (application bug) in query: `%s`", params
[n
].type
, sql_query
);
324 SMSD_Log(DEBUG_ERROR
, Config
, "SQL: wrong number of parameter: %i (max %i) in query: `%s`", n
+1, argc
, sql_query
);
334 to_print
= Config
->Status
->IMEI
;
337 to_print
= Config
->PhoneID
;
340 snprintf(static_buff
, sizeof(static_buff
), "Gammu %s, %s, %s", GAMMU_VERSION
, GetOS(), GetCompiler());
341 to_print
= static_buff
;
344 to_print
= Config
->CreatorID
;
350 EncodeUTF8(static_buff
, sms
->Number
);
351 to_print
= static_buff
;
354 EncodeUTF8(static_buff
, sms
->SMSC
.Number
);
355 to_print
= static_buff
;
358 if (sms
->UDH
.Type
!= UDH_NoUDH
) {
359 EncodeHexBin(static_buff
, sms
->UDH
.Text
, sms
->UDH
.Length
);
360 to_print
= static_buff
;
366 int_to_print
= sms
->Class
;
370 to_print
= GSM_SMSCodingToString(sms
->Coding
);
373 int_to_print
= sms
->MessageReference
;
377 switch (sms
->Coding
) {
378 case SMS_Coding_Unicode_No_Compression
:
379 case SMS_Coding_Default_No_Compression
:
380 EncodeHexUnicode(static_buff
, sms
->Text
, UnicodeLength(sms
->Text
));
382 case SMS_Coding_8bit
:
383 EncodeHexBin(static_buff
, sms
->Text
, sms
->Length
);
389 to_print
= static_buff
;
392 switch (sms
->Coding
) {
393 case SMS_Coding_Unicode_No_Compression
:
394 case SMS_Coding_Default_No_Compression
:
395 EncodeUTF8(static_buff
, sms
->Text
);
396 to_print
= static_buff
;
404 if (sms
->SMSC
.Validity
.Format
== SMS_Validity_RelativeFormat
) {
405 int_to_print
= sms
->SMSC
.Validity
.Relative
;
412 SMSDSQL_Time2String(Config
, Fill_Time_T(sms
->SMSCTime
), static_buff
, sizeof(static_buff
));
413 to_print
= static_buff
;
416 SMSDSQL_Time2String(Config
, Fill_Time_T(sms
->DateTime
), static_buff
, sizeof(static_buff
));
417 to_print
= static_buff
;
420 int_to_print
= sms
->DeliveryStatus
;
424 SMSD_Log(DEBUG_ERROR
, Config
, "SQL: uexpected char '%c' in query: %s", c
, sql_query
);
427 } /* end of switch */
429 SMSD_Log(DEBUG_ERROR
, Config
, "Syntax error in query.. uexpected char '%c' in query: %s", c
, sql_query
);
433 } /* end of switch */
435 ptr
+= sprintf(ptr
, "%i", int_to_print
);
436 } else if (to_print
!= NULL
) {
437 buffer2
= db
->QuoteString(Config
, to_print
);
438 memcpy(ptr
, buffer2
, strlen(buffer2
));
439 ptr
+= strlen(buffer2
);
442 memcpy(ptr
, "NULL", 4);
445 } while (*(++q
) != '\0');
447 return SMSDSQL_Query(Config
, buff
, res
);
451 static GSM_Error
SMSDSQL_CheckTable(GSM_SMSDConfig
* Config
, const char *table
)
456 struct GSM_SMSDdbobj
*db
= Config
->db
;
457 const char *escape_char
;
459 escape_char
= SMSDSQL_EscapeChar(Config
);
461 sprintf(buffer
, "SELECT %s %sID%s FROM %s %s", SMSDSQL_TopClause(Config
, "1"), escape_char
, escape_char
, table
, SMSDSQL_LimitClause(Config
, "1"));
462 error
= SMSDSQL_Query(Config
, buffer
, &res
);
463 if (error
!= ERR_NONE
) {
464 SMSD_Log(DEBUG_ERROR
, Config
, "Table %s not found, disconnecting!", table
);
468 db
->FreeResult(Config
, &res
);
472 /* Disconnects from a database */
473 static GSM_Error
SMSDSQL_Free(GSM_SMSDConfig
* Config
)
476 SMSD_Log(DEBUG_SQL
, Config
, "Disconnecting from SQL database.");
477 Config
->db
->Free(Config
);
478 /* free configuration */
479 for(i
= 0; i
< SQL_QUERY_LAST_NO
; i
++){
480 free(SMSDSQL_queries
[i
]);
481 SMSDSQL_queries
[i
] = NULL
;
486 /* Connects to database */
487 static GSM_Error
SMSDSQL_Init(GSM_SMSDConfig
* Config
)
492 struct GSM_SMSDdbobj
*db
;
493 const char *escape_char
;
504 if (db
->Connect(Config
) != SQL_OK
)
507 error
= SMSDSQL_CheckTable(Config
, "outbox");
508 if (error
!= ERR_NONE
)
510 error
= SMSDSQL_CheckTable(Config
, "outbox_multipart");
511 if (error
!= ERR_NONE
)
513 error
= SMSDSQL_CheckTable(Config
, "sentitems");
514 if (error
!= ERR_NONE
)
516 error
= SMSDSQL_CheckTable(Config
, "inbox");
517 if (error
!= ERR_NONE
)
520 escape_char
= SMSDSQL_EscapeChar(Config
);
522 sprintf(buffer
, "SELECT %sVersion%s FROM gammu", escape_char
, escape_char
);
523 if (SMSDSQL_Query(Config
, buffer
, &res
) != ERR_NONE
) {
527 if (db
->NextRow(Config
, &res
) != 1) {
528 SMSD_Log(DEBUG_ERROR
, Config
, "Failed to seek to first row!");
529 db
->FreeResult(Config
, &res
);
533 version
= db
->GetNumber(Config
, &res
, 0);
534 db
->FreeResult(Config
, &res
);
535 if (SMSD_CheckDBVersion(Config
, version
) != ERR_NONE
) {
540 SMSD_Log(DEBUG_INFO
, Config
, "Connected to Database %s: %s on %s", Config
->driver
, Config
->database
, Config
->host
);
545 static GSM_Error
SMSDSQL_InitAfterConnect(GSM_SMSDConfig
* Config
)
548 struct GSM_SMSDdbobj
*db
= Config
->db
;
549 SQL_Var vars
[3] = {{SQL_TYPE_STRING
, {NULL
}}, {SQL_TYPE_STRING
, {NULL
}}, {SQL_TYPE_NONE
, {NULL
}}};
551 if (SMSDSQL_NamedQuery(Config
, SMSDSQL_queries
[SQL_QUERY_DELETE_PHONE
], NULL
, NULL
, &res
) != ERR_NONE
) {
552 SMSD_Log(DEBUG_INFO
, Config
, "Error deleting from database (%s)", __FUNCTION__
);
555 db
->FreeResult(Config
, &res
);
557 SMSD_Log(DEBUG_INFO
, Config
, "Inserting phone info");
558 vars
[0].v
.s
= Config
->enable_send
? "yes" : "no";
559 vars
[1].v
.s
= Config
->enable_receive
? "yes" : "no";
561 if (SMSDSQL_NamedQuery(Config
, SMSDSQL_queries
[SQL_QUERY_INSERT_PHONE
], NULL
, vars
, &res
) != ERR_NONE
) {
562 SMSD_Log(DEBUG_INFO
, Config
, "Error inserting into database (%s)", __FUNCTION__
);
565 db
->FreeResult(Config
, &res
);
570 /* Save SMS from phone (called Inbox sms - it's in phone Inbox) somewhere */
571 static GSM_Error
SMSDSQL_SaveInboxSMS(GSM_MultiSMSMessage
* sms
, GSM_SMSDConfig
* Config
, char **Locations
)
573 SQL_result res
, res2
;
575 struct GSM_SMSDdbobj
*db
= Config
->db
;
576 const char *q
, *status
;
578 char smstext
[3 * GSM_MAX_SMS_LENGTH
+ 1];
579 char destinationnumber
[3 * GSM_MAX_NUMBER_LENGTH
+ 1];
580 char smsc_message
[3 * GSM_MAX_NUMBER_LENGTH
+ 1];
582 time_t t_time1
, t_time2
;
585 unsigned long long new_id
;
586 size_t locations_size
= 0, locations_pos
= 0;
587 const char *state
, *smsc
;
591 for (i
= 0; i
< sms
->Number
; i
++) {
592 EncodeUTF8(destinationnumber
, sms
->SMS
[i
].Number
);
593 EncodeUTF8(smsc_message
, sms
->SMS
[i
].SMSC
.Number
);
594 if (sms
->SMS
[i
].PDU
== SMS_Status_Report
) {
595 EncodeUTF8(smstext
, sms
->SMS
[i
].Text
);
596 SMSD_Log(DEBUG_INFO
, Config
, "Delivery report: %s to %s", smstext
, destinationnumber
);
598 if (SMSDSQL_NamedQuery(Config
, SMSDSQL_queries
[SQL_QUERY_SAVE_INBOX_SMS_SELECT
], &sms
->SMS
[i
], NULL
, &res
) != ERR_NONE
) {
599 SMSD_Log(DEBUG_INFO
, Config
, "Error reading from database (%s)", __FUNCTION__
);
604 while (db
->NextRow(Config
, &res
)) {
605 smsc
= db
->GetString(Config
, &res
, 4);
606 state
= db
->GetString(Config
, &res
, 1);
607 SMSD_Log(DEBUG_NOTICE
, Config
, "Checking for delivery report, SMSC=%s, state=%s", smsc
, state
);
609 if (strcmp(smsc
, smsc_message
) != 0) {
610 if (Config
->skipsmscnumber
[0] == 0 || strcmp(Config
->skipsmscnumber
, smsc
)) {
615 if (strcmp(state
, "SendingOK") == 0 || strcmp(state
, "DeliveryPending") == 0) {
616 t_time1
= db
->GetDate(Config
, &res
, 2);
618 SMSD_Log(DEBUG_ERROR
, Config
, "Invalid SendingDateTime -1 for SMS TPMR=%i", sms
->SMS
[i
].MessageReference
);
621 t_time2
= Fill_Time_T(sms
->SMS
[i
].DateTime
);
622 diff
= t_time2
- t_time1
;
624 if (diff
> -Config
->deliveryreportdelay
&& diff
< Config
->deliveryreportdelay
) {
628 SMSD_Log(DEBUG_NOTICE
, Config
,
629 "Delivery report would match, but time delta is too big (%ld), consider increasing DeliveryReportDelay", diff
);
635 if (!strcmp(smstext
, "Delivered")) {
636 q
= SMSDSQL_queries
[SQL_QUERY_SAVE_INBOX_SMS_UPDATE_DELIVERED
];
638 q
= SMSDSQL_queries
[SQL_QUERY_SAVE_INBOX_SMS_UPDATE
];
641 if (!strcmp(smstext
, "Delivered")) {
642 status
= "DeliveryOK";
643 } else if (!strcmp(smstext
, "Failed")) {
644 status
= "DeliveryFailed";
645 } else if (!strcmp(smstext
, "Pending")) {
646 status
= "DeliveryPending";
647 } else if (!strcmp(smstext
, "Unknown")) {
648 status
= "DeliveryUnknown";
653 vars
[0].type
= SQL_TYPE_STRING
;
654 vars
[0].v
.s
= status
; /* Status */
655 vars
[1].type
= SQL_TYPE_INT
;
656 vars
[1].v
.i
= (long)db
->GetNumber(Config
, &res
, 0); /* ID */
657 vars
[2].type
= SQL_TYPE_NONE
;
659 if (SMSDSQL_NamedQuery(Config
, q
, &sms
->SMS
[i
], vars
, &res2
) != ERR_NONE
) {
660 SMSD_Log(DEBUG_INFO
, Config
, "Error writing to database (%s)", __FUNCTION__
);
663 db
->FreeResult(Config
, &res2
);
665 db
->FreeResult(Config
, &res
);
669 if (sms
->SMS
[i
].PDU
!= SMS_Deliver
)
672 if (SMSDSQL_NamedQuery(Config
, SMSDSQL_queries
[SQL_QUERY_SAVE_INBOX_SMS_INSERT
], &sms
->SMS
[i
], NULL
, &res
) != ERR_NONE
) {
673 SMSD_Log(DEBUG_INFO
, Config
, "Error writing to database (%s)", __FUNCTION__
);
677 new_id
= db
->SeqID(Config
, "inbox_ID_seq");
679 SMSD_Log(DEBUG_INFO
, Config
, "Failed to get inserted row ID (%s)", __FUNCTION__
);
682 SMSD_Log(DEBUG_NOTICE
, Config
, "Inserted message id %lu", (long)new_id
);
684 db
->FreeResult(Config
, &res
);
687 if (locations_pos
+ 10 >= locations_size
) {
688 locations_size
+= 40;
689 *Locations
= (char *)realloc(*Locations
, locations_size
);
690 assert(*Locations
!= NULL
);
691 if (locations_pos
== 0) {
695 locations_pos
+= sprintf((*Locations
) + locations_pos
, "%lu ", (long)new_id
);
698 if (SMSDSQL_NamedQuery(Config
, SMSDSQL_queries
[SQL_QUERY_UPDATE_RECEIVED
], &sms
->SMS
[i
], NULL
, &res2
) != ERR_NONE
) {
699 SMSD_Log(DEBUG_INFO
, Config
, "Error updating number of received messages (%s)", __FUNCTION__
);
702 db
->FreeResult(Config
, &res2
);
709 static GSM_Error
SMSDSQL_RefreshSendStatus(GSM_SMSDConfig
* Config
, char *ID
)
712 struct GSM_SMSDdbobj
*db
= Config
->db
;
714 {SQL_TYPE_STRING
, {ID
}},
715 {SQL_TYPE_NONE
, {NULL
}}};
717 if (SMSDSQL_NamedQuery(Config
, SMSDSQL_queries
[SQL_QUERY_REFRESH_SEND_STATUS
], NULL
, vars
, &res
) != ERR_NONE
) {
718 SMSD_Log(DEBUG_INFO
, Config
, "Error writing to database (%s)", __FUNCTION__
);
722 if (db
->AffectedRows(Config
, &res
) == 0) {
723 db
->FreeResult(Config
, &res
);
727 db
->FreeResult(Config
, &res
);
731 /* Find one multi SMS to sending and return it (or return ERR_EMPTY)
732 * There is also set ID for SMS
734 static GSM_Error
SMSDSQL_FindOutboxSMS(GSM_MultiSMSMessage
* sms
, GSM_SMSDConfig
* Config
, char *ID
)
737 struct GSM_SMSDdbobj
*db
= Config
->db
;
739 gboolean found
= FALSE
;
743 const char *sender_id
;
745 const char *text_decoded
;
746 const char *destination
;
750 unsigned int limit
= 1;
753 /* Min. limit is 8 SMS, limit grows with higher loopsleep setting Max. limit is 30 messages.*/
754 limit
= Config
->loopsleep
>1 ? Config
->loopsleep
* 4 : 8;
755 limit
= limit
>30 ? 30 : limit
;
757 vars
[0].type
= SQL_TYPE_INT
;
759 vars
[1].type
= SQL_TYPE_NONE
;
761 if (SMSDSQL_NamedQuery(Config
, SMSDSQL_queries
[SQL_QUERY_FIND_OUTBOX_SMS_ID
], NULL
, vars
, &res
) != ERR_NONE
) {
762 SMSD_Log(DEBUG_INFO
, Config
, "Error reading from database (%s)", __FUNCTION__
);
766 while (db
->NextRow(Config
, &res
)) {
767 sprintf(ID
, "%ld", (long)db
->GetNumber(Config
, &res
, 0));
768 timestamp
= db
->GetDate(Config
, &res
, 1);
769 if (timestamp
== -1) {
770 SMSD_Log(DEBUG_INFO
, Config
, "Invalid date for InsertIntoDB.");
773 SMSDSQL_Time2String(Config
, timestamp
, Config
->DT
, sizeof(Config
->DT
));
774 sender_id
= db
->GetString(Config
, &res
, 3);
775 if (sender_id
== NULL
|| strlen(sender_id
) == 0 || !strcmp(sender_id
, Config
->PhoneID
)) {
776 if (SMSDSQL_RefreshSendStatus(Config
, ID
) == ERR_NONE
) {
783 db
->FreeResult(Config
, &res
);
790 for (i
= 0; i
< GSM_MAX_MULTI_SMS
; i
++) {
791 GSM_SetDefaultSMSData(&sms
->SMS
[i
]);
792 sms
->SMS
[i
].SMSC
.Number
[0] = 0;
793 sms
->SMS
[i
].SMSC
.Number
[1] = 0;
796 for (i
= 1; i
< GSM_MAX_MULTI_SMS
+ 1; i
++) {
797 vars
[0].type
= SQL_TYPE_STRING
;
799 vars
[1].type
= SQL_TYPE_INT
;
801 vars
[2].type
= SQL_TYPE_NONE
;
803 q
= SMSDSQL_queries
[SQL_QUERY_FIND_OUTBOX_BODY
];
805 q
= SMSDSQL_queries
[SQL_QUERY_FIND_OUTBOX_MULTIPART
];
807 if (SMSDSQL_NamedQuery(Config
, q
, NULL
, vars
, &res
) != ERR_NONE
) {
808 SMSD_Log(DEBUG_ERROR
, Config
, "Error reading from database (%s)", __FUNCTION__
);
812 if (db
->NextRow(Config
, &res
) != 1) {
813 db
->FreeResult(Config
, &res
);
817 coding
= db
->GetString(Config
, &res
, 1);
818 text
= db
->GetString(Config
, &res
, 0);
822 text_len
= strlen(text
);
824 text_decoded
= db
->GetString(Config
, &res
, 4);
825 udh
= db
->GetString(Config
, &res
, 2);
829 udh_len
= strlen(udh
);
832 sms
->SMS
[sms
->Number
].Coding
= GSM_StringToSMSCoding(coding
);
833 if (sms
->SMS
[sms
->Number
].Coding
== 0) {
834 if (text
== NULL
|| text_len
== 0) {
835 SMSD_Log(DEBUG_NOTICE
, Config
, "Assuming default coding for text message");
836 sms
->SMS
[sms
->Number
].Coding
= SMS_Coding_Default_No_Compression
;
838 SMSD_Log(DEBUG_NOTICE
, Config
, "Assuming 8bit coding for binary message");
839 sms
->SMS
[sms
->Number
].Coding
= SMS_Coding_8bit
;
843 if (text
== NULL
|| text_len
== 0) {
844 if (text_decoded
== NULL
) {
845 SMSD_Log(DEBUG_ERROR
, Config
, "Message without text!");
848 SMSD_Log(DEBUG_NOTICE
, Config
, "Message: %s", text_decoded
);
849 DecodeUTF8(sms
->SMS
[sms
->Number
].Text
, text_decoded
, strlen(text_decoded
));
852 switch (sms
->SMS
[sms
->Number
].Coding
) {
853 case SMS_Coding_Unicode_No_Compression
:
855 case SMS_Coding_Default_No_Compression
:
856 DecodeHexUnicode(sms
->SMS
[sms
->Number
].Text
, text
, text_len
);
859 case SMS_Coding_8bit
:
860 DecodeHexBin(sms
->SMS
[sms
->Number
].Text
, text
, text_len
);
861 sms
->SMS
[sms
->Number
].Length
= text_len
/ 2;
870 destination
= db
->GetString(Config
, &res
, 6);
871 if (destination
== NULL
) {
872 SMSD_Log(DEBUG_ERROR
, Config
, "Message without recipient!");
875 DecodeUTF8(sms
->SMS
[sms
->Number
].Number
, destination
, strlen(destination
));
877 CopyUnicodeString(sms
->SMS
[sms
->Number
].Number
, sms
->SMS
[0].Number
);
880 sms
->SMS
[sms
->Number
].UDH
.Type
= UDH_NoUDH
;
881 if (udh
!= NULL
&& udh_len
!= 0) {
882 sms
->SMS
[sms
->Number
].UDH
.Type
= UDH_UserUDH
;
883 sms
->SMS
[sms
->Number
].UDH
.Length
= udh_len
/ 2;
884 DecodeHexBin(sms
->SMS
[sms
->Number
].UDH
.Text
, udh
, udh_len
);
887 sms
->SMS
[sms
->Number
].Class
= db
->GetNumber(Config
, &res
, 3);
888 sms
->SMS
[sms
->Number
].PDU
= SMS_Submit
;
892 strcpy(Config
->CreatorID
, db
->GetString(Config
, &res
, 10));
893 Config
->relativevalidity
= db
->GetNumber(Config
, &res
, 8);
895 Config
->currdeliveryreport
= db
->GetBool(Config
, &res
, 9);
897 /* Is this a multipart message? */
898 if (!db
->GetBool(Config
, &res
, 7)) {
899 db
->FreeResult(Config
, &res
);
904 db
->FreeResult(Config
, &res
);
910 /* After sending SMS is moved to Sent Items or Error Items. */
911 static GSM_Error
SMSDSQL_MoveSMS(GSM_MultiSMSMessage
* sms UNUSED
, GSM_SMSDConfig
* Config
, char *ID
, gboolean alwaysDelete UNUSED
, gboolean sent UNUSED
)
915 struct GSM_SMSDdbobj
*db
= Config
->db
;
917 vars
[0].type
= SQL_TYPE_STRING
;
919 vars
[1].type
= SQL_TYPE_NONE
;
921 if (SMSDSQL_NamedQuery(Config
, SMSDSQL_queries
[SQL_QUERY_DELETE_OUTBOX
], NULL
, vars
, &res
) != ERR_NONE
) {
922 SMSD_Log(DEBUG_INFO
, Config
, "Error deleting from database (%s)", __FUNCTION__
);
925 db
->FreeResult(Config
, &res
);
927 if (SMSDSQL_NamedQuery(Config
, SMSDSQL_queries
[SQL_QUERY_DELETE_OUTBOX_MULTIPART
], NULL
, vars
, &res
) != ERR_NONE
) {
928 SMSD_Log(DEBUG_INFO
, Config
, "Error deleting from database (%s)", __FUNCTION__
);
931 db
->FreeResult(Config
, &res
);
936 /* Adds SMS to Outbox */
937 static GSM_Error
SMSDSQL_CreateOutboxSMS(GSM_MultiSMSMessage
* sms
, GSM_SMSDConfig
* Config
, char *NewID
)
944 struct GSM_SMSDdbobj
*db
= Config
->db
;
945 const char *report
, *multipart
, *q
;
947 sprintf(creator
, "Gammu %s",GAMMU_VERSION
); /* %1 */
948 multipart
= (sms
->Number
== 1) ? "FALSE" : "TRUE"; /* %3 */
950 for (i
= 0; i
< sms
->Number
; i
++) {
951 report
= (sms
->SMS
[i
].PDU
== SMS_Status_Report
) ? "yes": "default"; /* %2 */
953 q
= SMSDSQL_queries
[SQL_QUERY_CREATE_OUTBOX
];
955 q
= SMSDSQL_queries
[SQL_QUERY_CREATE_OUTBOX_MULTIPART
];
958 vars
[0].type
= SQL_TYPE_STRING
;
959 vars
[0].v
.s
= creator
;
960 vars
[1].type
= SQL_TYPE_STRING
;
961 vars
[1].v
.s
= report
;
962 vars
[2].type
= SQL_TYPE_STRING
;
963 vars
[2].v
.s
= multipart
;
964 vars
[3].type
= SQL_TYPE_INT
;
966 vars
[4].type
= SQL_TYPE_INT
;
968 vars
[5].type
= SQL_TYPE_NONE
;
970 if (SMSDSQL_NamedQuery(Config
, q
, &sms
->SMS
[i
], vars
, &res
) != ERR_NONE
) {
971 SMSD_Log(DEBUG_INFO
, Config
, "Error writing to database (%s)", __FUNCTION__
);
975 ID
= db
->SeqID(Config
, "outbox_ID_seq");
977 SMSD_Log(DEBUG_INFO
, Config
, "Failed to get inserted row ID (%s)", __FUNCTION__
);
981 db
->FreeResult(Config
, &res
);
983 SMSD_Log(DEBUG_INFO
, Config
, "Written message with ID %u", ID
);
985 sprintf(NewID
, "%d", ID
);
989 static GSM_Error
SMSDSQL_AddSentSMSInfo(GSM_MultiSMSMessage
* sms
, GSM_SMSDConfig
* Config
, char *ID
, int Part
, GSM_SMSDSendingError err
, int TPMR
)
992 struct GSM_SMSDdbobj
*db
= Config
->db
;
994 const char *message_state
;
996 char smsc
[GSM_MAX_NUMBER_LENGTH
+ 1];
997 char destination
[GSM_MAX_NUMBER_LENGTH
+ 1];
999 EncodeUTF8(smsc
, sms
->SMS
[Part
- 1].SMSC
.Number
);
1000 EncodeUTF8(destination
, sms
->SMS
[Part
- 1].Number
);
1002 if (err
== SMSD_SEND_OK
) {
1003 SMSD_Log(DEBUG_NOTICE
, Config
, "Transmitted %s (%s: %i) to %s", Config
->SMSID
,
1004 (Part
== sms
->Number
? "total" : "part"), Part
, DecodeUnicodeString(sms
->SMS
[0].Number
));
1007 if (err
== SMSD_SEND_OK
) {
1008 if (sms
->SMS
[Part
- 1].PDU
== SMS_Status_Report
) {
1009 message_state
= "SendingOK";
1011 message_state
= "SendingOKNoReport";
1013 } else if (err
== SMSD_SEND_SENDING_ERROR
) {
1014 message_state
= "SendingError";
1015 } else if (err
== SMSD_SEND_ERROR
) {
1016 message_state
= "Error";
1018 SMSD_Log(DEBUG_INFO
, Config
, "Unknown SMS state: %d, assuming Error", err
);
1019 message_state
= "Error";
1022 /* 1 = ID, 2 = SequencePosition, 3 = Status, 4 = TPMR, 5 = insertintodb */
1023 vars
[0].type
= SQL_TYPE_STRING
;
1025 vars
[1].type
= SQL_TYPE_INT
;
1027 vars
[2].type
= SQL_TYPE_STRING
;
1028 vars
[2].v
.s
= message_state
;
1029 vars
[3].type
= SQL_TYPE_INT
;
1031 vars
[4].type
= SQL_TYPE_STRING
;
1032 vars
[4].v
.s
= Config
->DT
;
1033 vars
[5].type
= SQL_TYPE_NONE
;
1035 if (SMSDSQL_NamedQuery(Config
, SMSDSQL_queries
[SQL_QUERY_ADD_SENT_INFO
], &sms
->SMS
[Part
- 1], vars
, &res
) != ERR_NONE
) {
1036 SMSD_Log(DEBUG_INFO
, Config
, "Error writing to database (%s)", __FUNCTION__
);
1039 db
->FreeResult(Config
, &res
);
1041 if (SMSDSQL_NamedQuery(Config
, SMSDSQL_queries
[SQL_QUERY_UPDATE_SENT
], &sms
->SMS
[Part
- 1], NULL
, &res
) != ERR_NONE
) {
1042 SMSD_Log(DEBUG_INFO
, Config
, "Error updating number of sent messages (%s)", __FUNCTION__
);
1045 db
->FreeResult(Config
, &res
);
1050 static GSM_Error
SMSDSQL_RefreshPhoneStatus(GSM_SMSDConfig
* Config
)
1054 {SQL_TYPE_INT
, {NULL
}},
1055 {SQL_TYPE_INT
, {NULL
}},
1056 {SQL_TYPE_NONE
, {NULL
}}};
1057 struct GSM_SMSDdbobj
*db
= Config
->db
;
1058 vars
[0].v
.i
= Config
->Status
->Charge
.BatteryPercent
;
1059 vars
[1].v
.i
= Config
->Status
->Network
.SignalPercent
;
1061 if (SMSDSQL_NamedQuery(Config
, SMSDSQL_queries
[SQL_QUERY_REFRESH_PHONE_STATUS
], NULL
, vars
, &res
) != ERR_NONE
) {
1062 SMSD_Log(DEBUG_INFO
, Config
, "Error writing to database (%s)", __FUNCTION__
);
1065 db
->FreeResult(Config
, &res
);
1071 * better strcat... shows where is the bug
1073 #define STRCAT_MAX 80
1074 GSM_Error
SMSDSQL_option(GSM_SMSDConfig
*Config
, int optint
, const char *option
, ...)
1076 size_t len
[STRCAT_MAX
], to_alloc
= 0;
1080 const char *args
[STRCAT_MAX
];
1083 /* read from config */
1084 buffer
= INI_GetValue(Config
->smsdcfgfile
, "sql", option
, FALSE
);
1086 if (buffer
!= NULL
){
1087 SMSDSQL_queries
[optint
] = strdup(buffer
); /* avoid to double free */
1091 /* not found.. we use default query */
1092 va_start(ap
, option
);
1093 for(i
= 0; i
< STRCAT_MAX
; i
++){
1094 arg
= va_arg(ap
, const char *);
1097 len
[i
] = strlen(arg
);
1103 if (i
== STRCAT_MAX
) {
1104 SMSD_Log(DEBUG_ERROR
, Config
, "STRCAT_MAX too small.. consider increase this value for option %s", option
);
1108 buffer
= malloc(to_alloc
+1);
1109 if (buffer
== NULL
){
1110 SMSD_Log(DEBUG_ERROR
, Config
, "Insufficient memory problem for option %s", option
);
1114 for (j
= 0; j
< i
; j
++) {
1115 memcpy(ptr
, args
[j
], len
[j
]);
1119 SMSDSQL_queries
[optint
] = buffer
;
1125 * Reads common options for database backends.
1127 GSM_Error
SMSDSQL_ReadConfiguration(GSM_SMSDConfig
*Config
)
1130 const char *escape_char
;
1132 Config
->user
= INI_GetValue(Config
->smsdcfgfile
, "smsd", "user", FALSE
);
1133 if (Config
->user
== NULL
) {
1134 Config
->user
="root";
1137 Config
->password
= INI_GetValue(Config
->smsdcfgfile
, "smsd", "password", FALSE
);
1138 if (Config
->password
== NULL
) {
1139 Config
->password
="";
1142 Config
->host
= INI_GetValue(Config
->smsdcfgfile
, "smsd", "host", FALSE
);
1143 if (Config
->host
== NULL
) {
1144 /* Backward compatibility */
1145 Config
->host
= INI_GetValue(Config
->smsdcfgfile
, "smsd", "pc", FALSE
);
1147 if (Config
->host
== NULL
) {
1148 Config
->host
="localhost";
1151 Config
->database
= INI_GetValue(Config
->smsdcfgfile
, "smsd", "database", FALSE
);
1152 if (Config
->database
== NULL
) {
1153 Config
->database
="sms";
1156 Config
->driverspath
= INI_GetValue(Config
->smsdcfgfile
, "smsd", "driverspath", FALSE
);
1158 Config
->sql
= INI_GetValue(Config
->smsdcfgfile
, "smsd", "sql", FALSE
);
1160 Config
->dbdir
= INI_GetValue(Config
->smsdcfgfile
, "smsd", "dbdir", FALSE
);
1162 if (Config
->driver
== NULL
) {
1163 SMSD_Log(DEBUG_ERROR
, Config
, "No database driver selected. Must be native_mysql, native_pgsql, ODBC or DBI one.");
1168 #ifdef HAVE_MYSQL_MYSQL_H
1169 if (!strcasecmp(Config
->driver
, "native_mysql"))
1170 Config
->db
= &SMSDMySQL
;
1172 #ifdef HAVE_POSTGRESQL_LIBPQ_FE_H
1173 if (!strcasecmp(Config
->driver
, "native_pgsql"))
1174 Config
->db
= &SMSDPgSQL
;
1177 if (!strcasecmp(Config
->driver
, "odbc"))
1178 Config
->db
= &SMSDODBC
;
1179 if (Config
->sql
== NULL
) {
1180 SMSD_Log(DEBUG_INFO
, Config
, "Using generic SQL for ODBC, this might fail. In such case please set SQL configuration option.");
1183 if (Config
->db
== NULL
) {
1185 Config
->db
= &SMSDDBI
;
1187 SMSD_Log(DEBUG_ERROR
, Config
, "Unknown DB driver");
1192 escape_char
= SMSDSQL_EscapeChar(Config
);
1193 #define ESCAPE_FIELD(x) escape_char, x, escape_char
1195 locktime
= Config
->loopsleep
* 8; /* reserve 8 sec per message */
1196 locktime
= locktime
< 60 ? 60 : locktime
; /* Minimum time reserve is 60 sec */
1198 if (SMSDSQL_option(Config
, SQL_QUERY_DELETE_PHONE
, "delete_phone",
1199 "DELETE FROM phones WHERE ", ESCAPE_FIELD("IMEI"), " = %I", NULL
) != ERR_NONE
) {
1203 if (SMSDSQL_option(Config
, SQL_QUERY_INSERT_PHONE
, "insert_phone",
1204 "INSERT INTO phones (",
1205 ESCAPE_FIELD("IMEI"),
1206 ", ", ESCAPE_FIELD("ID"),
1207 ", ", ESCAPE_FIELD("Send"),
1208 ", ", ESCAPE_FIELD("Receive"),
1209 ", ", ESCAPE_FIELD("InsertIntoDB"),
1210 ", ", ESCAPE_FIELD("TimeOut"),
1211 ", ", ESCAPE_FIELD("Client"),
1212 ", ", ESCAPE_FIELD("Battery"),
1213 ", ", ESCAPE_FIELD("Signal"),
1214 ") VALUES (%I, %P, %1, %2, ",
1215 SMSDSQL_Now(Config
),
1217 SMSDSQL_NowPlus(Config
, 10),
1218 ", %N, -1, -1)", NULL
) != ERR_NONE
) {
1222 if (SMSDSQL_option(Config
, SQL_QUERY_SAVE_INBOX_SMS_SELECT
, "save_inbox_sms_select",
1225 ", ", ESCAPE_FIELD("Status"),
1226 ", ", ESCAPE_FIELD("SendingDateTime"),
1227 ", ", ESCAPE_FIELD("DeliveryDateTime"),
1228 ", ", ESCAPE_FIELD("SMSCNumber"), " "
1229 "FROM sentitems WHERE ",
1230 ESCAPE_FIELD("DeliveryDateTime"), " IS NULL AND ",
1231 ESCAPE_FIELD("SenderID"), " = %P AND ",
1232 ESCAPE_FIELD("TPMR"), " = %t AND ",
1233 ESCAPE_FIELD("DestinationNumber"), " = %R", NULL
) != ERR_NONE
) {
1237 if (SMSDSQL_option(Config
, SQL_QUERY_SAVE_INBOX_SMS_UPDATE_DELIVERED
, "save_inbox_sms_update_delivered",
1239 "SET ", ESCAPE_FIELD("DeliveryDateTime"), " = %C"
1240 ", ", ESCAPE_FIELD("Status"), " = %1"
1241 ", ", ESCAPE_FIELD("StatusError"), " = %e"
1242 " WHERE ", ESCAPE_FIELD("ID"), " = %2"
1243 " AND ", ESCAPE_FIELD("TPMR"), " = %t", NULL
) != ERR_NONE
) {
1247 if (SMSDSQL_option(Config
, SQL_QUERY_SAVE_INBOX_SMS_UPDATE
, "save_inbox_sms_update",
1249 "SET ", ESCAPE_FIELD("Status"), " = %1"
1250 ", ", ESCAPE_FIELD("StatusError"), " = %e"
1251 " WHERE ", ESCAPE_FIELD("ID"), " = %2"
1252 " AND ", ESCAPE_FIELD("TPMR"), " = %t", NULL
) != ERR_NONE
) {
1256 if (SMSDSQL_option(Config
, SQL_QUERY_SAVE_INBOX_SMS_INSERT
, "save_inbox_sms_insert",
1257 "INSERT INTO inbox "
1258 "(", ESCAPE_FIELD("ReceivingDateTime"),
1259 ", ", ESCAPE_FIELD("Text"),
1260 ", ", ESCAPE_FIELD("SenderNumber"),
1261 ", ", ESCAPE_FIELD("Coding"),
1262 ", ", ESCAPE_FIELD("SMSCNumber"),
1263 ", ", ESCAPE_FIELD("UDH"),
1264 ", ", ESCAPE_FIELD("Class"),
1265 ", ", ESCAPE_FIELD("TextDecoded"),
1266 ", ", ESCAPE_FIELD("RecipientID"), ")"
1267 " VALUES (%d, %E, %R, %c, %F, %u, %x, %T, %P)", NULL
) != ERR_NONE
) {
1271 if (SMSDSQL_option(Config
, SQL_QUERY_UPDATE_RECEIVED
, "update_received",
1272 "UPDATE phones SET ",
1273 ESCAPE_FIELD("Received"), " = ", ESCAPE_FIELD("Received"), " + 1"
1274 " WHERE ", ESCAPE_FIELD("IMEI"), " = %I", NULL
) != ERR_NONE
) {
1278 if (SMSDSQL_option(Config
, SQL_QUERY_REFRESH_SEND_STATUS
, "refresh_send_status",
1279 "UPDATE outbox SET ",
1280 ESCAPE_FIELD("SendingTimeOut"), " = ", SMSDSQL_NowPlus(Config
, locktime
),
1281 " WHERE ", ESCAPE_FIELD("ID"), " = %1"
1282 " AND (", ESCAPE_FIELD("SendingTimeOut"), " < ", SMSDSQL_Now(Config
),
1283 " OR ", ESCAPE_FIELD("SendingTimeOut"), " IS NULL)", NULL
) != ERR_NONE
) {
1287 if (SMSDSQL_option(Config
, SQL_QUERY_FIND_OUTBOX_SMS_ID
, "find_outbox_sms_id",
1288 "SELECT ", SMSDSQL_TopClause(Config
, "%1"),
1290 ", ", ESCAPE_FIELD("InsertIntoDB"),
1291 ", ", ESCAPE_FIELD("SendingDateTime"),
1292 ", ", ESCAPE_FIELD("SenderID"),
1293 " FROM outbox WHERE ",
1294 ESCAPE_FIELD("SendingDateTime"), " < ", SMSDSQL_Now(Config
),
1295 " AND ", ESCAPE_FIELD("SendingTimeOut"), " < ", SMSDSQL_Now(Config
),
1296 " AND ", ESCAPE_FIELD("SendBefore"), " >= ", SMSDSQL_CurrentTime(Config
),
1297 " AND ", ESCAPE_FIELD("SendAfter"), " <= ", SMSDSQL_CurrentTime(Config
),
1298 " AND ( ", ESCAPE_FIELD("SenderID"), " is NULL OR ", ESCAPE_FIELD("SenderID"), " = '' OR ", ESCAPE_FIELD("SenderID"), " = %P )"
1299 " ORDER BY ", ESCAPE_FIELD("InsertIntoDB"), " ASC ", SMSDSQL_LimitClause(Config
, "%1"), NULL
) != ERR_NONE
) {
1303 if (SMSDSQL_option(Config
, SQL_QUERY_FIND_OUTBOX_BODY
, "find_outbox_body",
1305 ESCAPE_FIELD("Text"),
1306 ", ", ESCAPE_FIELD("Coding"),
1307 ", ", ESCAPE_FIELD("UDH"),
1308 ", ", ESCAPE_FIELD("Class"),
1309 ", ", ESCAPE_FIELD("TextDecoded"),
1310 ", ", ESCAPE_FIELD("ID"),
1311 ", ", ESCAPE_FIELD("DestinationNumber"),
1312 ", ", ESCAPE_FIELD("MultiPart"),
1313 ", ", ESCAPE_FIELD("RelativeValidity"),
1314 ", ", ESCAPE_FIELD("DeliveryReport"),
1315 ", ", ESCAPE_FIELD("CreatorID"),
1316 " FROM outbox WHERE ",
1317 ESCAPE_FIELD("ID"), "=%1", NULL
) != ERR_NONE
) {
1321 if (SMSDSQL_option(Config
, SQL_QUERY_FIND_OUTBOX_MULTIPART
, "find_outbox_multipart",
1323 ESCAPE_FIELD("Text"),
1324 ", ", ESCAPE_FIELD("Coding"),
1325 ", ", ESCAPE_FIELD("UDH"),
1326 ", ", ESCAPE_FIELD("Class"),
1327 ", ", ESCAPE_FIELD("TextDecoded"),
1328 ", ", ESCAPE_FIELD("ID"),
1329 ", ", ESCAPE_FIELD("SequencePosition"),
1330 " FROM outbox_multipart WHERE ",
1331 ESCAPE_FIELD("ID"), "=%1 AND ",
1332 ESCAPE_FIELD("SequencePosition"), "=%2", NULL
) != ERR_NONE
) {
1336 if (SMSDSQL_option(Config
, SQL_QUERY_DELETE_OUTBOX
, "delete_outbox",
1337 "DELETE FROM outbox WHERE ", ESCAPE_FIELD("ID"), "=%1", NULL
) != ERR_NONE
) {
1341 if (SMSDSQL_option(Config
, SQL_QUERY_DELETE_OUTBOX_MULTIPART
, "delete_outbox_multipart",
1342 "DELETE FROM outbox_multipart WHERE ", ESCAPE_FIELD("ID"), "=%1", NULL
) != ERR_NONE
) {
1346 if (SMSDSQL_option(Config
, SQL_QUERY_CREATE_OUTBOX
, "create_outbox",
1347 "INSERT INTO outbox "
1348 "(", ESCAPE_FIELD("CreatorID"),
1349 ", ", ESCAPE_FIELD("SenderID"),
1350 ", ", ESCAPE_FIELD("DeliveryReport"),
1351 ", ", ESCAPE_FIELD("MultiPart"),
1352 ", ", ESCAPE_FIELD("InsertIntoDB"),
1353 ", ", ESCAPE_FIELD("Text"),
1354 ", ", ESCAPE_FIELD("DestinationNumber"),
1355 ", ", ESCAPE_FIELD("RelativeValidity"),
1356 ", ", ESCAPE_FIELD("Coding"),
1357 ", ", ESCAPE_FIELD("UDH"),
1358 ", ", ESCAPE_FIELD("Class"),
1359 ", ", ESCAPE_FIELD("TextDecoded"), ") VALUES "
1360 "(%1, %P, %2, %3, ", SMSDSQL_Now(Config
),
1361 ", %E, %R, %V, %c, %u, %x, %T)", NULL
) != ERR_NONE
) {
1365 if (SMSDSQL_option(Config
, SQL_QUERY_CREATE_OUTBOX_MULTIPART
, "create_outbox_multipart",
1366 "INSERT INTO outbox_multipart "
1367 "(", ESCAPE_FIELD("SequencePosition"),
1368 ", ", ESCAPE_FIELD("Text"),
1369 ", ", ESCAPE_FIELD("Coding"),
1370 ", ", ESCAPE_FIELD("UDH"),
1371 ", ", ESCAPE_FIELD("Class"),
1372 ", ", ESCAPE_FIELD("TextDecoded"),
1373 ", ", ESCAPE_FIELD("ID"), ") VALUES (%4, %E, %c, %u, %x, %T, %5)", NULL
) != ERR_NONE
) {
1377 if (SMSDSQL_option(Config
, SQL_QUERY_ADD_SENT_INFO
, "add_sent_info",
1378 "INSERT INTO sentitems "
1379 "(", ESCAPE_FIELD("CreatorID"),
1380 ", ", ESCAPE_FIELD("ID"),
1381 ", ", ESCAPE_FIELD("SequencePosition"),
1382 ", ", ESCAPE_FIELD("Status"),
1383 ", ", ESCAPE_FIELD("SendingDateTime"),
1384 ", ", ESCAPE_FIELD("SMSCNumber"),
1385 ", ", ESCAPE_FIELD("TPMR"),
1386 ", ", ESCAPE_FIELD("SenderID"),
1387 ", ", ESCAPE_FIELD("Text"),
1388 ", ", ESCAPE_FIELD("DestinationNumber"),
1389 ", ", ESCAPE_FIELD("Coding"),
1390 ", ", ESCAPE_FIELD("UDH"),
1391 ", ", ESCAPE_FIELD("Class"),
1392 ", ", ESCAPE_FIELD("TextDecoded"),
1393 ", ", ESCAPE_FIELD("InsertIntoDB"),
1394 ", ", ESCAPE_FIELD("RelativeValidity"),
1396 " VALUES (%A, %1, %2, %3, ",
1397 SMSDSQL_Now(Config
),
1398 ", %F, %4, %P, %E, %R, %c, %u, %x, %T, %5, %V)", NULL
) != ERR_NONE
) {
1402 if (SMSDSQL_option(Config
, SQL_QUERY_UPDATE_SENT
, "update_sent",
1403 "UPDATE phones SET ",
1404 ESCAPE_FIELD("Sent"), "= ", ESCAPE_FIELD("Sent"), " + 1"
1405 " WHERE ", ESCAPE_FIELD("IMEI"), " = %I", NULL
) != ERR_NONE
) {
1409 if (SMSDSQL_option(Config
, SQL_QUERY_REFRESH_PHONE_STATUS
, "refresh_phone_status",
1410 "UPDATE phones SET ",
1411 ESCAPE_FIELD("TimeOut"), "= ", SMSDSQL_NowPlus(Config
, 10),
1412 ", ", ESCAPE_FIELD("Battery"), " = %1"
1413 ", ", ESCAPE_FIELD("Signal"), " = %2"
1414 " WHERE ", ESCAPE_FIELD("IMEI"), " = %I", NULL
) != ERR_NONE
) {
1422 time_t SMSDSQL_ParseDate(GSM_SMSDConfig
* Config
, const char *date
)
1425 struct tm timestruct
;
1428 if (strcmp(date
, "0000-00-00 00:00:00") == 0) {
1432 parse_res
= strptime(date
, "%Y-%m-%d %H:%M:%S", ×truct
);
1434 if (parse_res
!= NULL
&& *parse_res
== 0) {
1435 DT
.Year
= timestruct
.tm_year
+ 1900;
1436 DT
.Month
= timestruct
.tm_mon
+ 1;
1437 DT
.Day
= timestruct
.tm_mday
;
1438 DT
.Hour
= timestruct
.tm_hour
;
1439 DT
.Minute
= timestruct
.tm_min
;
1440 DT
.Second
= timestruct
.tm_sec
;
1442 return Fill_Time_T(DT
);
1444 /* Used during testing */
1445 if (Config
!= NULL
) {
1446 SMSD_Log(DEBUG_ERROR
, Config
, "Failed to parse date: %s", date
);
1451 GSM_SMSDService SMSDSQL
= {
1454 SMSDSQL_InitAfterConnect
,
1455 SMSDSQL_SaveInboxSMS
,
1456 SMSDSQL_FindOutboxSMS
,
1458 SMSDSQL_CreateOutboxSMS
,
1459 SMSDSQL_AddSentSMSInfo
,
1460 SMSDSQL_RefreshSendStatus
,
1461 SMSDSQL_RefreshPhoneStatus
,
1462 SMSDSQL_ReadConfiguration
1465 /* How should editor hadle tabs in this file? Add editor commands here.
1466 * vim: noexpandtab sw=8 ts=8 sts=8: