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"
33 * Returns name of the SQL dialect to use.
35 const char *SMSDSQL_SQLName(GSM_SMSDConfig
* Config
)
37 if (Config
->sql
!= NULL
) {
40 return Config
->driver
;
44 /* FIXME: I know this is broken, need to figure out better way */
45 const char now_plus_odbc
[] = "{fn CURRENT_TIMESTAMP()} + INTERVAL %d SECOND";
46 const char now_plus_mysql
[] = "(NOW() + INTERVAL %d SECOND) + 0";
47 const char now_plus_pgsql
[] = "now() + interval '%d seconds'";
48 const char now_plus_sqlite
[] = "datetime('now', '+%d seconds')";
49 const char now_plus_freetds
[] = "DATEADD('second', %d, CURRENT_TIMESTAMP)";
50 const char now_plus_access
[] = "now()+#00:00:%d#";
51 const char now_plus_fallback
[] = "NOW() + INTERVAL %d SECOND";
54 static const char *SMSDSQL_NowPlus(GSM_SMSDConfig
* Config
, int seconds
)
56 const char *driver_name
;
57 static char result
[100];
59 driver_name
= SMSDSQL_SQLName(Config
);
61 if (strcasecmp(driver_name
, "mysql") == 0 || strcasecmp(driver_name
, "native_mysql") == 0) {
62 sprintf(result
, now_plus_mysql
, seconds
);
63 } else if (strcasecmp(driver_name
, "pgsql") == 0 || strcasecmp(driver_name
, "native_pgsql") == 0) {
64 sprintf(result
, now_plus_pgsql
, seconds
);
65 } else if (strncasecmp(driver_name
, "sqlite", 6) == 0) {
66 sprintf(result
, now_plus_sqlite
, seconds
);
67 } else if (strcasecmp(driver_name
, "freetds") == 0) {
68 sprintf(result
, now_plus_freetds
, seconds
);
69 } else if (strcasecmp(driver_name
, "access") == 0) {
70 sprintf(result
, now_plus_access
, seconds
);
71 } else if (strcasecmp(driver_name
, "odbc") == 0) {
72 sprintf(result
, now_plus_odbc
, seconds
);
74 sprintf(result
, now_plus_fallback
, seconds
);
79 const char escape_char_odbc
[] = "";
80 const char escape_char_mysql
[] = "`";
81 const char escape_char_pgsql
[] = "\"";
82 const char escape_char_sqlite
[] = "";
83 const char escape_char_freetds
[] = "";
84 const char escape_char_fallback
[] = "";
86 static const char *SMSDSQL_EscapeChar(GSM_SMSDConfig
* Config
)
88 const char *driver_name
;
90 driver_name
= SMSDSQL_SQLName(Config
);
92 if (strcasecmp(driver_name
, "mysql") == 0 || strcasecmp(driver_name
, "native_mysql") == 0) {
93 return escape_char_mysql
;
94 } else if (strcasecmp(driver_name
, "pgsql") == 0 || strcasecmp(driver_name
, "native_pgsql") == 0) {
95 return escape_char_pgsql
;
96 } else if (strncasecmp(driver_name
, "sqlite", 6) == 0) {
97 return escape_char_sqlite
;
98 } else if (strcasecmp(driver_name
, "freetds") == 0 || strcasecmp(driver_name
, "mssql") == 0 || strcasecmp(driver_name
, "sybase") == 0) {
99 return escape_char_freetds
;
100 } else if (strcasecmp(Config
->driver
, "odbc") == 0) {
101 return escape_char_odbc
;
103 return escape_char_fallback
;
107 const char top_clause_access
[] = "TOP";
108 const char top_clause_fallback
[] = "";
110 static const char *SMSDSQL_TopClause(GSM_SMSDConfig
* Config
, const char *count
)
112 const char *driver_name
;
113 static char result
[100];
115 driver_name
= SMSDSQL_SQLName(Config
);
117 if (strcasecmp(driver_name
, "access") == 0) {
118 strcpy(result
, top_clause_access
);
120 strcat(result
, count
);
123 return top_clause_fallback
;
127 const char limit_clause_access
[] = "";
128 const char limit_clause_fallback
[] = "LIMIT";
130 static const char *SMSDSQL_LimitClause(GSM_SMSDConfig
* Config
, const char *count
)
132 const char *driver_name
;
133 static char result
[100];
135 driver_name
= SMSDSQL_SQLName(Config
);
137 if (strcasecmp(driver_name
, "access") == 0) {
138 return limit_clause_access
;
140 strcpy(result
, limit_clause_fallback
);
142 strcat(result
, count
);
147 const char now_odbc
[] = "{fn CURRENT_TIMESTAMP()}";
148 const char now_mysql
[] = "NOW()";
149 const char now_pgsql
[] = "now()";
150 const char now_sqlite
[] = "datetime('now')";
151 const char now_freetds
[] = "CURRENT_TIMESTAMP";
152 const char now_access
[] = "now()";
153 const char now_fallback
[] = "NOW()";
155 const char currtime_odbc
[] = "{fn CURTIME()}";
156 const char currtime_mysql
[] = "CURTIME()";
157 const char currtime_pgsql
[] = "localtime";
158 const char currtime_sqlite
[] = "time('now')";
159 const char currtime_freetds
[] = "CURRENT_TIME";
160 const char currtime_fallback
[] = "CURTIME()";
162 static const char *SMSDSQL_CurrentTime(GSM_SMSDConfig
* Config
)
164 const char *driver_name
;
166 driver_name
= SMSDSQL_SQLName(Config
);
168 if (strcasecmp(driver_name
, "mysql") == 0 || strcasecmp(driver_name
, "native_mysql") == 0) {
169 return currtime_mysql
;
170 } else if (strcasecmp(driver_name
, "pgsql") == 0 || strcasecmp(driver_name
, "native_pgsql") == 0) {
171 return currtime_pgsql
;
172 } else if (strncasecmp(driver_name
, "sqlite", 6) == 0) {
173 return currtime_sqlite
;
174 } else if (strcasecmp(driver_name
, "freetds") == 0 || strcasecmp(driver_name
, "mssql") == 0 || strcasecmp(driver_name
, "sybase") == 0) {
175 return currtime_freetds
;
176 } else if (strcasecmp(Config
->driver
, "odbc") == 0) {
177 return currtime_odbc
;
179 return currtime_fallback
;
182 static const char *SMSDSQL_Now(GSM_SMSDConfig
* Config
)
184 const char *driver_name
;
186 driver_name
= SMSDSQL_SQLName(Config
);
188 if (strcasecmp(driver_name
, "mysql") == 0 || strcasecmp(driver_name
, "native_mysql") == 0) {
190 } else if (strcasecmp(driver_name
, "pgsql") == 0 || strcasecmp(driver_name
, "native_pgsql") == 0) {
192 } else if (strncasecmp(driver_name
, "sqlite", 6) == 0) {
194 } else if (strcasecmp(driver_name
, "freetds") == 0 || strcasecmp(driver_name
, "mssql") == 0 || strcasecmp(driver_name
, "sybase") == 0) {
196 } else if (strcasecmp(Config
->driver
, "access") == 0) {
198 } else if (strcasecmp(Config
->driver
, "odbc") == 0) {
204 static SQL_Error
SMSDSQL_Query(GSM_SMSDConfig
* Config
, const char *query
, SQL_result
* res
)
206 SQL_Error error
= SQL_TIMEOUT
;
208 struct GSM_SMSDdbobj
*db
= Config
->db
;
210 for (attempts
= 1; attempts
<= Config
->backend_retries
; attempts
++) {
211 SMSD_Log(DEBUG_SQL
, Config
, "Execute SQL: %s", query
);
212 error
= db
->Query(Config
, query
, res
);
213 if (error
== SQL_OK
) {
217 if (error
!= SQL_TIMEOUT
){
218 SMSD_Log(DEBUG_INFO
, Config
, "SQL failure: %d", error
);
222 SMSD_Log(DEBUG_INFO
, Config
, "SQL failed (timeout): %s", query
);
223 /* We will try to reconnect */
224 SMSD_Log(DEBUG_INFO
, Config
, "reconnecting to database!");
225 while (error
!= SQL_OK
&& attempts
< Config
->backend_retries
) {
226 SMSD_Log(DEBUG_INFO
, Config
, "Reconnecting after %d seconds...", attempts
* attempts
);
227 sleep(attempts
* attempts
);
229 error
= db
->Connect(Config
);
236 void SMSDSQL_Time2String(GSM_SMSDConfig
* Config
, time_t timestamp
, char *static_buff
, size_t size
)
238 struct tm
*timestruct
;
239 const char *driver_name
;
241 driver_name
= SMSDSQL_SQLName(Config
);
243 if (timestamp
== -2) {
244 strcpy(static_buff
, "0000-00-00 00:00:00");
245 } else if (strcasecmp(driver_name
, "pgsql") == 0 || strcasecmp(driver_name
, "native_pgsql") == 0) {
246 timestruct
= gmtime(×tamp
);
247 strftime(static_buff
, size
, "%Y-%m-%d %H:%M:%S GMT", timestruct
);
248 } else if (strcasecmp(driver_name
, "access") == 0) {
249 timestruct
= gmtime(×tamp
);
250 strftime(static_buff
, size
, "'%Y-%m-%d %H:%M:%S'", timestruct
);
251 } else if (strcasecmp(Config
->driver
, "odbc") == 0) {
252 timestruct
= gmtime(×tamp
);
253 strftime(static_buff
, size
, "{ ts '%Y-%m-%d %H:%M:%S' }", timestruct
);
255 timestruct
= localtime(×tamp
);
256 strftime(static_buff
, size
, "%Y-%m-%d %H:%M:%S", timestruct
);
260 static SQL_Error
SMSDSQL_NamedQuery(GSM_SMSDConfig
* Config
, const char *sql_query
, GSM_SMSMessage
*sms
,
261 const SQL_Var
*params
, SQL_result
* res
)
263 char buff
[65536], *ptr
, c
, static_buff
[8192];
265 const char *to_print
, *q
= sql_query
;
269 struct GSM_SMSDdbobj
*db
= Config
->db
;
271 if (params
!= NULL
) {
272 while (params
[argc
].type
!= SQL_TYPE_NONE
) argc
++;
283 if( c
>= '0' && c
<= '9'){
284 n
= strtoul(q
, &end
, 10) - 1;
285 if (n
< argc
&& n
>= 0) {
286 switch(params
[n
].type
){
288 ptr
+= sprintf(ptr
, "%i", params
[n
].v
.i
);
290 case SQL_TYPE_STRING
:
291 buffer2
= db
->QuoteString(Config
, params
[n
].v
.s
);
292 memcpy(ptr
, buffer2
, strlen(buffer2
));
293 ptr
+= strlen(buffer2
);
297 SMSD_Log(DEBUG_ERROR
, Config
, "SQL: unknown type: %i (application bug) in query: `%s`", params
[n
].type
, sql_query
);
302 SMSD_Log(DEBUG_ERROR
, Config
, "SQL: wrong number of parameter: %i (max %i) in query: `%s`", n
+1, argc
, sql_query
);
312 to_print
= Config
->Status
->IMEI
;
315 to_print
= Config
->PhoneID
;
318 snprintf(static_buff
, sizeof(static_buff
), "Gammu %s, %s, %s", GAMMU_VERSION
, GetOS(), GetCompiler());
319 to_print
= static_buff
;
322 to_print
= Config
->CreatorID
;
328 EncodeUTF8(static_buff
, sms
->Number
);
329 to_print
= static_buff
;
332 EncodeUTF8(static_buff
, sms
->SMSC
.Number
);
333 to_print
= static_buff
;
336 if (sms
->UDH
.Type
!= UDH_NoUDH
) {
337 EncodeHexBin(static_buff
, sms
->UDH
.Text
, sms
->UDH
.Length
);
338 to_print
= static_buff
;
344 int_to_print
= sms
->Class
;
348 to_print
= GSM_SMSCodingToString(sms
->Coding
);
351 int_to_print
= sms
->MessageReference
;
355 switch (sms
->Coding
) {
356 case SMS_Coding_Unicode_No_Compression
:
357 case SMS_Coding_Default_No_Compression
:
358 EncodeHexUnicode(static_buff
, sms
->Text
, UnicodeLength(sms
->Text
));
360 case SMS_Coding_8bit
:
361 EncodeHexBin(static_buff
, sms
->Text
, sms
->Length
);
367 to_print
= static_buff
;
370 switch (sms
->Coding
) {
371 case SMS_Coding_Unicode_No_Compression
:
372 case SMS_Coding_Default_No_Compression
:
373 EncodeUTF8(static_buff
, sms
->Text
);
374 to_print
= static_buff
;
382 if (sms
->SMSC
.Validity
.Format
== SMS_Validity_RelativeFormat
) {
383 int_to_print
= sms
->SMSC
.Validity
.Relative
;
390 SMSDSQL_Time2String(Config
, Fill_Time_T(sms
->SMSCTime
), static_buff
, sizeof(static_buff
));
391 to_print
= static_buff
;
394 SMSDSQL_Time2String(Config
, Fill_Time_T(sms
->DateTime
), static_buff
, sizeof(static_buff
));
395 to_print
= static_buff
;
398 int_to_print
= sms
->DeliveryStatus
;
402 SMSD_Log(DEBUG_ERROR
, Config
, "SQL: uexpected char '%c' in query: %s", c
, sql_query
);
405 } /* end of switch */
407 SMSD_Log(DEBUG_ERROR
, Config
, "Syntax error in query.. uexpected char '%c' in query: %s", c
, sql_query
);
411 } /* end of switch */
413 ptr
+= sprintf(ptr
, "%i", int_to_print
);
414 } else if (to_print
!= NULL
) {
415 buffer2
= db
->QuoteString(Config
, to_print
);
416 memcpy(ptr
, buffer2
, strlen(buffer2
));
417 ptr
+= strlen(buffer2
);
420 memcpy(ptr
, "NULL", 4);
423 } while (*(++q
) != '\0');
425 return SMSDSQL_Query(Config
, buff
, res
);
429 static GSM_Error
SMSDSQL_CheckTable(GSM_SMSDConfig
* Config
, const char *table
)
434 struct GSM_SMSDdbobj
*db
= Config
->db
;
435 const char *escape_char
;
437 escape_char
= SMSDSQL_EscapeChar(Config
);
439 sprintf(buffer
, "SELECT %s %sID%s FROM %s %s", SMSDSQL_TopClause(Config
, "1"), escape_char
, escape_char
, table
, SMSDSQL_LimitClause(Config
, "1"));
440 error
= SMSDSQL_Query(Config
, buffer
, &res
);
441 if (error
!= SQL_OK
) {
442 SMSD_Log(DEBUG_ERROR
, Config
, "Table %s not found, disconnecting!", table
);
446 db
->FreeResult(Config
, &res
);
450 /* Disconnects from a database */
451 static GSM_Error
SMSDSQL_Free(GSM_SMSDConfig
* Config
)
454 SMSD_Log(DEBUG_SQL
, Config
, "Disconnecting from SQL database.");
455 Config
->db
->Free(Config
);
456 /* free configuration */
457 for(i
= 0; i
< SQL_QUERY_LAST_NO
; i
++){
458 free(Config
->SMSDSQL_queries
[i
]);
459 Config
->SMSDSQL_queries
[i
] = NULL
;
464 /* Connects to database */
465 static GSM_Error
SMSDSQL_Init(GSM_SMSDConfig
* Config
)
470 struct GSM_SMSDdbobj
*db
;
471 const char *escape_char
;
482 if (db
->Connect(Config
) != SQL_OK
)
485 error
= SMSDSQL_CheckTable(Config
, "outbox");
486 if (error
!= ERR_NONE
)
488 error
= SMSDSQL_CheckTable(Config
, "outbox_multipart");
489 if (error
!= ERR_NONE
)
491 error
= SMSDSQL_CheckTable(Config
, "sentitems");
492 if (error
!= ERR_NONE
)
494 error
= SMSDSQL_CheckTable(Config
, "inbox");
495 if (error
!= ERR_NONE
)
498 escape_char
= SMSDSQL_EscapeChar(Config
);
500 sprintf(buffer
, "SELECT %sVersion%s FROM gammu", escape_char
, escape_char
);
501 if (SMSDSQL_Query(Config
, buffer
, &res
) != SQL_OK
) {
505 if (db
->NextRow(Config
, &res
) != 1) {
506 SMSD_Log(DEBUG_ERROR
, Config
, "Failed to seek to first row!");
507 db
->FreeResult(Config
, &res
);
511 version
= db
->GetNumber(Config
, &res
, 0);
512 db
->FreeResult(Config
, &res
);
513 if (SMSD_CheckDBVersion(Config
, version
) != ERR_NONE
) {
518 SMSD_Log(DEBUG_INFO
, Config
, "Connected to Database %s: %s on %s", Config
->driver
, Config
->database
, Config
->host
);
523 static GSM_Error
SMSDSQL_InitAfterConnect(GSM_SMSDConfig
* Config
)
526 struct GSM_SMSDdbobj
*db
= Config
->db
;
527 SQL_Var vars
[3] = {{SQL_TYPE_STRING
, {NULL
}}, {SQL_TYPE_STRING
, {NULL
}}, {SQL_TYPE_NONE
, {NULL
}}};
529 if (SMSDSQL_NamedQuery(Config
, Config
->SMSDSQL_queries
[SQL_QUERY_DELETE_PHONE
], NULL
, NULL
, &res
) != SQL_OK
) {
530 SMSD_Log(DEBUG_INFO
, Config
, "Error deleting from database (%s)", __FUNCTION__
);
533 db
->FreeResult(Config
, &res
);
535 SMSD_Log(DEBUG_INFO
, Config
, "Inserting phone info");
536 vars
[0].v
.s
= Config
->enable_send
? "yes" : "no";
537 vars
[1].v
.s
= Config
->enable_receive
? "yes" : "no";
539 if (SMSDSQL_NamedQuery(Config
, Config
->SMSDSQL_queries
[SQL_QUERY_INSERT_PHONE
], NULL
, vars
, &res
) != SQL_OK
) {
540 SMSD_Log(DEBUG_INFO
, Config
, "Error inserting into database (%s)", __FUNCTION__
);
543 db
->FreeResult(Config
, &res
);
548 /* Save SMS from phone (called Inbox sms - it's in phone Inbox) somewhere */
549 static GSM_Error
SMSDSQL_SaveInboxSMS(GSM_MultiSMSMessage
* sms
, GSM_SMSDConfig
* Config
, char **Locations
)
551 SQL_result res
, res2
;
553 struct GSM_SMSDdbobj
*db
= Config
->db
;
554 const char *q
, *status
;
556 char smstext
[3 * GSM_MAX_SMS_LENGTH
+ 1];
557 char destinationnumber
[3 * GSM_MAX_NUMBER_LENGTH
+ 1];
558 char smsc_message
[3 * GSM_MAX_NUMBER_LENGTH
+ 1];
560 time_t t_time1
, t_time2
;
563 unsigned long long new_id
;
564 size_t locations_size
= 0, locations_pos
= 0;
565 const char *state
, *smsc
;
569 for (i
= 0; i
< sms
->Number
; i
++) {
570 EncodeUTF8(destinationnumber
, sms
->SMS
[i
].Number
);
571 EncodeUTF8(smsc_message
, sms
->SMS
[i
].SMSC
.Number
);
572 if (sms
->SMS
[i
].PDU
== SMS_Status_Report
) {
573 EncodeUTF8(smstext
, sms
->SMS
[i
].Text
);
574 SMSD_Log(DEBUG_INFO
, Config
, "Delivery report: %s to %s", smstext
, destinationnumber
);
576 if (SMSDSQL_NamedQuery(Config
, Config
->SMSDSQL_queries
[SQL_QUERY_SAVE_INBOX_SMS_SELECT
], &sms
->SMS
[i
], NULL
, &res
) != SQL_OK
) {
577 SMSD_Log(DEBUG_INFO
, Config
, "Error reading from database (%s)", __FUNCTION__
);
582 while (db
->NextRow(Config
, &res
)) {
583 smsc
= db
->GetString(Config
, &res
, 4);
584 state
= db
->GetString(Config
, &res
, 1);
585 SMSD_Log(DEBUG_NOTICE
, Config
, "Checking for delivery report, SMSC=%s, state=%s", smsc
, state
);
587 if (strcmp(smsc
, smsc_message
) != 0) {
588 if (Config
->skipsmscnumber
[0] == 0 || strcmp(Config
->skipsmscnumber
, smsc
)) {
593 if (strcmp(state
, "SendingOK") == 0 || strcmp(state
, "DeliveryPending") == 0) {
594 t_time1
= db
->GetDate(Config
, &res
, 2);
596 SMSD_Log(DEBUG_ERROR
, Config
, "Invalid SendingDateTime -1 for SMS TPMR=%i", sms
->SMS
[i
].MessageReference
);
599 t_time2
= Fill_Time_T(sms
->SMS
[i
].DateTime
);
600 diff
= t_time2
- t_time1
;
602 if (diff
> -Config
->deliveryreportdelay
&& diff
< Config
->deliveryreportdelay
) {
606 SMSD_Log(DEBUG_NOTICE
, Config
,
607 "Delivery report would match, but time delta is too big (%ld), consider increasing DeliveryReportDelay", diff
);
613 if (!strcmp(smstext
, "Delivered")) {
614 q
= Config
->SMSDSQL_queries
[SQL_QUERY_SAVE_INBOX_SMS_UPDATE_DELIVERED
];
616 q
= Config
->SMSDSQL_queries
[SQL_QUERY_SAVE_INBOX_SMS_UPDATE
];
619 if (!strcmp(smstext
, "Delivered")) {
620 status
= "DeliveryOK";
621 } else if (!strcmp(smstext
, "Failed")) {
622 status
= "DeliveryFailed";
623 } else if (!strcmp(smstext
, "Pending")) {
624 status
= "DeliveryPending";
625 } else if (!strcmp(smstext
, "Unknown")) {
626 status
= "DeliveryUnknown";
631 vars
[0].type
= SQL_TYPE_STRING
;
632 vars
[0].v
.s
= status
; /* Status */
633 vars
[1].type
= SQL_TYPE_INT
;
634 vars
[1].v
.i
= (long)db
->GetNumber(Config
, &res
, 0); /* ID */
635 vars
[2].type
= SQL_TYPE_NONE
;
637 if (SMSDSQL_NamedQuery(Config
, q
, &sms
->SMS
[i
], vars
, &res2
) != SQL_OK
) {
638 SMSD_Log(DEBUG_INFO
, Config
, "Error writing to database (%s)", __FUNCTION__
);
641 db
->FreeResult(Config
, &res2
);
643 db
->FreeResult(Config
, &res
);
647 if (sms
->SMS
[i
].PDU
!= SMS_Deliver
)
650 if (SMSDSQL_NamedQuery(Config
, Config
->SMSDSQL_queries
[SQL_QUERY_SAVE_INBOX_SMS_INSERT
], &sms
->SMS
[i
], NULL
, &res
) != SQL_OK
) {
651 SMSD_Log(DEBUG_INFO
, Config
, "Error writing to database (%s)", __FUNCTION__
);
655 new_id
= db
->SeqID(Config
, "inbox_ID_seq");
657 SMSD_Log(DEBUG_INFO
, Config
, "Failed to get inserted row ID (%s)", __FUNCTION__
);
660 SMSD_Log(DEBUG_NOTICE
, Config
, "Inserted message id %lu", (long)new_id
);
662 db
->FreeResult(Config
, &res
);
665 if (locations_pos
+ 10 >= locations_size
) {
666 locations_size
+= 40;
667 *Locations
= (char *)realloc(*Locations
, locations_size
);
668 assert(*Locations
!= NULL
);
669 if (locations_pos
== 0) {
673 locations_pos
+= sprintf((*Locations
) + locations_pos
, "%lu ", (long)new_id
);
676 if (SMSDSQL_NamedQuery(Config
, Config
->SMSDSQL_queries
[SQL_QUERY_UPDATE_RECEIVED
], &sms
->SMS
[i
], NULL
, &res2
) != SQL_OK
) {
677 SMSD_Log(DEBUG_INFO
, Config
, "Error updating number of received messages (%s)", __FUNCTION__
);
680 db
->FreeResult(Config
, &res2
);
687 static GSM_Error
SMSDSQL_RefreshSendStatus(GSM_SMSDConfig
* Config
, char *ID
)
690 struct GSM_SMSDdbobj
*db
= Config
->db
;
692 {SQL_TYPE_STRING
, {ID
}},
693 {SQL_TYPE_NONE
, {NULL
}}};
695 if (SMSDSQL_NamedQuery(Config
, Config
->SMSDSQL_queries
[SQL_QUERY_REFRESH_SEND_STATUS
], NULL
, vars
, &res
) != SQL_OK
) {
696 SMSD_Log(DEBUG_INFO
, Config
, "Error writing to database (%s)", __FUNCTION__
);
700 if (db
->AffectedRows(Config
, &res
) == 0) {
701 db
->FreeResult(Config
, &res
);
705 db
->FreeResult(Config
, &res
);
709 /* Find one multi SMS to sending and return it (or return ERR_EMPTY)
710 * There is also set ID for SMS
712 static GSM_Error
SMSDSQL_FindOutboxSMS(GSM_MultiSMSMessage
* sms
, GSM_SMSDConfig
* Config
, char *ID
)
715 struct GSM_SMSDdbobj
*db
= Config
->db
;
721 const char *text_decoded
;
722 const char *destination
;
728 vars
[0].type
= SQL_TYPE_INT
;
730 vars
[1].type
= SQL_TYPE_NONE
;
733 if (SMSDSQL_NamedQuery(Config
, Config
->SMSDSQL_queries
[SQL_QUERY_FIND_OUTBOX_SMS_ID
], NULL
, vars
, &res
) != SQL_OK
) {
734 SMSD_Log(DEBUG_INFO
, Config
, "Error reading from database (%s)", __FUNCTION__
);
738 if (db
->NextRow(Config
, &res
) != 1) {
739 db
->FreeResult(Config
, &res
);
743 sprintf(ID
, "%ld", (long)db
->GetNumber(Config
, &res
, 0));
744 timestamp
= db
->GetDate(Config
, &res
, 1);
746 db
->FreeResult(Config
, &res
);
748 if (timestamp
== -1) {
749 SMSD_Log(DEBUG_INFO
, Config
, "Invalid date for InsertIntoDB.");
753 SMSDSQL_Time2String(Config
, timestamp
, Config
->DT
, sizeof(Config
->DT
));
754 if (SMSDSQL_RefreshSendStatus(Config
, ID
) == ERR_NONE
) {
760 for (i
= 0; i
< GSM_MAX_MULTI_SMS
; i
++) {
761 GSM_SetDefaultSMSData(&sms
->SMS
[i
]);
762 sms
->SMS
[i
].SMSC
.Number
[0] = 0;
763 sms
->SMS
[i
].SMSC
.Number
[1] = 0;
766 for (i
= 1; i
< GSM_MAX_MULTI_SMS
+ 1; i
++) {
767 vars
[0].type
= SQL_TYPE_STRING
;
769 vars
[1].type
= SQL_TYPE_INT
;
771 vars
[2].type
= SQL_TYPE_NONE
;
773 q
= Config
->SMSDSQL_queries
[SQL_QUERY_FIND_OUTBOX_BODY
];
775 q
= Config
->SMSDSQL_queries
[SQL_QUERY_FIND_OUTBOX_MULTIPART
];
777 if (SMSDSQL_NamedQuery(Config
, q
, NULL
, vars
, &res
) != SQL_OK
) {
778 SMSD_Log(DEBUG_ERROR
, Config
, "Error reading from database (%s)", __FUNCTION__
);
782 if (db
->NextRow(Config
, &res
) != 1) {
783 db
->FreeResult(Config
, &res
);
787 coding
= db
->GetString(Config
, &res
, 1);
788 text
= db
->GetString(Config
, &res
, 0);
792 text_len
= strlen(text
);
794 text_decoded
= db
->GetString(Config
, &res
, 4);
795 udh
= db
->GetString(Config
, &res
, 2);
799 udh_len
= strlen(udh
);
802 sms
->SMS
[sms
->Number
].Coding
= GSM_StringToSMSCoding(coding
);
803 if (sms
->SMS
[sms
->Number
].Coding
== 0) {
804 if (text
== NULL
|| text_len
== 0) {
805 SMSD_Log(DEBUG_NOTICE
, Config
, "Assuming default coding for text message");
806 sms
->SMS
[sms
->Number
].Coding
= SMS_Coding_Default_No_Compression
;
808 SMSD_Log(DEBUG_NOTICE
, Config
, "Assuming 8bit coding for binary message");
809 sms
->SMS
[sms
->Number
].Coding
= SMS_Coding_8bit
;
813 if (text
== NULL
|| text_len
== 0) {
814 if (text_decoded
== NULL
) {
815 SMSD_Log(DEBUG_ERROR
, Config
, "Message without text!");
818 SMSD_Log(DEBUG_NOTICE
, Config
, "Message: %s", text_decoded
);
819 DecodeUTF8(sms
->SMS
[sms
->Number
].Text
, text_decoded
, strlen(text_decoded
));
822 switch (sms
->SMS
[sms
->Number
].Coding
) {
823 case SMS_Coding_Unicode_No_Compression
:
825 case SMS_Coding_Default_No_Compression
:
826 DecodeHexUnicode(sms
->SMS
[sms
->Number
].Text
, text
, text_len
);
829 case SMS_Coding_8bit
:
830 DecodeHexBin(sms
->SMS
[sms
->Number
].Text
, text
, text_len
);
831 sms
->SMS
[sms
->Number
].Length
= text_len
/ 2;
840 destination
= db
->GetString(Config
, &res
, 6);
841 if (destination
== NULL
) {
842 SMSD_Log(DEBUG_ERROR
, Config
, "Message without recipient!");
845 DecodeUTF8(sms
->SMS
[sms
->Number
].Number
, destination
, strlen(destination
));
847 CopyUnicodeString(sms
->SMS
[sms
->Number
].Number
, sms
->SMS
[0].Number
);
850 sms
->SMS
[sms
->Number
].UDH
.Type
= UDH_NoUDH
;
851 if (udh
!= NULL
&& udh_len
!= 0) {
852 sms
->SMS
[sms
->Number
].UDH
.Type
= UDH_UserUDH
;
853 sms
->SMS
[sms
->Number
].UDH
.Length
= udh_len
/ 2;
854 DecodeHexBin(sms
->SMS
[sms
->Number
].UDH
.Text
, udh
, udh_len
);
857 sms
->SMS
[sms
->Number
].Class
= db
->GetNumber(Config
, &res
, 3);
858 sms
->SMS
[sms
->Number
].PDU
= SMS_Submit
;
862 strcpy(Config
->CreatorID
, db
->GetString(Config
, &res
, 10));
863 Config
->relativevalidity
= db
->GetNumber(Config
, &res
, 8);
865 Config
->currdeliveryreport
= db
->GetBool(Config
, &res
, 9);
867 /* Is this a multipart message? */
868 if (!db
->GetBool(Config
, &res
, 7)) {
869 db
->FreeResult(Config
, &res
);
874 db
->FreeResult(Config
, &res
);
880 /* After sending SMS is moved to Sent Items or Error Items. */
881 static GSM_Error
SMSDSQL_MoveSMS(GSM_MultiSMSMessage
* sms UNUSED
, GSM_SMSDConfig
* Config
, char *ID
, gboolean alwaysDelete UNUSED
, gboolean sent UNUSED
)
885 struct GSM_SMSDdbobj
*db
= Config
->db
;
887 vars
[0].type
= SQL_TYPE_STRING
;
889 vars
[1].type
= SQL_TYPE_NONE
;
891 if (SMSDSQL_NamedQuery(Config
, Config
->SMSDSQL_queries
[SQL_QUERY_DELETE_OUTBOX
], NULL
, vars
, &res
) != SQL_OK
) {
892 SMSD_Log(DEBUG_INFO
, Config
, "Error deleting from database (%s)", __FUNCTION__
);
895 db
->FreeResult(Config
, &res
);
897 if (SMSDSQL_NamedQuery(Config
, Config
->SMSDSQL_queries
[SQL_QUERY_DELETE_OUTBOX_MULTIPART
], NULL
, vars
, &res
) != SQL_OK
) {
898 SMSD_Log(DEBUG_INFO
, Config
, "Error deleting from database (%s)", __FUNCTION__
);
901 db
->FreeResult(Config
, &res
);
906 /* Adds SMS to Outbox */
907 static GSM_Error
SMSDSQL_CreateOutboxSMS(GSM_MultiSMSMessage
* sms
, GSM_SMSDConfig
* Config
, char *NewID
)
914 struct GSM_SMSDdbobj
*db
= Config
->db
;
915 const char *report
, *multipart
, *q
;
917 sprintf(creator
, "Gammu %s",GAMMU_VERSION
); /* %1 */
918 multipart
= (sms
->Number
== 1) ? "FALSE" : "TRUE"; /* %3 */
920 for (i
= 0; i
< sms
->Number
; i
++) {
921 report
= (sms
->SMS
[i
].PDU
== SMS_Status_Report
) ? "yes": "default"; /* %2 */
923 q
= Config
->SMSDSQL_queries
[SQL_QUERY_CREATE_OUTBOX
];
925 q
= Config
->SMSDSQL_queries
[SQL_QUERY_CREATE_OUTBOX_MULTIPART
];
928 vars
[0].type
= SQL_TYPE_STRING
;
929 vars
[0].v
.s
= creator
;
930 vars
[1].type
= SQL_TYPE_STRING
;
931 vars
[1].v
.s
= report
;
932 vars
[2].type
= SQL_TYPE_STRING
;
933 vars
[2].v
.s
= multipart
;
934 vars
[3].type
= SQL_TYPE_INT
;
936 vars
[4].type
= SQL_TYPE_INT
;
938 vars
[5].type
= SQL_TYPE_NONE
;
940 if (SMSDSQL_NamedQuery(Config
, q
, &sms
->SMS
[i
], vars
, &res
) != SQL_OK
) {
941 SMSD_Log(DEBUG_INFO
, Config
, "Error writing to database (%s)", __FUNCTION__
);
945 ID
= db
->SeqID(Config
, "outbox_ID_seq");
947 SMSD_Log(DEBUG_INFO
, Config
, "Failed to get inserted row ID (%s)", __FUNCTION__
);
951 db
->FreeResult(Config
, &res
);
953 SMSD_Log(DEBUG_INFO
, Config
, "Written message with ID %u", ID
);
955 sprintf(NewID
, "%d", ID
);
959 static GSM_Error
SMSDSQL_AddSentSMSInfo(GSM_MultiSMSMessage
* sms
, GSM_SMSDConfig
* Config
, char *ID
, int Part
, GSM_SMSDSendingError err
, int TPMR
)
962 struct GSM_SMSDdbobj
*db
= Config
->db
;
964 const char *message_state
;
966 char smsc
[GSM_MAX_NUMBER_LENGTH
+ 1];
967 char destination
[GSM_MAX_NUMBER_LENGTH
+ 1];
969 EncodeUTF8(smsc
, sms
->SMS
[Part
- 1].SMSC
.Number
);
970 EncodeUTF8(destination
, sms
->SMS
[Part
- 1].Number
);
972 if (err
== SMSD_SEND_OK
) {
973 SMSD_Log(DEBUG_NOTICE
, Config
, "Transmitted %s (%s: %i) to %s", Config
->SMSID
,
974 (Part
== sms
->Number
? "total" : "part"), Part
, DecodeUnicodeString(sms
->SMS
[0].Number
));
977 if (err
== SMSD_SEND_OK
) {
978 if (sms
->SMS
[Part
- 1].PDU
== SMS_Status_Report
) {
979 message_state
= "SendingOK";
981 message_state
= "SendingOKNoReport";
983 } else if (err
== SMSD_SEND_SENDING_ERROR
) {
984 message_state
= "SendingError";
985 } else if (err
== SMSD_SEND_ERROR
) {
986 message_state
= "Error";
988 SMSD_Log(DEBUG_INFO
, Config
, "Unknown SMS state: %d, assuming Error", err
);
989 message_state
= "Error";
992 /* 1 = ID, 2 = SequencePosition, 3 = Status, 4 = TPMR, 5 = insertintodb */
993 vars
[0].type
= SQL_TYPE_STRING
;
995 vars
[1].type
= SQL_TYPE_INT
;
997 vars
[2].type
= SQL_TYPE_STRING
;
998 vars
[2].v
.s
= message_state
;
999 vars
[3].type
= SQL_TYPE_INT
;
1001 vars
[4].type
= SQL_TYPE_STRING
;
1002 vars
[4].v
.s
= Config
->DT
;
1003 vars
[5].type
= SQL_TYPE_NONE
;
1005 if (SMSDSQL_NamedQuery(Config
, Config
->SMSDSQL_queries
[SQL_QUERY_ADD_SENT_INFO
], &sms
->SMS
[Part
- 1], vars
, &res
) != SQL_OK
) {
1006 SMSD_Log(DEBUG_INFO
, Config
, "Error writing to database (%s)", __FUNCTION__
);
1009 db
->FreeResult(Config
, &res
);
1011 if (SMSDSQL_NamedQuery(Config
, Config
->SMSDSQL_queries
[SQL_QUERY_UPDATE_SENT
], &sms
->SMS
[Part
- 1], NULL
, &res
) != SQL_OK
) {
1012 SMSD_Log(DEBUG_INFO
, Config
, "Error updating number of sent messages (%s)", __FUNCTION__
);
1015 db
->FreeResult(Config
, &res
);
1020 static GSM_Error
SMSDSQL_RefreshPhoneStatus(GSM_SMSDConfig
* Config
)
1024 {SQL_TYPE_INT
, {NULL
}},
1025 {SQL_TYPE_INT
, {NULL
}},
1026 {SQL_TYPE_NONE
, {NULL
}}};
1027 struct GSM_SMSDdbobj
*db
= Config
->db
;
1028 vars
[0].v
.i
= Config
->Status
->Charge
.BatteryPercent
;
1029 vars
[1].v
.i
= Config
->Status
->Network
.SignalPercent
;
1031 if (SMSDSQL_NamedQuery(Config
, Config
->SMSDSQL_queries
[SQL_QUERY_REFRESH_PHONE_STATUS
], NULL
, vars
, &res
) != SQL_OK
) {
1032 SMSD_Log(DEBUG_INFO
, Config
, "Error writing to database (%s)", __FUNCTION__
);
1035 db
->FreeResult(Config
, &res
);
1041 * better strcat... shows where is the bug
1043 #define STRCAT_MAX 80
1044 GSM_Error
SMSDSQL_option(GSM_SMSDConfig
*Config
, int optint
, const char *option
, ...)
1046 size_t len
[STRCAT_MAX
], to_alloc
= 0;
1050 const char *args
[STRCAT_MAX
];
1053 /* read from config */
1054 buffer
= INI_GetValue(Config
->smsdcfgfile
, "sql", option
, FALSE
);
1056 if (buffer
!= NULL
){
1057 Config
->SMSDSQL_queries
[optint
] = strdup(buffer
); /* avoid to double free */
1061 /* not found.. we use default query */
1062 va_start(ap
, option
);
1063 for(i
= 0; i
< STRCAT_MAX
; i
++){
1064 arg
= va_arg(ap
, const char *);
1067 len
[i
] = strlen(arg
);
1073 if (i
== STRCAT_MAX
) {
1074 SMSD_Log(DEBUG_ERROR
, Config
, "STRCAT_MAX too small.. consider increase this value for option %s", option
);
1078 buffer
= malloc(to_alloc
+1);
1079 if (buffer
== NULL
){
1080 SMSD_Log(DEBUG_ERROR
, Config
, "Insufficient memory problem for option %s", option
);
1084 for (j
= 0; j
< i
; j
++) {
1085 memcpy(ptr
, args
[j
], len
[j
]);
1089 Config
->SMSDSQL_queries
[optint
] = buffer
;
1095 * Reads common options for database backends.
1097 GSM_Error
SMSDSQL_ReadConfiguration(GSM_SMSDConfig
*Config
)
1100 const char *escape_char
;
1102 Config
->user
= INI_GetValue(Config
->smsdcfgfile
, "smsd", "user", FALSE
);
1103 if (Config
->user
== NULL
) {
1104 Config
->user
="root";
1107 Config
->password
= INI_GetValue(Config
->smsdcfgfile
, "smsd", "password", FALSE
);
1108 if (Config
->password
== NULL
) {
1109 Config
->password
="";
1112 Config
->host
= INI_GetValue(Config
->smsdcfgfile
, "smsd", "host", FALSE
);
1113 if (Config
->host
== NULL
) {
1114 /* Backward compatibility */
1115 Config
->host
= INI_GetValue(Config
->smsdcfgfile
, "smsd", "pc", FALSE
);
1117 if (Config
->host
== NULL
) {
1118 Config
->host
="localhost";
1121 Config
->database
= INI_GetValue(Config
->smsdcfgfile
, "smsd", "database", FALSE
);
1122 if (Config
->database
== NULL
) {
1123 Config
->database
="sms";
1126 Config
->driverspath
= INI_GetValue(Config
->smsdcfgfile
, "smsd", "driverspath", FALSE
);
1128 Config
->sql
= INI_GetValue(Config
->smsdcfgfile
, "smsd", "sql", FALSE
);
1130 Config
->dbdir
= INI_GetValue(Config
->smsdcfgfile
, "smsd", "dbdir", FALSE
);
1132 if (Config
->driver
== NULL
) {
1133 SMSD_Log(DEBUG_ERROR
, Config
, "No database driver selected. Must be native_mysql, native_pgsql, ODBC or DBI one.");
1138 #ifdef HAVE_MYSQL_MYSQL_H
1139 if (!strcasecmp(Config
->driver
, "native_mysql")) {
1140 Config
->db
= &SMSDMySQL
;
1143 #ifdef HAVE_POSTGRESQL_LIBPQ_FE_H
1144 if (!strcasecmp(Config
->driver
, "native_pgsql")) {
1145 Config
->db
= &SMSDPgSQL
;
1149 if (!strcasecmp(Config
->driver
, "odbc")) {
1150 Config
->db
= &SMSDODBC
;
1151 if (Config
->sql
== NULL
) {
1152 SMSD_Log(DEBUG_INFO
, Config
, "Using generic SQL for ODBC, this might fail. In such case please set SQL configuration option.");
1156 if (Config
->db
== NULL
) {
1158 Config
->db
= &SMSDDBI
;
1160 SMSD_Log(DEBUG_ERROR
, Config
, "Unknown DB driver");
1165 escape_char
= SMSDSQL_EscapeChar(Config
);
1166 #define ESCAPE_FIELD(x) escape_char, x, escape_char
1168 locktime
= Config
->loopsleep
* 8; /* reserve 8 sec per message */
1169 locktime
= locktime
< 60 ? 60 : locktime
; /* Minimum time reserve is 60 sec */
1171 if (SMSDSQL_option(Config
, SQL_QUERY_DELETE_PHONE
, "delete_phone",
1172 "DELETE FROM phones WHERE ", ESCAPE_FIELD("IMEI"), " = %I", NULL
) != ERR_NONE
) {
1176 if (SMSDSQL_option(Config
, SQL_QUERY_INSERT_PHONE
, "insert_phone",
1177 "INSERT INTO phones (",
1178 ESCAPE_FIELD("IMEI"),
1179 ", ", ESCAPE_FIELD("ID"),
1180 ", ", ESCAPE_FIELD("Send"),
1181 ", ", ESCAPE_FIELD("Receive"),
1182 ", ", ESCAPE_FIELD("InsertIntoDB"),
1183 ", ", ESCAPE_FIELD("TimeOut"),
1184 ", ", ESCAPE_FIELD("Client"),
1185 ", ", ESCAPE_FIELD("Battery"),
1186 ", ", ESCAPE_FIELD("Signal"),
1187 ") VALUES (%I, %P, %1, %2, ",
1188 SMSDSQL_Now(Config
),
1190 SMSDSQL_NowPlus(Config
, 10),
1191 ", %N, -1, -1)", NULL
) != ERR_NONE
) {
1195 if (SMSDSQL_option(Config
, SQL_QUERY_SAVE_INBOX_SMS_SELECT
, "save_inbox_sms_select",
1198 ", ", ESCAPE_FIELD("Status"),
1199 ", ", ESCAPE_FIELD("SendingDateTime"),
1200 ", ", ESCAPE_FIELD("DeliveryDateTime"),
1201 ", ", ESCAPE_FIELD("SMSCNumber"), " "
1202 "FROM sentitems WHERE ",
1203 ESCAPE_FIELD("DeliveryDateTime"), " IS NULL AND ",
1204 ESCAPE_FIELD("SenderID"), " = %P AND ",
1205 ESCAPE_FIELD("TPMR"), " = %t AND ",
1206 ESCAPE_FIELD("DestinationNumber"), " = %R", NULL
) != ERR_NONE
) {
1210 if (SMSDSQL_option(Config
, SQL_QUERY_SAVE_INBOX_SMS_UPDATE_DELIVERED
, "save_inbox_sms_update_delivered",
1212 "SET ", ESCAPE_FIELD("DeliveryDateTime"), " = %C"
1213 ", ", ESCAPE_FIELD("Status"), " = %1"
1214 ", ", ESCAPE_FIELD("StatusError"), " = %e"
1215 " WHERE ", ESCAPE_FIELD("ID"), " = %2"
1216 " AND ", ESCAPE_FIELD("TPMR"), " = %t", NULL
) != ERR_NONE
) {
1220 if (SMSDSQL_option(Config
, SQL_QUERY_SAVE_INBOX_SMS_UPDATE
, "save_inbox_sms_update",
1222 "SET ", ESCAPE_FIELD("Status"), " = %1"
1223 ", ", ESCAPE_FIELD("StatusError"), " = %e"
1224 " WHERE ", ESCAPE_FIELD("ID"), " = %2"
1225 " AND ", ESCAPE_FIELD("TPMR"), " = %t", NULL
) != ERR_NONE
) {
1229 if (SMSDSQL_option(Config
, SQL_QUERY_SAVE_INBOX_SMS_INSERT
, "save_inbox_sms_insert",
1230 "INSERT INTO inbox "
1231 "(", ESCAPE_FIELD("ReceivingDateTime"),
1232 ", ", ESCAPE_FIELD("Text"),
1233 ", ", ESCAPE_FIELD("SenderNumber"),
1234 ", ", ESCAPE_FIELD("Coding"),
1235 ", ", ESCAPE_FIELD("SMSCNumber"),
1236 ", ", ESCAPE_FIELD("UDH"),
1237 ", ", ESCAPE_FIELD("Class"),
1238 ", ", ESCAPE_FIELD("TextDecoded"),
1239 ", ", ESCAPE_FIELD("RecipientID"), ")"
1240 " VALUES (%d, %E, %R, %c, %F, %u, %x, %T, %P)", NULL
) != ERR_NONE
) {
1244 if (SMSDSQL_option(Config
, SQL_QUERY_UPDATE_RECEIVED
, "update_received",
1245 "UPDATE phones SET ",
1246 ESCAPE_FIELD("Received"), " = ", ESCAPE_FIELD("Received"), " + 1"
1247 " WHERE ", ESCAPE_FIELD("IMEI"), " = %I", NULL
) != ERR_NONE
) {
1251 if (SMSDSQL_option(Config
, SQL_QUERY_REFRESH_SEND_STATUS
, "refresh_send_status",
1252 "UPDATE outbox SET ",
1253 ESCAPE_FIELD("SendingTimeOut"), " = ", SMSDSQL_NowPlus(Config
, locktime
),
1254 " WHERE ", ESCAPE_FIELD("ID"), " = %1"
1255 " AND (", ESCAPE_FIELD("SendingTimeOut"), " < ", SMSDSQL_Now(Config
),
1256 " OR ", ESCAPE_FIELD("SendingTimeOut"), " IS NULL)", NULL
) != ERR_NONE
) {
1260 if (SMSDSQL_option(Config
, SQL_QUERY_FIND_OUTBOX_SMS_ID
, "find_outbox_sms_id",
1261 "SELECT ", SMSDSQL_TopClause(Config
, "%1"),
1263 ", ", ESCAPE_FIELD("InsertIntoDB"),
1264 ", ", ESCAPE_FIELD("SendingDateTime"),
1265 ", ", ESCAPE_FIELD("SenderID"),
1266 " FROM outbox WHERE ",
1267 ESCAPE_FIELD("SendingDateTime"), " < ", SMSDSQL_Now(Config
),
1268 " AND ", ESCAPE_FIELD("SendingTimeOut"), " < ", SMSDSQL_Now(Config
),
1269 " AND ", ESCAPE_FIELD("SendBefore"), " >= ", SMSDSQL_CurrentTime(Config
),
1270 " AND ", ESCAPE_FIELD("SendAfter"), " <= ", SMSDSQL_CurrentTime(Config
),
1271 " AND ( ", ESCAPE_FIELD("SenderID"), " is NULL OR ", ESCAPE_FIELD("SenderID"), " = '' OR ", ESCAPE_FIELD("SenderID"), " = %P )"
1272 " ORDER BY ", ESCAPE_FIELD("InsertIntoDB"), " ASC ", SMSDSQL_LimitClause(Config
, "%1"), NULL
) != ERR_NONE
) {
1276 if (SMSDSQL_option(Config
, SQL_QUERY_FIND_OUTBOX_BODY
, "find_outbox_body",
1278 ESCAPE_FIELD("Text"),
1279 ", ", ESCAPE_FIELD("Coding"),
1280 ", ", ESCAPE_FIELD("UDH"),
1281 ", ", ESCAPE_FIELD("Class"),
1282 ", ", ESCAPE_FIELD("TextDecoded"),
1283 ", ", ESCAPE_FIELD("ID"),
1284 ", ", ESCAPE_FIELD("DestinationNumber"),
1285 ", ", ESCAPE_FIELD("MultiPart"),
1286 ", ", ESCAPE_FIELD("RelativeValidity"),
1287 ", ", ESCAPE_FIELD("DeliveryReport"),
1288 ", ", ESCAPE_FIELD("CreatorID"),
1289 " FROM outbox WHERE ",
1290 ESCAPE_FIELD("ID"), "=%1", NULL
) != ERR_NONE
) {
1294 if (SMSDSQL_option(Config
, SQL_QUERY_FIND_OUTBOX_MULTIPART
, "find_outbox_multipart",
1296 ESCAPE_FIELD("Text"),
1297 ", ", ESCAPE_FIELD("Coding"),
1298 ", ", ESCAPE_FIELD("UDH"),
1299 ", ", ESCAPE_FIELD("Class"),
1300 ", ", ESCAPE_FIELD("TextDecoded"),
1301 ", ", ESCAPE_FIELD("ID"),
1302 ", ", ESCAPE_FIELD("SequencePosition"),
1303 " FROM outbox_multipart WHERE ",
1304 ESCAPE_FIELD("ID"), "=%1 AND ",
1305 ESCAPE_FIELD("SequencePosition"), "=%2", NULL
) != ERR_NONE
) {
1309 if (SMSDSQL_option(Config
, SQL_QUERY_DELETE_OUTBOX
, "delete_outbox",
1310 "DELETE FROM outbox WHERE ", ESCAPE_FIELD("ID"), "=%1", NULL
) != ERR_NONE
) {
1314 if (SMSDSQL_option(Config
, SQL_QUERY_DELETE_OUTBOX_MULTIPART
, "delete_outbox_multipart",
1315 "DELETE FROM outbox_multipart WHERE ", ESCAPE_FIELD("ID"), "=%1", NULL
) != ERR_NONE
) {
1319 if (SMSDSQL_option(Config
, SQL_QUERY_CREATE_OUTBOX
, "create_outbox",
1320 "INSERT INTO outbox "
1321 "(", ESCAPE_FIELD("CreatorID"),
1322 ", ", ESCAPE_FIELD("SenderID"),
1323 ", ", ESCAPE_FIELD("DeliveryReport"),
1324 ", ", ESCAPE_FIELD("MultiPart"),
1325 ", ", ESCAPE_FIELD("InsertIntoDB"),
1326 ", ", ESCAPE_FIELD("Text"),
1327 ", ", ESCAPE_FIELD("DestinationNumber"),
1328 ", ", ESCAPE_FIELD("RelativeValidity"),
1329 ", ", ESCAPE_FIELD("Coding"),
1330 ", ", ESCAPE_FIELD("UDH"),
1331 ", ", ESCAPE_FIELD("Class"),
1332 ", ", ESCAPE_FIELD("TextDecoded"), ") VALUES "
1333 "(%1, %P, %2, %3, ", SMSDSQL_Now(Config
),
1334 ", %E, %R, %V, %c, %u, %x, %T)", NULL
) != ERR_NONE
) {
1338 if (SMSDSQL_option(Config
, SQL_QUERY_CREATE_OUTBOX_MULTIPART
, "create_outbox_multipart",
1339 "INSERT INTO outbox_multipart "
1340 "(", ESCAPE_FIELD("SequencePosition"),
1341 ", ", ESCAPE_FIELD("Text"),
1342 ", ", ESCAPE_FIELD("Coding"),
1343 ", ", ESCAPE_FIELD("UDH"),
1344 ", ", ESCAPE_FIELD("Class"),
1345 ", ", ESCAPE_FIELD("TextDecoded"),
1346 ", ", ESCAPE_FIELD("ID"), ") VALUES (%4, %E, %c, %u, %x, %T, %5)", NULL
) != ERR_NONE
) {
1350 if (SMSDSQL_option(Config
, SQL_QUERY_ADD_SENT_INFO
, "add_sent_info",
1351 "INSERT INTO sentitems "
1352 "(", ESCAPE_FIELD("CreatorID"),
1353 ", ", ESCAPE_FIELD("ID"),
1354 ", ", ESCAPE_FIELD("SequencePosition"),
1355 ", ", ESCAPE_FIELD("Status"),
1356 ", ", ESCAPE_FIELD("SendingDateTime"),
1357 ", ", ESCAPE_FIELD("SMSCNumber"),
1358 ", ", ESCAPE_FIELD("TPMR"),
1359 ", ", ESCAPE_FIELD("SenderID"),
1360 ", ", ESCAPE_FIELD("Text"),
1361 ", ", ESCAPE_FIELD("DestinationNumber"),
1362 ", ", ESCAPE_FIELD("Coding"),
1363 ", ", ESCAPE_FIELD("UDH"),
1364 ", ", ESCAPE_FIELD("Class"),
1365 ", ", ESCAPE_FIELD("TextDecoded"),
1366 ", ", ESCAPE_FIELD("InsertIntoDB"),
1367 ", ", ESCAPE_FIELD("RelativeValidity"),
1369 " VALUES (%A, %1, %2, %3, ",
1370 SMSDSQL_Now(Config
),
1371 ", %F, %4, %P, %E, %R, %c, %u, %x, %T, %5, %V)", NULL
) != ERR_NONE
) {
1375 if (SMSDSQL_option(Config
, SQL_QUERY_UPDATE_SENT
, "update_sent",
1376 "UPDATE phones SET ",
1377 ESCAPE_FIELD("Sent"), "= ", ESCAPE_FIELD("Sent"), " + 1"
1378 " WHERE ", ESCAPE_FIELD("IMEI"), " = %I", NULL
) != ERR_NONE
) {
1382 if (SMSDSQL_option(Config
, SQL_QUERY_REFRESH_PHONE_STATUS
, "refresh_phone_status",
1383 "UPDATE phones SET ",
1384 ESCAPE_FIELD("TimeOut"), "= ", SMSDSQL_NowPlus(Config
, 10),
1385 ", ", ESCAPE_FIELD("Battery"), " = %1"
1386 ", ", ESCAPE_FIELD("Signal"), " = %2"
1387 " WHERE ", ESCAPE_FIELD("IMEI"), " = %I", NULL
) != ERR_NONE
) {
1395 time_t SMSDSQL_ParseDate(GSM_SMSDConfig
* Config
, const char *date
)
1398 struct tm timestruct
;
1401 if (strcmp(date
, "0000-00-00 00:00:00") == 0) {
1405 parse_res
= strptime(date
, "%Y-%m-%d %H:%M:%S", ×truct
);
1407 if (parse_res
!= NULL
&& *parse_res
== 0) {
1408 DT
.Year
= timestruct
.tm_year
+ 1900;
1409 DT
.Month
= timestruct
.tm_mon
+ 1;
1410 DT
.Day
= timestruct
.tm_mday
;
1411 DT
.Hour
= timestruct
.tm_hour
;
1412 DT
.Minute
= timestruct
.tm_min
;
1413 DT
.Second
= timestruct
.tm_sec
;
1415 return Fill_Time_T(DT
);
1417 /* Used during testing */
1418 if (Config
!= NULL
) {
1419 SMSD_Log(DEBUG_ERROR
, Config
, "Failed to parse date: %s", date
);
1424 GSM_SMSDService SMSDSQL
= {
1427 SMSDSQL_InitAfterConnect
,
1428 SMSDSQL_SaveInboxSMS
,
1429 SMSDSQL_FindOutboxSMS
,
1431 SMSDSQL_CreateOutboxSMS
,
1432 SMSDSQL_AddSentSMSInfo
,
1433 SMSDSQL_RefreshSendStatus
,
1434 SMSDSQL_RefreshPhoneStatus
,
1435 SMSDSQL_ReadConfiguration
1438 /* How should editor hadle tabs in this file? Add editor commands here.
1439 * vim: noexpandtab sw=8 ts=8 sts=8: