Kannel: Open Source WAP and SMS gateway  svn-r5335
smsc_cimd2.c
Go to the documentation of this file.
1 /* ====================================================================
2  * The Kannel Software License, Version 1.0
3  *
4  * Copyright (c) 2001-2018 Kannel Group
5  * Copyright (c) 1998-2001 WapIT Ltd.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  * notice, this list of conditions and the following disclaimer in
17  * the documentation and/or other materials provided with the
18  * distribution.
19  *
20  * 3. The end-user documentation included with the redistribution,
21  * if any, must include the following acknowledgment:
22  * "This product includes software developed by the
23  * Kannel Group (http://www.kannel.org/)."
24  * Alternately, this acknowledgment may appear in the software itself,
25  * if and wherever such third-party acknowledgments normally appear.
26  *
27  * 4. The names "Kannel" and "Kannel Group" must not be used to
28  * endorse or promote products derived from this software without
29  * prior written permission. For written permission, please
30  * contact org@kannel.org.
31  *
32  * 5. Products derived from this software may not be called "Kannel",
33  * nor may "Kannel" appear in their name, without prior written
34  * permission of the Kannel Group.
35  *
36  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39  * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
40  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
41  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
42  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
43  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
44  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
45  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
46  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
47  * ====================================================================
48  *
49  * This software consists of voluntary contributions made by many
50  * individuals on behalf of the Kannel Group. For more information on
51  * the Kannel Group, please see <http://www.kannel.org/>.
52  *
53  * Portions of this software are based upon software originally written at
54  * WapIT Ltd., Helsinki, Finland for the Kannel project.
55  */
56 
57 /* Driver for CIMD 2 SMS centres.
58  * Copyright 2000 WapIT Oy Ltd.
59  * Author: Richard Braakman
60  *
61  * Upgrade to SMSCConn API: 2002 Kalle Marjola / 2003 Angel Fradejas
62  */
63 
64 /* TODO: Check checksums on incoming packets */
65 /* TODO: Leading or trailing spaces are not allowed on parameters
66  * "user identity" and "password". Check this. */
67 /* TODO: Try to use the "More messages to send" flag */
68 
69 /* This code is based on the CIMD 2 spec, version 2-0 en.
70  * All USSD-specific parts have been left out, since we only want to
71  * communicate with SMSC's.
72  *
73  * I found one contradiction in the spec:
74  *
75  * - The definition of Integer parameters specifies decimal digits only,
76  * but at least one Integer parameter (Validity Period Relative) can
77  * be negative. I assume that this means a leading - is valid.
78  */
79 
80 #include <ctype.h>
81 #include <time.h>
82 #include <errno.h>
83 #include <limits.h>
84 #include <string.h>
85 
86 #include <unistd.h>
87 
88 #include "gwlib/gwlib.h"
89 #include "smscconn.h"
90 #include "smscconn_p.h"
91 #include "bb_smscconn_cb.h"
92 
93 #include "shared.h"
94 #include "sms.h"
95 #include "dlr.h"
96 
97 
98 typedef struct privdata {
101  Octstr *host;
102  long port;
103  long our_port;
104  long keepalive;
106  int no_dlr;
107 
108  int socket;
109  int send_seq;
111 
114 
115  time_t next_ping;
116 
120  int quitting;
121  List *stopped; /* list-trick for suspend/isolate */
122 
123 } PrivData;
124 
125 
126 
127 /* Microseconds before giving up on a request */
128 #define RESPONSE_TIMEOUT (60 * 1000000)
129 
130 /* Textual names for the operation codes defined by the CIMD 2 spec. */
131 /* If you make changes here, also change the operation table. */
132 enum {
133  /* Requests from client */
134  LOGIN = 1,
135  LOGOUT = 2,
140  SET_REQ = 8,
141  GET_REQ = 9,
142 
143  /* Requests from server */
146 
147  /* Requests from either */
148  ALIVE = 40,
149 
150  /* Not a request; add to any request to make it a response */
151  RESPONSE = 50,
152 
153  /* Responses not related to requests */
155  NACK = 99
156 };
157 
158 /* Textual names for the parameters defined by the CIMD 2 spec. */
159 /* If you make changes here, also change the parameter table. */
160 enum {
193  P_MC_TIME = 501,
196 };
197 
198 /***************************************************************************/
199 /* Table of properties of the parameters defined by CIMD 2, and some */
200 /* functions to look up fields. */
201 /***************************************************************************/
202 
203 /* Parameter types, internal. CIMD 2 spec considers P_TIME to be "Integer"
204  * and P_SMS to be "User Data". */
206 
207 /* Information about the parameters defined by the CIMD 2 spec.
208  * Used for warning about invalid incoming messages, and for validating
209  * outgoing messages. */
210 static const struct
211 {
212  char *name;
213  int number;
214  int maxlen;
215  int type; /* P_ values */
216  int minval, maxval; /* For P_INT */
217 }
218 parameters[] = {
219  { "user identity", P_USER_IDENTITY, 32, P_STRING },
220  { "password", P_PASSWORD, 32, P_STRING },
221  { "destination address", P_DESTINATION_ADDRESS, 20, P_ADDRESS },
222  { "originating address", P_ORIGINATING_ADDRESS, 20, P_ADDRESS },
223  /* IMSI is International Mobile Subscriber Identity number */
224  { "originating IMSI", P_ORIGINATING_IMSI, 20, P_ADDRESS },
225  { "alphanumeric originating address", P_ALPHANUMERIC_ORIGINATING_ADDRESS, 11, P_STRING },
226  { "originated visited MSC", P_ORIGINATED_VISITED_MSC, 20, P_ADDRESS },
227  { "data coding scheme", P_DATA_CODING_SCHEME, 3, P_INT, 0, 255 },
228  { "user data header", P_USER_DATA_HEADER, 280, P_HEX },
229  { "user data", P_USER_DATA, 480, P_SMS },
230  { "user data binary", P_USER_DATA_BINARY, 280, P_HEX },
231  { "more messages to send", P_MORE_MESSAGES_TO_SEND, 1, P_INT, 0, 1 },
232  { "validity period relative", P_VALIDITY_PERIOD_RELATIVE, 3, P_INT, -1, 255 },
233  { "validity period absolute", P_VALIDITY_PERIOD_ABSOLUTE, 12, P_TIME },
234  { "protocol identifier", P_PROTOCOL_IDENTIFIER, 3, P_INT, 0, 255 },
235  { "first delivery time relative", P_FIRST_DELIVERY_TIME_RELATIVE, 3, P_INT, -1, 255 },
236  { "first delivery time absolute", P_FIRST_DELIVERY_TIME_ABSOLUTE, 12, P_TIME },
237  { "reply path", P_REPLY_PATH, 1, P_INT, 0, 1 },
238  { "status report request", P_STATUS_REPORT_REQUEST, 2, P_INT, 0, 63 },
239  { "cancel enabled", P_CANCEL_ENABLED, 1, P_INT, 0, 1 },
240  { "cancel mode", P_CANCEL_MODE, 1, P_INT, 0, 2 },
241  { "service centre timestamp", P_MC_TIMESTAMP, 12, P_TIME },
242  { "status code", P_STATUS_CODE, 2, P_INT, 0, 9 },
243  { "status error code", P_STATUS_ERROR_CODE, 3, P_INT, 0, 999 },
244  { "discharge time", P_DISCHARGE_TIME, 12, P_TIME },
245  { "tariff class", P_TARIFF_CLASS, 2, P_INT, 0, 99 },
246  { "service description", P_SERVICE_DESCRIPTION, 2, P_INT, 0, 9 },
247  { "message count", P_MESSAGE_COUNT, 3, P_INT, 0, 999 },
248  { "priority", P_PRIORITY, 1, P_INT, 1, 9 },
249  { "delivery request mode", P_DELIVERY_REQUEST_MODE, 1, P_INT, 0, 2 },
250  { "service center address", P_SERVICE_CENTER_ADDRESS, 20, P_ADDRESS },
251  { "get parameter", P_GET_PARAMETER, 3, P_INT, 501, 999 },
252  { "MC time", P_MC_TIME, 12, P_TIME },
253  { "error code", P_ERROR_CODE, 3, P_INT, 0, 999 },
254  { "error text", P_ERROR_TEXT, 64, P_STRING },
255  { NULL }
256 };
257 
258 /* Return the index in the parameters array for this parameter id.
259  * Return -1 if it is not found. */
260 static int parm_index(int parmno)
261 {
262  int i;
263 
264  for (i = 0; parameters[i].name != NULL; i++) {
265  if (parameters[i].number == parmno)
266  return i;
267  }
268 
269  return -1;
270 }
271 
272 #ifndef NO_GWASSERT
273 /* Return the type of this parameter id. Return -1 if the id is unknown. */
274 static int parm_type(int parmno)
275 {
276  int i = parm_index(parmno);
277 
278  if (i < 0)
279  return -1;
280 
281  return parameters[i].type;
282 }
283 #endif
284 
285 /* Return the max length for this parameter id.
286  * Return -1 if the id is unknown. */
287 static int parm_maxlen(int parmno)
288 {
289  int i = parm_index(parmno);
290 
291  if (i < 0)
292  return -1;
293 
294  return parameters[i].maxlen;
295 }
296 
297 static const char *parm_name(int parmno)
298 {
299  int i = parm_index(parmno);
300 
301  if (i < 0)
302  return NULL;
303 
304  return parameters[i].name;
305 }
306 
307 #ifndef NO_GWASSERT
308 /* Return 1 if the value for this (Integer) parameter is in range.
309  * Return 0 otherwise. Return -1 if the parameter was not found. */
310 static int parm_in_range(int parmno, long value)
311 {
312  int i;
313 
314  i = parm_index(parmno);
315 
316  if (i < 0)
317  return -1;
318 
319  return (value >= parameters[i].minval && value <= parameters[i].maxval);
320 }
321 #endif
322 
323 /* Helper function to check P_ADDRESS type */
324 static int isphonedigit(int c)
325 {
326  return isdigit(c) || c == '+' || c == '-';
327 }
328 
329 static int parm_valid_address(Octstr *value)
330 {
331  return octstr_check_range(value, 0, octstr_len(value), isphonedigit);
332 }
333 
334 /***************************************************************************/
335 /* Some functions to look up information about operation codes */
336 /***************************************************************************/
337 
338 static int operation_find(int operation);
339 static Octstr *operation_name(int operation);
340 static int operation_can_send(int operation);
341 static int operation_can_receive(int operation);
342 
343 static const struct
344 {
345  char *name;
346  int code;
347  int can_send;
349 }
350 operations[] = {
351  { "Login", LOGIN, 1, 0 },
352  { "Logout", LOGOUT, 1, 0 },
353  { "Submit message", SUBMIT_MESSAGE, 1, 0 },
354  { "Enquire message status", ENQUIRE_MESSAGE_STATUS, 1, 0 },
355  { "Delivery request", DELIVERY_REQUEST, 1, 0 },
356  { "Cancel message", CANCEL_MESSAGE, 1, 0 },
357  { "Set parameter", SET_REQ, 1, 0 },
358  { "Get parameter", GET_REQ, 1, 0 },
359 
360  { "Deliver message", DELIVER_MESSAGE, 0, 1 },
361  { "Deliver status report", DELIVER_STATUS_REPORT, 0, 1 },
362 
363  { "Alive", ALIVE, 1, 1 },
364 
365  { "NACK", NACK, 1, 1 },
366  { "General error response", GENERAL_ERROR_RESPONSE, 0, 1 },
367 
368  { NULL, 0, 0, 0 }
369 };
370 
371 static int operation_find(int operation)
372 {
373  int i;
374 
375  for (i = 0; operations[i].name != NULL; i++) {
376  if (operations[i].code == operation)
377  return i;
378  }
379 
380  return -1;
381 }
382 
383 /* Return a human-readable representation of this operation code */
384 static Octstr *operation_name(int operation)
385 {
386  int i;
387 
388  i = operation_find(operation);
389  if (i >= 0)
390  return octstr_create(operations[i].name);
391 
392  if (operation >= RESPONSE) {
393  i = operation_find(operation - RESPONSE);
394  if (i >= 0) {
396  octstr_append_cstr(name, " response");
397  return name;
398  }
399  }
400 
401  /* Put the operation number here when we have octstr_format */
402  return octstr_create("(unknown)");
403 }
404 
405 /* Return true if a CIMD2 client may send this operation */
406 static int operation_can_send(int operation)
407 {
408  int i = operation_find(operation);
409 
410  if (i >= 0)
411  return operations[i].can_send;
412 
413  /* If we can receive the request, then we can send the response. */
414  if (operation >= RESPONSE)
415  return operation_can_receive(operation - RESPONSE);
416 
417  return 0;
418 }
419 
420 
421 /* Return true if a CIMD2 server may send this operation */
422 static int operation_can_receive(int operation)
423 {
424  int i = operation_find(operation);
425 
426  if (i >= 0)
427  return operations[i].can_receive;
428 
429  /* If we can send the request, then we can receive the response. */
430  if (operation >= RESPONSE)
431  return operation_can_send(operation - RESPONSE);
432 
433  return 0;
434 }
435 
436 /***************************************************************************/
437 /* Packet encoding/decoding functions. They handle packets at the octet */
438 /* level, and know nothing of the network. */
439 /***************************************************************************/
440 
441 struct packet
442 {
443  /* operation and seq are -1 if their value could not be parsed */
445  int seq; /* Sequence number */
446  Octstr *data; /* Encoded packet */
447  /* CIMD 2 packet structure is so simple that packet information is
448  * stored as a valid encoded packet, and decoded as necessary.
449  * Exceptions: operation code and sequence number are also stored
450  * as ints for speed, and the checksum is not added until the packet
451  * is about to be sent. Since checksums are optional, the packet
452  * is still valid without a checksum.
453  *
454  * The sequence number is kept at 0 until it's time to actually
455  * send the packet, so that the send functions have control over
456  * the sequence numbers.
457  */
458 };
459 
460 /* These are the separators defined by the CIMD 2 spec */
461 #define STX 2 /* Start of packet */
462 #define ETX 3 /* End of packet */
463 #define TAB 9 /* End of parameter */
464 
465 /* The same separators, in string form */
466 #define STX_str "\02"
467 #define ETX_str "\03"
468 #define TAB_str "\011"
469 
470 /* A reminder that packets are created without a valid sequence number */
471 #define BOGUS_SEQUENCE 0
472 
473 static Msg *cimd2_accept_delivery_report_message(struct packet *request,
474  SMSCConn *conn);
475 /* Look for the STX OO:SSS TAB header defined by CIMD 2, where OO is the
476  * operation code in two decimals and SSS is the sequence number in three
477  * decimals. Leave the results in the proper fields of the packet.
478  * Try to make sense of headers that don't fit this pattern; validating
479  * the packet format is not our job. */
480 static void packet_parse_header(struct packet *packet)
481 {
482  int pos;
483  long number;
484 
485  /* Set default values, in case we can't parse the fields */
486  packet->operation = -1;
487  packet->seq = -1;
488 
489  pos = octstr_parse_long(&number, packet->data, 1, 10);
490  if (pos < 0)
491  return;
493 
494  if (octstr_get_char(packet->data, pos++) != ':')
495  return;
496 
497  pos = octstr_parse_long(&number, packet->data, pos, 10);
498  if (pos < 0)
499  return;
500  packet->seq = number;
501 }
502 
503 
504 /* Accept an Octstr containing one packet, build a struct packet around
505  * it, and return that struct. The Octstr is stored in the struct.
506  * No error checking is done here yet. */
507 static struct packet *packet_parse(Octstr *packet_data)
508 {
509  struct packet *packet;
510 
511  packet = gw_malloc(sizeof(*packet));
512  packet->data = packet_data;
513 
514  /* Fill in packet->operation and packet->seq */
516 
517  return packet;
518 }
519 
520 /* Deallocate this packet */
521 static void packet_destroy(struct packet *packet)
522 {
523  if (packet != NULL) {
525  gw_free(packet);
526  }
527 }
528 
529 /* Find the first packet in "in", delete it from "in", and return it as
530  * a struct. Return NULL if "in" contains no packet. Always delete
531  * leading non-packet data from "in". (The CIMD 2 spec says we should
532  * ignore any data between the packet markers). */
533 static struct packet *packet_extract(Octstr *in, SMSCConn *conn)
534 {
535  int stx, etx;
536  Octstr *packet;
537 
538  /* Find STX, and delete everything up to it */
539  stx = octstr_search_char(in, STX, 0);
540  if (stx < 0) {
541  octstr_delete(in, 0, octstr_len(in));
542  return NULL;
543  } else {
544  octstr_delete(in, 0, stx);
545  }
546 
547  /* STX is now in position 0. Find ETX. */
548  etx = octstr_search_char(in, ETX, 1);
549  if (etx < 0)
550  return NULL;
551 
552  /* What shall we do with STX data... STX data... ETX?
553  * Either skip to the second STX, or assume an ETX marker before
554  * the STX. Doing the latter has a chance of succeeding, and
555  * will at least allow good logging of the error. */
556  stx = octstr_search_char(in, STX, 1);
557  if (stx >= 0 && stx < etx) {
558  warning(0, "CIMD2[%s]: packet without end marker",
559  octstr_get_cstr(conn->id));
560  packet = octstr_copy(in, 0, stx);
561  octstr_delete(in, 0, stx);
563  } else {
564  /* Normal case. Copy packet, and cut it from the source. */
565  packet = octstr_copy(in, 0, etx + 1);
566  octstr_delete(in, 0, etx + 1);
567  }
568 
569  return packet_parse(packet);
570 }
571 
572 /* The get_parm functions always return the first parameter with the
573  * correct id. There is only one case where the spec allows multiple
574  * parameters with the same id, and that is when an SMS has multiple
575  * destination addresses. We only support one destination address anyway. */
576 
577 /* Look for the first parameter with id 'parmno' and return its value.
578  * Return NULL if the parameter was not found. */
579 static Octstr *packet_get_parm(struct packet *packet, int parmno)
580 {
581  long pos, next;
582  long valuepos;
583  long number;
584 
585  gw_assert(packet != NULL);
586  pos = octstr_search_char(packet->data, TAB, 0);
587  if (pos < 0)
588  return NULL; /* Bad packet, nothing we can do */
589 
590  /* Parameters have a tab on each end. If we don't find the
591  * closing tab, we're at the checksum, so we stop. */
592  for ( ;
593  (next = octstr_search_char(packet->data, TAB, pos + 1)) >= 0;
594  pos = next) {
595  if (octstr_parse_long(&number, packet->data, pos + 1, 10) < 0)
596  continue;
597  if (number != parmno)
598  continue;
599  valuepos = octstr_search_char(packet->data, ':', pos + 1);
600  if (valuepos < 0)
601  continue; /* badly formatted parm */
602  valuepos++; /* skip the ':' */
603 
604  /* Found the right parameter */
605  return octstr_copy(packet->data, valuepos, next - valuepos);
606  }
607 
608  return NULL;
609 }
610 
611 
612 /* Look for an Integer parameter with id 'parmno' in the packet and
613  * return its value. Return INT_MIN if the parameter was not found.
614  * (Unfortunately, -1 is a valid parameter value for at least one
615  * parameter.) */
616 static long packet_get_int_parm(struct packet *packet, int parmno)
617 {
618  Octstr *valuestr = NULL;
619  long value;
620 
621  /* Our code should never even try a bad parameter access. */
622  gw_assert(parm_type(parmno) == P_INT);
623 
624  valuestr = packet_get_parm(packet, parmno);
625  if (!valuestr)
626  goto error;
627 
628  if (octstr_parse_long(&value, valuestr, 0, 10) < 0)
629  goto error;
630 
631  octstr_destroy(valuestr);
632  return value;
633 
634 error:
635  octstr_destroy(valuestr);
636  return INT_MIN;
637 }
638 
639 /* Look for a String parameter with id 'parmno' in the packet and
640  * return its value. Return NULL if the parameter was not found.
641  * No translations are done on the value. */
642 static Octstr *packet_get_string_parm(struct packet *packet, int parmno)
643 {
644  /* Our code should never even try a bad parameter access. */
645  gw_assert(parm_type(parmno) == P_STRING);
646 
647  return packet_get_parm(packet, parmno);
648 }
649 
650 /* Look for an Address parameter with id 'parmno' in the packet and
651  * return its value. Return NULL if the parameter was not found.
652  * No translations are done on the value. */
653 static Octstr *packet_get_address_parm(struct packet *packet, int parmno)
654 {
655  /* Our code should never even try a bad parameter access. */
656  gw_assert(parm_type(parmno) == P_ADDRESS);
657 
658  return packet_get_parm(packet, parmno);
659 }
660 
661 /* Look for an SMS parameter with id 'parmno' in the packet and return its
662  * value. Return NULL if the parameter was not found. No translations
663  * are done on the value, so it will be in the ISO-Latin-1 character set
664  * with CIMD2-specific escapes. */
665 static Octstr *packet_get_sms_parm(struct packet *packet, int parmno)
666 {
667  /* Our code should never even try a bad parameter access. */
668  gw_assert(parm_type(parmno) == P_SMS);
669 
670  return packet_get_parm(packet, parmno);
671 }
672 
673 /* There is no packet_get_time_parm because the CIMD 2 timestamp
674  * format is useless. It's in the local time of the MC, with
675  * a 2-digit year and no DST information. We can do without.
676  */
677 
678 /* Look for a Hex parameter with id 'parmno' in the packet and return
679  * its value. Return NULL if the parameter was not found. The value
680  * is de-hexed. */
681 static Octstr *packet_get_hex_parm(struct packet *packet, int parmno)
682 {
683  Octstr *value = NULL;
684 
685  /* Our code should never even try a bad parameter access. */
686  gw_assert(parm_type(parmno) == P_HEX);
687 
688  value = packet_get_parm(packet, parmno);
689  if (!value)
690  goto error;
691 
692  if (octstr_hex_to_binary(value) < 0)
693  goto error;
694 
695  return value;
696 
697 error:
698  octstr_destroy(value);
699  return NULL;
700 }
701 
702 
703 /* Check if the header is according to CIMD 2 spec, generating log
704  * entries as necessary. Return -1 if anything was wrong, otherwise 0. */
705 static int packet_check_header(struct packet *packet, SMSCConn *conn)
706 {
707  Octstr *data;
708 
709  gw_assert(packet != NULL);
710  data = packet->data;
711 
712  /* The header must have a two-digit operation code, a colon,
713  * and a three-digit sequence number, followed by a tab.
714  * (CIMD2, 3.1) */
715  if (octstr_len(data) < 8 ||
717  octstr_get_char(data, 3) != ':' ||
719  octstr_get_char(data, 7) != TAB) {
720  warning(0, "CIMD2[%s]: packet header in wrong format",
721  octstr_get_cstr(conn->id));
722  return -1;
723  }
724 
725  return 0;
726 }
727 
728 static int packet_check_parameter(struct packet *packet, long pos, long len, SMSCConn *conn)
729 {
730  Octstr *data;
731  long parm;
732  long dpos, dlen;
733  int negative;
734  long value;
735  int i;
736  int errors = 0;
737 
738  gw_assert(packet != NULL);
739  data = packet->data;
740 
741  /* The parameter header should be TAB, followed by a three-digit
742  * parameter number, a colon, and the data. We already know about
743  * the tab. */
744 
745  if (len < 5 ||
746  !octstr_check_range(data, pos + 1, 3, gw_isdigit) ||
747  octstr_get_char(data, pos + 4) != ':') {
748  warning(0, "CIMD2[%s]: parameter at offset %ld in wrong format",
749  octstr_get_cstr(conn->id),
750  pos);
751  errors++;
752  }
753 
754  /* If we can't parse a parameter number, there's nothing more
755  * that we can check. */
756  dpos = octstr_parse_long(&parm, data, pos + 1, 10);
757  if (dpos < 0)
758  return -1;
759  if (octstr_get_char(data, dpos) == ':')
760  dpos++;
761  dlen = len - (dpos - pos);
762  /* dlen can not go negative because octstr_parse_long must have
763  * been stopped by the TAB at the end of the parameter data. */
764  gw_assert(dlen >= 0);
765 
766  i = parm_index(parm);
767 
768  if (i < 0) {
769  warning(0, "CIMD2[%s]: packet contains unknown parameter %ld",
770  octstr_get_cstr(conn->id),
771  parm);
772  return -1;
773  }
774 
775  if (dlen > parameters[i].maxlen) {
776  warning(0, "CIMD2[%s]: packet has '%s' parameter with length %ld, spec says max %d",
777  octstr_get_cstr(conn->id),
778  parameters[i].name, len, parameters[i].maxlen);
779  errors++;
780  }
781 
782  switch (parameters[i].type) {
783  case P_INT:
784  /* Allow a leading - */
785  negative = (octstr_get_char(data, dpos) == '-');
786  if (!octstr_check_range(data, dpos + negative,
787  dlen - negative, gw_isdigit)) {
788  warning(0, "CIMD2[%s]: packet has '%s' parameter with non-integer contents",
789  octstr_get_cstr(conn->id),
790  parameters[i].name);
791  errors++;
792  }
793  if (octstr_parse_long(&value, data, dpos, 10) >= 0 &&
794  (value < parameters[i].minval || value > parameters[i].maxval)) {
795  warning(0, "CIMD2[%s]: packet has '%s' parameter out of range (value %ld, min %d, max %d)",
796  octstr_get_cstr(conn->id),
797  parameters[i].name, value,
798  parameters[i].minval, parameters[i].maxval);
799  errors++;
800  }
801  break;
802  case P_TIME:
803  if (!octstr_check_range(data, dpos, dlen, gw_isdigit)) {
804  warning(0, "CIMD2[%s]: packet has '%s' parameter with non-digit contents",
805  octstr_get_cstr(conn->id),
806  parameters[i].name);
807  errors++;
808  }
809  break;
810  case P_ADDRESS:
811  if (!octstr_check_range(data, dpos, dlen, isphonedigit)) {
812  warning(0, "CIMD2[%s]: packet has '%s' parameter with non phone number contents",
813  octstr_get_cstr(conn->id),
814  parameters[i].name);
815  errors++;
816  }
817  break;
818  case P_HEX:
819  if (!octstr_check_range(data, dpos, dlen, gw_isxdigit)) {
820  warning(0, "CIMD2[%s]: packet has '%s' parameter with non-hex contents",
821  octstr_get_cstr(conn->id),
822  parameters[i].name);
823  errors++;
824  }
825  if (dlen % 2 != 0) {
826  warning(0, "CIMD2[%s]: packet has odd-length '%s' parameter",
827  octstr_get_cstr(conn->id),
828  parameters[i].name);
829  errors++;
830  }
831  break;
832  case P_SMS:
833  case P_STRING: /* nothing to check */
834  break;
835  }
836 
837  if (errors > 0)
838  return -1;
839  return 0;
840 }
841 
842 
843 /* Check the packet against the CIMD 2 spec, generating log entries as
844  * necessary. Return -1 if anything was wrong, otherwise 0. */
845 /* TODO: Check if parameters found actually belong in the packet type */
846 static int packet_check(struct packet *packet, SMSCConn *conn)
847 {
848  int errors = 0;
849  long pos, next;
850  Octstr *data;
851 
852  gw_assert(packet != NULL);
853  data = packet->data;
854 
855  if (octstr_search_char(data, 0, 0) >= 0) {
856  /* CIMD2 spec does not allow NUL bytes in a packet */
857  warning(0, "CIMD2[%s]: packet contains NULs",
858  octstr_get_cstr(conn->id));
859  errors++;
860  }
861 
862  /* Assume the packet starts with STX and ends with ETX,
863  * because we parsed it that way in the first place. */
864 
865  errors += (packet_check_header(packet,conn) < 0);
866 
867  /* Parameters are separated by tabs. After the last parameter
868  * there is a tab, an optional two-digit checksum, and the ETX.
869  * Check each parameter in turn, by skipping from tab to tab.
870  */
871  /* Start at the first tab, wherever it is, so that we can still
872  * check parameters if the header was weird. */
873  pos = octstr_search_char(data, TAB, 0);
874  for ( ; pos >= 0; pos = next) {
875  next = octstr_search_char(data, TAB, pos + 1);
876  if (next >= 0) {
877  errors += (packet_check_parameter(packet, pos, next - pos, conn) < 0);
878  } else {
879  /* Check if the checksum has the right format. Don't
880  * check the sum itself here, that will be done in a
881  * separate call later. */
882  /* There are two valid formats: TAB ETX (no checksum)
883  * and TAB digit digit ETX. We already know the TAB
884  * and the ETX are there. */
885  if (!(octstr_len(data) - pos == 2 ||
886  (octstr_len(data) - pos == 4 &&
887  octstr_check_range(data, pos + 1, 2, gw_isxdigit)))) {
888  warning(0, "CIMD2[%s]: packet checksum in wrong format",
889  octstr_get_cstr(conn->id));
890  errors++;
891  }
892  }
893  }
894 
895 
896  if (errors > 0) {
897  octstr_dump(packet->data, 0);
898  return -1;
899  }
900 
901  return 0;
902 }
903 
904 static void packet_check_can_receive(struct packet *packet, SMSCConn *conn)
905 {
906  gw_assert(packet != NULL);
907 
910  warning(0, "CIMD2[%s]: SMSC sent us %s request",
911  octstr_get_cstr(conn->id),
914  }
915 }
916 
917 /* Table of known error codes */
918 static struct
919 {
920  int code;
921  char *text;
922 }
923 cimd2_errors[] = {
924  { 0, "No error" },
925  { 1, "Unexpected operation" },
926  { 2, "Syntax error" },
927  { 3, "Unsupported parameter error" },
928  { 4, "Connection to message center lost" },
929  { 5, "No response from message center" },
930  { 6, "General system error" },
931  { 7, "Cannot find information" },
932  { 8, "Parameter formatting error" },
933  { 9, "Requested operation failed" },
934  /* LOGIN error codes */
935  { 100, "Invalid login" },
936  { 101, "Incorrect access type" },
937  { 102, "Too many users with this login id" },
938  { 103, "Login refused by message center" },
939  /* SUBMIT MESSAGE error codes */
940  { 300, "Incorrect destination address" },
941  { 301, "Incorrect number of destination addresses" },
942  { 302, "Syntax error in user data parameter" },
943  { 303, "Incorrect bin/head/normal user data parameter combination" },
944  { 304, "Incorrect data coding scheme parameter usage" },
945  { 305, "Incorrect validity period parameters usage" },
946  { 306, "Incorrect originator address usage" },
947  { 307, "Incorrect pid paramterer usage" },
948  { 308, "Incorrect first delivery parameter usage" },
949  { 309, "Incorrect reply path usage" },
950  { 310, "Incorrect status report request parameter usage" },
951  { 311, "Incorrect cancel enabled parameter usage" },
952  { 312, "Incorrect priority parameter usage" },
953  { 313, "Incorrect tariff class parameter usage" },
954  { 314, "Incorrect service description parameter usage" },
955  { 315, "Incorrect transport type parameter usage" },
956  { 316, "Incorrect message type parameter usage" },
957  { 318, "Incorrect mms parameter usage" },
958  { 319, "Incorrect operation timer parameter usage" },
959  /* ENQUIRE MESSAGE STATUS error codes */
960  { 400, "Incorrect address parameter usage" },
961  { 401, "Incorrect scts parameter usage" },
962  /* DELIVERY REQUEST error codes */
963  { 500, "Incorrect scts parameter usage" },
964  { 501, "Incorrect mode parameter usage" },
965  { 502, "Incorrect parameter combination" },
966  /* CANCEL MESSAGE error codes */
967  { 600, "Incorrect scts parameter usage" },
968  { 601, "Incorrect address parameter usage" },
969  { 602, "Incorrect mode parameter usage" },
970  { 603, "Incorrect parameter combination" },
971  /* SET error codes */
972  { 800, "Changing password failed" },
973  { 801, "Changing password not allowed" },
974  /* GET error codes */
975  { 900, "Unsupported item requested" },
976  { -1, NULL }
977 };
978 
979 static int packet_display_error(struct packet *packet, SMSCConn *conn)
980 {
981  int code;
982  Octstr *text = NULL;
983  Octstr *opname = NULL;
984 
987 
988  if (code <= 0) {
990  return 0;
991  }
992 
993  if (text == NULL) {
994  /* No error text. Try to find it in the table. */
995  int i;
996  for (i = 0; cimd2_errors[i].text != NULL; i++) {
997  if (cimd2_errors[i].code == code) {
999  break;
1000  }
1001  }
1002  }
1003 
1004  if (text == NULL) {
1005  /* Still no error text. Make one up. */
1006  text = octstr_create("Unknown error");
1007  }
1008 
1009  opname = operation_name(packet->operation);
1010  error(0, "CIMD2[%s]: %s contained error message:",
1011  octstr_get_cstr(conn->id),
1012  octstr_get_cstr(opname));
1013  error(0, "code %03d: %s", code, octstr_get_cstr(text));
1014  octstr_destroy(opname);
1016  return code;
1017 }
1018 
1019 /* Table of special combinations, for convert_gsm_to_latin1. */
1020 /* Each cimd1, cimd2 pair is mapped to a character in the GSM default
1021  * character set. */
1022 static const struct
1023 {
1024  unsigned char cimd1, cimd2;
1025  unsigned char gsm;
1026 }
1027 cimd_combinations[] = {
1028  { 'O', 'a', 0 }, /* @ */
1029  { 'L', '-', 1 }, /* Pounds sterling */
1030  { 'Y', '-', 3 }, /* Yen */
1031  { 'e', '`', 4 }, /* egrave */
1032  { 'e', '\'', 5 }, /* eacute */
1033  { 'u', '`', 6 }, /* ugrave */
1034  { 'i', '`', 7 }, /* igrave */
1035  { 'o', '`', 8 }, /* ograve */
1036  { 'C', ',', 9 }, /* C cedilla */
1037  { 'O', '/', 11 }, /* Oslash */
1038  { 'o', '/', 12 }, /* oslash */
1039  { 'A', '*', 14 }, /* Aring */
1040  { 'a', '*', 15 }, /* aring */
1041  { 'g', 'd', 16 }, /* greek delta */
1042  { '-', '-', 17 }, /* underscore */
1043  { 'g', 'f', 18 }, /* greek phi */
1044  { 'g', 'g', 19 }, /* greek gamma */
1045  { 'g', 'l', 20 }, /* greek lambda */
1046  { 'g', 'o', 21 }, /* greek omega */
1047  { 'g', 'p', 22 }, /* greek pi */
1048  { 'g', 'i', 23 }, /* greek psi */
1049  { 'g', 's', 24 }, /* greek sigma */
1050  { 'g', 't', 25 }, /* greek theta */
1051  { 'g', 'x', 26 }, /* greek xi */
1052  { 'X', 'X', 27 }, /* escape */
1053  { 'A', 'E', 28 }, /* AE ligature */
1054  { 'a', 'e', 29 }, /* ae ligature */
1055  { 's', 's', 30 }, /* german double s */
1056  { 'E', '\'', 31 }, /* Eacute */
1057  { 'q', 'q', '"' },
1058  { 'o', 'x', 36 }, /* international currency symbol */
1059  { '!', '!', 64 }, /* inverted ! */
1060  { 'A', '"', 91 }, /* Adieresis */
1061  { 'O', '"', 92 }, /* Odieresis */
1062  { 'N', '~', 93 }, /* N tilde */
1063  { 'U', '"', 94 }, /* Udieresis */
1064  { 's', 'o', 95 }, /* section mark */
1065  { '?', '?', 96 }, /* inverted ? */
1066  { 'a', '"', 123 }, /* adieresis */
1067  { 'o', '"', 124 }, /* odieresis */
1068  { 'n', '~', 125 }, /* n tilde */
1069  { 'u', '"', 126 }, /* udieresis */
1070  { 'a', '`', 127 }, /* agrave */
1071  { 0, 0, 0 }
1072 };
1073 
1074 
1075 /* Convert text in the CIMD2 User Data format to the GSM default
1076  * character set.
1077  * CIMD2 allows 8-bit characters in this format; they map directly
1078  * to the corresponding ISO-8859-1 characters. Since we are heading
1079  * toward that character set in the end, we don't bother converting
1080  * those to GSM. */
1082 {
1083  long pos, len;
1084  int cimd1, cimd2;
1085  int c;
1086  int i;
1087 
1088  /* CIMD2 uses four single-character mappings that do not map
1089  * to themselves:
1090  * '@' from 64 to 0, '$' from 36 to 2, ']' from 93 to 14 (A-ring),
1091  * and '}' from 125 to 15 (a-ring).
1092  * Other than those, we only have to worry about the escape
1093  * sequences introduced by _ (underscore).
1094  */
1095 
1096  len = octstr_len(text);
1097  for (pos = 0; pos < len; pos++) {
1098  c = octstr_get_char(text, pos);
1099  if (c == '@')
1100  octstr_set_char(text, pos, 0);
1101  else if (c == '$')
1102  octstr_set_char(text, pos, 2);
1103  else if (c == ']')
1104  octstr_set_char(text, pos, 14);
1105  else if (c == '}')
1106  octstr_set_char(text, pos, 15);
1107  else if (c == '_' && pos + 2 < len) {
1108  cimd1 = octstr_get_char(text, pos + 1);
1109  cimd2 = octstr_get_char(text, pos + 2);
1110  for (i = 0; cimd_combinations[i].cimd1 != 0; i++) {
1111  if (cimd_combinations[i].cimd1 == cimd1 &&
1113  break;
1114  }
1115  if (cimd_combinations[i].cimd1 == 0)
1116  warning(0, "CIMD2[%s]: Encountered unknown "
1117  "escape code _%c%c, ignoring.",
1118  octstr_get_cstr(conn->id),
1119  cimd1, cimd2);
1120  else {
1121  octstr_delete(text, pos, 2);
1123  len = octstr_len(text);
1124  }
1125  }
1126  }
1127 }
1128 
1129 
1130 /* Convert text in the GSM default character set to the CIMD2 User Data
1131  * format, which is a representation of the GSM default character set
1132  * in the lower 7 bits of ISO-8859-1. (8-bit characters are also
1133  * allowed, but it's just as easy not to use them.) */
1135 {
1136  long pos, len;
1137 
1138  len = octstr_len(text);
1139  for (pos = 0; pos < len; pos++) {
1140  int c, i;
1141 
1142  c = octstr_get_char(text, pos);
1143  /* If c is not in the GSM alphabet at this point,
1144  * the caller did something badly wrong. */
1145  gw_assert(c >= 0);
1146  gw_assert(c < 128);
1147 
1148  for (i = 0; cimd_combinations[i].cimd1 != 0; i++) {
1149  if (cimd_combinations[i].gsm == c)
1150  break;
1151  }
1152 
1153  if (cimd_combinations[i].gsm == c) {
1154  /* Escape sequence */
1155  octstr_insert_data(text, pos, "_ ", 2);
1156  pos += 2;
1157  len += 2;
1160  } else if (c == 2) {
1161  /* The dollar sign is the only GSM character that
1162  * does not have a CIMD escape sequence and does not
1163  * map to itself. */
1164  octstr_set_char(text, pos, '$');
1165  }
1166  }
1167 }
1168 
1169 
1170 /***************************************************************************/
1171 /* Packet encoding functions. They do not allow the creation of invalid */
1172 /* CIMD 2 packets. */
1173 /***************************************************************************/
1174 
1175 /* Build a new packet struct with this operation code and sequence number. */
1176 static struct packet *packet_create(int operation, int seq)
1177 {
1178  struct packet *packet;
1179  char minpacket[sizeof("sOO:SSSte")];
1180 
1181  packet = gw_malloc(sizeof(*packet));
1183  packet->seq = seq;
1184  sprintf(minpacket, STX_str "%02d:%03d" TAB_str ETX_str, operation, seq);
1185  packet->data = octstr_create(minpacket);
1186 
1187  return packet;
1188 }
1189 
1190 /* Add a parameter to the end of packet */
1191 static void packet_add_parm(struct packet *packet, int parmtype,
1192  int parmno, Octstr *value, SMSCConn *conn)
1193 {
1194  char parmh[sizeof("tPPP:")];
1195  long position;
1196  long len;
1197  int copied = 0;
1198 
1199  len = octstr_len(value);
1200 
1201  gw_assert(packet != NULL);
1202  gw_assert(parm_type(parmno) == parmtype);
1203 
1204  if (len > parm_maxlen(parmno)) {
1205  warning(0, "CIMD2[%s]: %s parameter too long, truncating from "
1206  "%ld to %ld characters",
1207  octstr_get_cstr(conn->id),
1208  parm_name(parmno),
1209  len,
1210  (long) parm_maxlen(parmno));
1211  value = octstr_copy(value, 0, parm_maxlen(parmno));
1212  copied = 1;
1213  }
1214 
1215  /* There's a TAB and ETX at the end; insert it before those.
1216  * The new parameter will come with a new starting TAB. */
1217  position = octstr_len(packet->data) - 2;
1218 
1219  sprintf(parmh, TAB_str "%03d:", parmno);
1220  octstr_insert_data(packet->data, position, parmh, strlen(parmh));
1221  octstr_insert(packet->data, value, position + strlen(parmh));
1222  if (copied)
1223  octstr_destroy(value);
1224 }
1225 
1226 /* Add a String parameter to the packet */
1227 static void packet_add_string_parm(struct packet *packet, int parmno, Octstr *value, SMSCConn *conn)
1228 {
1229  packet_add_parm(packet, P_STRING, parmno, value, conn);
1230 }
1231 
1232 /* Add an Address parameter to the packet */
1233 static void packet_add_address_parm(struct packet *packet, int parmno, Octstr *value, SMSCConn *conn)
1234 {
1236  packet_add_parm(packet, P_ADDRESS, parmno, value, conn);
1237 }
1238 
1239 /* Add an SMS parameter to the packet. The caller is expected to have done
1240  * the translation to the GSM character set already. */
1241 static void packet_add_sms_parm(struct packet *packet, int parmno, Octstr *value, SMSCConn *conn)
1242 {
1243  packet_add_parm(packet, P_SMS, parmno, value, conn);
1244 }
1245 
1246 /* There is no function for adding a Time parameter to the packet, because
1247  * the format makes Time parameters useless for us. If you find that you
1248  * need to use them, then also add code for querying the SMS center timestamp
1249  * and using that for synchronization. And beware of DST changes. */
1250 
1251 /* Add a Hexadecimal parameter to the packet */
1252 static void packet_add_hex_parm(struct packet *packet, int parmno, Octstr *value, SMSCConn *conn)
1253 {
1254  value = octstr_duplicate(value);
1255  octstr_binary_to_hex(value, 1); /* 1 for uppercase hex, i.e. A .. F */
1256  packet_add_parm(packet, P_HEX, parmno, value, conn);
1257  octstr_destroy(value);
1258 }
1259 
1260 /* Add an Integer parameter to the packet */
1261 static void packet_add_int_parm(struct packet *packet, int parmno, long value, SMSCConn *conn)
1262 {
1263  char buf[128];
1264  Octstr *valuestr;
1265 
1266  gw_assert(parm_in_range(parmno, value));
1267 
1268  sprintf(buf, "%ld", value);
1269  valuestr = octstr_create(buf);
1270  packet_add_parm(packet, P_INT, parmno, valuestr, conn);
1271  octstr_destroy(valuestr);
1272 }
1273 
1274 static void packet_set_checksum(struct packet *packet)
1275 {
1276  Octstr *data;
1277  int checksum;
1278  long pos, len;
1279  char buf[16];
1280 
1281  gw_assert(packet != NULL);
1282 
1283  data = packet->data;
1284  if (octstr_get_char(data, octstr_len(data) - 2) != TAB) {
1285  /* Packet already has checksum; kill it. */
1286  octstr_delete(data, octstr_len(data) - 3, 2);
1287  }
1288 
1290 
1291  /* Sum all the way up to the last TAB */
1292  checksum = 0;
1293  for (pos = 0, len = octstr_len(data); pos < len - 1; pos++) {
1294  checksum += octstr_get_char(data, pos);
1295  checksum &= 0xff;
1296  }
1297 
1298  sprintf(buf, "%02X", checksum);
1299  octstr_insert_data(data, len - 1, buf, 2);
1300 }
1301 
1302 static void packet_set_sequence(struct packet *packet, int seq)
1303 {
1304  char buf[16];
1305 
1306  gw_assert(packet != NULL);
1307  gw_assert(seq >= 0);
1308  gw_assert(seq < 256);
1309 
1310  sprintf(buf, "%03d", seq);
1311 
1312  /* Start at 4 to skip the <STX> ZZ: part of the header. */
1313  octstr_set_char(packet->data, 4, buf[0]);
1314  octstr_set_char(packet->data, 5, buf[1]);
1315  octstr_set_char(packet->data, 6, buf[2]);
1316  packet->seq = seq;
1317 }
1318 
1319 static struct packet *packet_encode_message(Msg *msg, Octstr *sender_prefix, SMSCConn *conn)
1320 {
1321  struct packet *packet;
1322  PrivData *pdata = conn->data;
1323  Octstr *text;
1324  int spaceleft;
1325  long truncated;
1326  int dcs = 0;
1327  int setvalidity = 0;
1328 
1329  gw_assert(msg != NULL);
1330  gw_assert(msg->type == sms);
1331  gw_assert(msg->sms.receiver != NULL);
1332 
1333  dcs = fields_to_dcs(msg, (msg->sms.alt_dcs != -1 ?
1334  msg->sms.alt_dcs : conn->alt_dcs));
1335  if (msg->sms.sender == NULL)
1336  msg->sms.sender = octstr_create("");
1337 
1338  if (!parm_valid_address(msg->sms.receiver)) {
1339  warning(0, "CIMD2[%s]: non-digits in destination phone number '%s', discarded",
1340  octstr_get_cstr(conn->id),
1341  octstr_get_cstr(msg->sms.receiver));
1342  return NULL;
1343  }
1344 
1346 
1348 
1349  /* CIMD2 interprets the originating address as a sub-address to
1350  * our connection number (so if the connection is "400" and we
1351  * fill in "600" as the sender number, the user sees "400600").
1352  * Since we have no way to ask what this number is, it has to
1353  * be configured. */
1354 
1355  /* Quick and dirty check to see if we are using alphanumeric sender */
1356  if (parm_valid_address(msg->sms.sender)) {
1357  /* We are not, so send in the usual way */
1358  /* Speed up the default case */
1359  if (octstr_len(sender_prefix) == 0) {
1361  }
1362  else if (octstr_compare(sender_prefix, octstr_imm("never")) != 0) {
1363  if (octstr_ncompare(sender_prefix, msg->sms.sender,
1364  octstr_len(sender_prefix)) == 0) {
1365  Octstr *sender;
1366  sender = octstr_copy(msg->sms.sender,
1367  octstr_len(sender_prefix), octstr_len(msg->sms.sender));
1369  octstr_destroy(sender);
1370  } else {
1371  warning(0, "CIMD2[%s]: Sending message with originating address <%s>, "
1372  "which does not start with the sender-prefix.",
1373  octstr_get_cstr(conn->id),
1374  octstr_get_cstr(msg->sms.sender));
1375  }
1376  }
1377  }
1378  else {
1379  /* The test above to check if sender was all digits failed, so assume we want alphanumeric sender */
1381  }
1382 
1383  /* Add the validity period if necessary. This sets the relative validity
1384  * period as this is the description of the "validity" parameter of the
1385  * sendsms interface.
1386  *
1387  * Convert from minutes to GSM 03.40 specification (section 9.2.3.12).
1388  * 0-143 = 0 to 12 hours in 5 minute increments.
1389  * 144-167 = 12hrs30min to 24hrs in 30 minute increments.
1390  * 168-196 = 2days to 30days in 1 day increments.
1391  * 197-255 = 5weeks to 63weeks in 1 week increments.
1392  *
1393  * This code was copied from smsc_at2.c.
1394  */
1395  if (msg->sms.validity != MSG_PARAM_UNDEFINED) {
1396  long val = (msg->sms.validity - time(NULL)) / 60;
1397  if (val > 635040)
1398  setvalidity = 255;
1399  if (val >= 50400 && val <= 635040)
1400  setvalidity = (val - 1) / 7 / 24 / 60 + 192 + 1;
1401  if (val > 43200 && val < 50400)
1402  setvalidity = 197;
1403  if (val >= 2880 && val <= 43200)
1404  setvalidity = (val - 1) / 24 / 60 + 166 + 1;
1405  if (val > 1440 && val < 2880)
1406  setvalidity = 168;
1407  if (val >= 750 && val <= 1440)
1408  setvalidity = (val - 720 - 1) / 30 + 143 + 1;
1409  if (val > 720 && val < 750)
1410  setvalidity = 144;
1411  if (val >= 5 && val <= 720)
1412  setvalidity = (val - 1) / 5 - 1 + 1;
1413  if (val < 5)
1414  setvalidity = 0;
1415 
1417  }
1418 
1419  /* Explicitly ask not to get status reports.
1420  * If we do not do this, the server's default might be to
1421  * send status reports in some cases, and we don't do anything
1422  * with those reports anyway. */
1423  /* ask for the delivery reports if needed*/
1424 
1425  if (!pdata->no_dlr)
1426  if (DLR_IS_SUCCESS_OR_FAIL(msg->sms.dlr_mask))
1428  else
1430  else if( pdata->no_dlr && DLR_IS_SUCCESS_OR_FAIL(msg->sms.dlr_mask))
1431  warning(0, "CIMD2[%s]: dlr request make no sense while no-dlr set to true",
1432  octstr_get_cstr(conn->id));
1433 
1434  /* Turn off reply path as default.
1435  * This avoids phones automatically asking for a reply
1436  */
1437  if (msg->sms.rpi > 0)
1439  else
1441 
1442  /* Use binfo to set the tariff class */
1443  if (octstr_len(msg->sms.binfo))
1444  packet_add_parm(packet, P_INT, P_TARIFF_CLASS, msg->sms.binfo, conn);
1445 
1446  /* Set the protocol identifier if requested */
1447  if (msg->sms.pid > 0)
1449 
1450  /* If there are more messages to the same destination, then set the
1451  * More Messages to Send flag. This allow faster delivery of many messages
1452  * to the same destination
1453  */
1454  if (msg->sms.msg_left > 0)
1456  else
1458 
1459  truncated = 0;
1460 
1461  spaceleft = 140;
1462  if (octstr_len(msg->sms.udhdata)) {
1463  /* udhdata will be truncated and warned about if
1464  * it does not fit. */
1465  packet_add_hex_parm(packet, P_USER_DATA_HEADER, msg->sms.udhdata, conn);
1466  }
1467  if (msg->sms.coding == DC_7BIT || msg->sms.coding == DC_UNDEF)
1468  spaceleft = spaceleft * 8 / 7;
1469  if (spaceleft < 0)
1470  spaceleft = 0;
1471 
1472  text = octstr_duplicate(msg->sms.msgdata);
1473 
1474  if (octstr_len(text) > 0 && spaceleft == 0) {
1475  warning(0, "CIMD2[%s]: message filled up with UDH, no room for message text",
1476  octstr_get_cstr(conn->id));
1477  } else if (msg->sms.coding == DC_8BIT || msg->sms.coding == DC_UCS2) {
1478  if (octstr_len(text) > spaceleft) {
1479  truncated = octstr_len(text) - spaceleft;
1480  octstr_truncate(text, spaceleft);
1481  }
1483  } else {
1484  /* Going from latin1 to GSM to CIMD2 may seem like a
1485  * detour, but it's the only way to get all the escape
1486  * codes right. */
1488  truncated = charset_gsm_truncate(text, spaceleft);
1491  }
1492 
1493  if (dcs != 0)
1495 
1496  if (truncated > 0) {
1497  warning(0, "CIMD2[%s]: truncating message text to fit in %d characters.",
1498  octstr_get_cstr(conn->id),
1499  spaceleft);
1500  }
1501 
1503  return packet;
1504 }
1505 
1506 /***************************************************************************/
1507 /* Protocol functions. These implement various transactions. */
1508 /***************************************************************************/
1509 
1510 /* Give this packet a proper sequence number for sending. */
1511 static void packet_set_send_sequence(struct packet *packet, PrivData *pdata)
1512 {
1513  gw_assert(pdata != NULL);
1514  /* LOGIN packets always have sequence number 001 */
1515  if (packet->operation == LOGIN)
1516  pdata->send_seq = 1;
1517  /* Send sequence numbers are always odd, receiving are always even */
1518  gw_assert(pdata->send_seq % 2 == 1);
1519 
1521  pdata->send_seq += 2;
1522  if (pdata->send_seq > 256)
1523  pdata->send_seq = 1;
1524 }
1525 
1526 static struct packet *cimd2_get_packet(PrivData *pdata, Octstr **ts)
1527 {
1528  struct packet *packet = NULL;
1529 
1530  gw_assert(pdata != NULL);
1531 
1532  /* If packet is already available, don't try to read anything */
1533  packet = packet_extract(pdata->inbuffer, pdata->conn);
1534 
1535  while (packet == NULL) {
1536  if (read_available(pdata->socket, RESPONSE_TIMEOUT) != 1) {
1537  warning(0, "CIMD2[%s]: SMSC is not responding",
1538  octstr_get_cstr(pdata->conn->id));
1539  return NULL;
1540  }
1541 
1542  if (octstr_append_from_socket(pdata->inbuffer, pdata->socket) <= 0) {
1543  error(0, "CIMD2[%s]: cimd2_get_packet: read failed",
1544  octstr_get_cstr(pdata->conn->id));
1545  return NULL;
1546  }
1547 
1548  packet = packet_extract(pdata->inbuffer, pdata->conn);
1549  }
1550 
1551  packet_check(packet,pdata->conn);
1553  debug("bb.sms.cimd2", 0, "CIMD2[%s]: received: <%s>",
1554  octstr_get_cstr(pdata->conn->id),
1556  if (ts)
1558 
1559  if (pdata->keepalive > 0)
1560  pdata->next_ping = time(NULL) + pdata->keepalive;
1561 
1562  return packet;
1563 }
1564 
1565 /* Acknowledge a request. The CIMD 2 spec only defines positive responses
1566  * to the server, because the server is perfect. */
1567 static void cimd2_send_response(struct packet *request, PrivData *pdata)
1568 {
1569  struct packet *response;
1570 
1571  gw_assert(request != NULL);
1572  gw_assert(request->operation < RESPONSE);
1573 
1574  response = packet_create(request->operation + RESPONSE, request->seq);
1576 
1577  debug("bb.sms.cimd2", 0, "CIMD2[%s]: sending <%s>",
1578  octstr_get_cstr(pdata->conn->id),
1579  octstr_get_cstr(response->data));
1580 
1581  /* Don't check errors here because if there is something
1582  * wrong with the socket, the main loop will detect it. */
1583  octstr_write_to_socket(pdata->socket, response->data);
1584 
1586 }
1587 
1588 static Msg *cimd2_accept_message(struct packet *request, SMSCConn *conn)
1589 {
1590  Msg *message = NULL;
1591  Octstr *destination = NULL;
1592  Octstr *origin = NULL;
1593  Octstr *UDH = NULL;
1594  Octstr *text = NULL;
1595  int DCS;
1596 
1597  /* See GSM 03.38. The bit patterns we can handle are:
1598  * 000xyyxx Uncompressed text, yy indicates alphabet.
1599  * yy = 00, default alphabet
1600  * yy = 01, 8-bit data
1601  * yy = 10, UCS-2
1602  * yy = 11, reserved
1603  * 1111xyxx Data, y indicates alphabet.
1604  * y = 0, default alphabet
1605  * y = 1, 8-bit data
1606  */
1607  DCS = packet_get_int_parm(request, P_DATA_CODING_SCHEME);
1608 
1609  destination = packet_get_address_parm(request, P_DESTINATION_ADDRESS);
1611  UDH = packet_get_hex_parm(request, P_USER_DATA_HEADER);
1612  /* Text is either in User Data or User Data Binary field. */
1613  text = packet_get_sms_parm(request, P_USER_DATA);
1614  if (text != NULL) {
1615  convert_cimd2_to_gsm(text,conn);
1617  } else {
1618  /*
1619  * FIXME: If DCS indicates GSM charset, and we get it in binary,
1620  * then it's probably bit-packed. We'll have to undo it because
1621  * our "charset_gsm" means one gsm character per octet. This is
1622  * not currently supported. -- RB
1623  */
1625  }
1626 
1627  /* Code elsewhere in the gateway always expects the sender and
1628  * receiver fields to be filled, so we discard messages that
1629  * lack them. If they should not be discarded, then the code
1630  * handling sms messages should be reviewed. -- RB */
1631  if (!destination || octstr_len(destination) == 0) {
1632  info(0, "CIMD2[%s]: Got SMS without receiver, discarding.",
1633  octstr_get_cstr(conn->id));
1634  goto error;
1635  }
1636  if (!origin || octstr_len(origin) == 0) {
1637  info(0, "CIMD2[%s]: Got SMS without sender, discarding.",
1638  octstr_get_cstr(conn->id));
1639  goto error;
1640  }
1641 
1642  if (!text && (!UDH || octstr_len(UDH) == 0)) {
1643  info(0, "CIMD2[%s]: Got empty SMS, ignoring.",
1644  octstr_get_cstr(conn->id));
1645  goto error;
1646  }
1647 
1648  message = msg_create(sms);
1649  if (! dcs_to_fields(&message, DCS)) {
1650  /* XXX Should reject this message ? */
1651  debug("bb.sms.cimd2", 0, "CIMD2[%s]: Invalid DCS",
1652  octstr_get_cstr(conn->id));
1653  dcs_to_fields(&message, 0);
1654  }
1655  time(&message->sms.time);
1656  message->sms.sender = origin;
1657  message->sms.receiver = destination;
1658  if (UDH) {
1659  message->sms.udhdata = UDH;
1660  }
1661  message->sms.msgdata = text;
1662  return message;
1663 
1664 error:
1665  msg_destroy(message);
1666  octstr_destroy(destination);
1667  octstr_destroy(origin);
1668  octstr_destroy(UDH);
1670  return NULL;
1671 }
1672 
1673 /* Deal with a request from the CIMD2 server, and acknowledge it. */
1674 static void cimd2_handle_request(struct packet *request, SMSCConn *conn)
1675 {
1676  PrivData *pdata = conn->data;
1677  Msg *message = NULL;
1678 
1679  if ((request->seq == 254 && pdata->receive_seq == 0) ||
1680  request->seq == pdata->receive_seq - 2) {
1681  warning(0, "CIMD2[%s]: request had same sequence number as previous.",
1682  octstr_get_cstr(conn->id));
1683  }
1684  else {
1685  pdata->receive_seq = request->seq + 2;
1686  if (pdata->receive_seq > 254)
1687  pdata->receive_seq = 0;
1688 
1689  if (request->operation == DELIVER_STATUS_REPORT) {
1690  message = cimd2_accept_delivery_report_message(request, conn);
1691  if (message)
1692  gwlist_append(pdata->received, message);
1693  }
1694  else if (request->operation == DELIVER_MESSAGE) {
1695  message = cimd2_accept_message(request,conn);
1696  if (message)
1697  gwlist_append(pdata->received, message);
1698  }
1699  }
1700 
1701  cimd2_send_response(request, pdata);
1702 }
1703 
1704 /* Send a request and wait for the ack. If the other side responds with
1705  * an error code, attempt to correct and retry.
1706  * If other packets arrive while we wait for the ack, handle them.
1707  *
1708  * Return -1 if the SMSC refused the request. Return -2 for other
1709  * errors, such as being unable to send the request at all. If the
1710  * function returns -2, the caller would do well to try to reopen the
1711  * connection.
1712  *
1713  * The SMSCenter must be already open.
1714  *
1715  * TODO: This function has grown large and complex. Break it up
1716  * into smaller pieces.
1717  */
1718 static int cimd2_request(struct packet *request, SMSCConn *conn, Octstr **ts)
1719 {
1720  PrivData *pdata = conn->data;
1721  int ret;
1722  struct packet *reply = NULL;
1723  int errorcode;
1724  int tries = 0;
1725 
1726  gw_assert(pdata != NULL);
1727  gw_assert(request != NULL);
1729 
1730  if (pdata->socket < 0) {
1731  warning(0, "CIMD2[%s]: cimd2_request: socket not open.",
1732  octstr_get_cstr(conn->id));
1733  return -2;
1734  }
1735 
1736 retransmit:
1737  packet_set_send_sequence(request, pdata);
1738  packet_set_checksum(request);
1739 
1740  debug("bb.sms.cimd2", 0, "CIMD2[%s]: sending <%s>",
1741  octstr_get_cstr(conn->id),
1742  octstr_get_cstr(request->data));
1743 
1744  ret = octstr_write_to_socket(pdata->socket, request->data);
1745  if (ret < 0)
1746  goto io_error;
1747 
1748 next_reply:
1749  packet_destroy(reply); /* destroy old, if any */
1750  reply = cimd2_get_packet(pdata, ts);
1751  if (!reply)
1752  goto io_error;
1753 
1754  errorcode = packet_display_error(reply,conn);
1755 
1756  if (reply->operation == NACK) {
1757  warning(0, "CIMD2[%s]: received NACK",
1758  octstr_get_cstr(conn->id));
1759  octstr_dump(reply->data, 0);
1760  /* Correct sequence number if server says it was wrong,
1761  * but only if server's number is sane. */
1762  if (reply->seq != request->seq && (reply->seq % 2) == 1) {
1763  warning(0, "CIMD2[%s]: correcting sequence number from %ld to %ld.",
1764  octstr_get_cstr(conn->id),
1765  (long) pdata->send_seq,
1766  (long) reply->seq);
1767  pdata->send_seq = reply->seq;
1768  }
1769  goto retry;
1770  }
1771 
1772  if (reply->operation == GENERAL_ERROR_RESPONSE) {
1773  error(0, "CIMD2[%s]: received general error response",
1774  octstr_get_cstr(conn->id));
1775  goto io_error;
1776  }
1777 
1778  /* The server sent us a request. Handle it, then wait for
1779  * a new reply. */
1780  if (reply->operation < RESPONSE) {
1781  cimd2_handle_request(reply, conn);
1782  goto next_reply;
1783  }
1784 
1785  if (reply->seq != request->seq) {
1786  /* We got a response to a different request number than
1787  * what we send. Strange. */
1788  warning(0, "CIMD2[%s]: response had unexpected sequence number; ignoring.",
1789  octstr_get_cstr(conn->id));
1790  goto next_reply;
1791  }
1792 
1793  if (reply->operation != request->operation + RESPONSE) {
1794  /* We got a response that didn't match our request */
1795  Octstr *request_name = operation_name(request->operation);
1796  Octstr *reply_name = operation_name(reply->operation);
1797  warning(0, "CIMD2[%s]: %s request got a %s",
1798  octstr_get_cstr(conn->id),
1799  octstr_get_cstr(request_name),
1800  octstr_get_cstr(reply_name));
1801 
1802  octstr_destroy(request_name);
1803  octstr_destroy(reply_name);
1804  octstr_dump(reply->data, 0);
1805  goto retry;
1806  }
1807 
1808  if (errorcode > 0)
1809  goto error;
1810 
1811  /* The reply passed all the checks... looks like the SMSC accepted
1812  * our request! */
1814  return 0;
1815 
1816 io_error:
1818  return -2;
1819 
1820 error:
1822  return -1;
1823 
1824 retry:
1825  if (++tries < 3) {
1826  warning(0, "CIMD2[%s]: Retransmitting (take %d)",
1827  octstr_get_cstr(conn->id),
1828  tries);
1829  goto retransmit;
1830  }
1831  warning(0, "CIMD2[%s]: Giving up.",
1832  octstr_get_cstr(conn->id));
1833  goto io_error;
1834 }
1835 
1836 /* Close the SMSC socket without fanfare. */
1837 static void cimd2_close_socket(PrivData *pdata)
1838 {
1839  gw_assert(pdata != NULL);
1840 
1841  if (pdata->socket < 0)
1842  return;
1843 
1844  if (close(pdata->socket) < 0)
1845  warning(errno, "CIMD2[%s]: error closing socket",
1846  octstr_get_cstr(pdata->conn->id));
1847  pdata->socket = -1;
1848 }
1849 
1850 /* Open a socket to the SMSC, send a login packet, and wait for ack.
1851  * This may block. Return 0 for success, or -1 for failure. */
1852 /* Make sure the socket is closed before calling this function, otherwise
1853  * we will leak fd's. */
1854 static int cimd2_login(SMSCConn *conn)
1855 {
1856  PrivData *pdata = conn->data;
1857  int ret;
1858  struct packet *packet = NULL;
1859 
1860  gw_assert(pdata != NULL);
1861 
1862  if (pdata->socket >= 0) {
1863  warning(0, "CIMD2[%s]: login: socket was already open; closing",
1864  octstr_get_cstr(conn->id));
1865  cimd2_close_socket(pdata);
1866  }
1867 
1869  octstr_get_cstr(pdata->host),
1870  pdata->port,
1871  pdata->our_port,
1872  (conn->our_host ? octstr_get_cstr(conn->our_host) : NULL));
1873  if (pdata->socket != -1) {
1874 
1878 
1879  ret = cimd2_request(packet, conn, NULL);
1880 
1881  if (ret >= 0) {
1883  info(0, "CIMD2[%s] logged in.",
1884  octstr_get_cstr(conn->id));
1885  return 0;
1886  }
1887  }
1888  error(0, "CIMD2[%s] login failed.",
1889  octstr_get_cstr(conn->id));
1890  cimd2_close_socket(pdata);
1892  return -1;
1893 }
1894 
1895 static void cimd2_logout(SMSCConn *conn)
1896 {
1897  struct packet *packet = NULL;
1898  int ret;
1899 
1901 
1902  /* TODO: Don't wait very long for a response in this case. */
1903  ret = cimd2_request(packet, conn, NULL);
1904 
1905  if (ret == 0) {
1906  info(0, "CIMD2[%s] logged out.",
1907  octstr_get_cstr(conn->id));
1908  }
1910 }
1911 
1912 static int cimd2_send_alive(SMSCConn *conn)
1913 {
1914  struct packet *packet = NULL;
1915  int ret;
1916 
1918  ret = cimd2_request(packet, conn, NULL);
1920 
1921  if (ret < 0)
1922  warning(0, "CIMD2[%s]: SMSC not alive.",
1923  octstr_get_cstr(conn->id));
1924 
1925  return ret;
1926 }
1927 
1928 
1929 static void cimd2_destroy(PrivData *pdata)
1930 {
1931  int discarded;
1932 
1933  if (pdata == NULL)
1934  return;
1935 
1936  octstr_destroy(pdata->host);
1937  octstr_destroy(pdata->username);
1938  octstr_destroy(pdata->password);
1939  octstr_destroy(pdata->inbuffer);
1940  octstr_destroy(pdata->my_number);
1941 
1942  discarded = gwlist_len(pdata->received);
1943  if (discarded > 0)
1944  warning(0, "CIMD2[%s]: discarded %d received messages",
1945  octstr_get_cstr(pdata->conn->id),
1946  discarded);
1947 
1949  gwlist_destroy(pdata->outgoing_queue, NULL);
1950  gwlist_destroy(pdata->stopped, NULL);
1951 
1952  gw_free(pdata);
1953 }
1954 
1955 
1956 static int cimd2_submit_msg(SMSCConn *conn, Msg *msg)
1957 {
1958  PrivData *pdata = conn->data;
1959  struct packet *packet;
1960  Octstr *ts = NULL;
1961  int ret;
1962 
1963  gw_assert(pdata != NULL);
1964  debug("bb.sms.cimd2", 0, "CIMD2[%s]: sending message",
1965  octstr_get_cstr(conn->id));
1966 
1967  packet = packet_encode_message(msg, pdata->my_number,conn);
1968  if (!packet) {
1969  /* This is a protocol error. Does this help? I doubt..
1970  * But nevermind that.
1971  */
1974  return -1;
1975  }
1976 
1977  ret = cimd2_request(packet, conn, &ts);
1978  if ((ret == 0) && (ts) && DLR_IS_SUCCESS_OR_FAIL(msg->sms.dlr_mask) && !pdata->no_dlr) {
1979  dlr_add(conn->id, ts, msg, 1);
1980  }
1981  octstr_destroy(ts);
1983 
1984  if (ret == -1) {
1987  }
1988  else if (ret == -2) {
1989  cimd2_close_socket(pdata);
1991  mutex_lock(conn->flow_mutex);
1992  conn->status = SMSCCONN_DISCONNECTED;
1993  mutex_unlock(conn->flow_mutex);
1994  }
1995  else {
1996  bb_smscconn_sent(conn,msg, NULL);
1997  }
1998 
1999  return ret;
2000 }
2001 
2002 static int cimd2_receive_msg(SMSCConn *conn, Msg **msg)
2003 {
2004  PrivData *pdata = conn->data;
2005  long ret;
2006  struct packet *packet;
2007 
2008  gw_assert(pdata != NULL);
2009 
2010  if (gwlist_len(pdata->received) > 0) {
2011  *msg = gwlist_consume(pdata->received);
2012  return 1;
2013  }
2014 
2015  if (pdata->socket < 0) {
2016  /* XXX We have to assume that smsc_send_message is
2017  * currently trying to reopen, so we have to make
2018  * this thread wait. It should be done in a nicer
2019  * way. */
2020  return 0;
2021  }
2022 
2023  ret = read_available(pdata->socket, 0);
2024  if (ret == 0) {
2025  if (pdata->keepalive > 0 && pdata->next_ping < time(NULL)) {
2026  if (cimd2_send_alive(conn) < 0)
2027  return -1;
2028  }
2029  return 0;
2030  }
2031 
2032  if (ret < 0) {
2033  warning(errno, "CIMD2[%s]: cimd2_receive_msg: read_available failed",
2034  octstr_get_cstr(conn->id));
2035  return -1;
2036  }
2037 
2038  /* We have some data waiting... see if it is an sms delivery. */
2039  ret = octstr_append_from_socket(pdata->inbuffer, pdata->socket);
2040 
2041  if (ret == 0) {
2042  warning(0, "CIMD2[%s]: cimd2_receive_msg: service center closed connection.",
2043  octstr_get_cstr(conn->id));
2044  return -1;
2045  }
2046  if (ret < 0) {
2047  warning(0, "CIMD2[%s]: cimd2_receive_msg: read failed",
2048  octstr_get_cstr(conn->id));
2049  return -1;
2050  }
2051 
2052 
2053  for (;;) {
2054  packet = packet_extract(pdata->inbuffer,conn);
2055  if (!packet)
2056  break;
2057 
2058  packet_check(packet,conn);
2060  debug("bb.sms.cimd2", 0, "CIMD2[%s]: received: <%s>",
2061  octstr_get_cstr(pdata->conn->id),
2063 
2064  if (packet->operation < RESPONSE)
2066  else {
2067  error(0, "CIMD2[%s]: cimd2_receive_msg: unexpected response packet",
2068  octstr_get_cstr(conn->id));
2069  octstr_dump(packet->data, 0);
2070  }
2071 
2073  }
2074 
2075  if (gwlist_len(pdata->received) > 0) {
2076  *msg = gwlist_consume(pdata->received);
2077  return 1;
2078  }
2079  return 0;
2080 }
2081 
2082 
2083 
2085  SMSCConn *conn)
2086 {
2087  Msg *msg = NULL;
2088  Octstr *destination = NULL;
2089  Octstr *timestamp = NULL;
2090  Octstr *statuscode = NULL;
2091  int st_code;
2092  int code;
2093 
2094  destination = packet_get_parm(request, P_DESTINATION_ADDRESS);
2095  timestamp = packet_get_parm(request, P_MC_TIMESTAMP);
2096  statuscode = packet_get_parm(request, P_STATUS_CODE);
2097 
2098  st_code = atoi(octstr_get_cstr(statuscode));
2099 
2100  switch(st_code)
2101  {
2102  case 2: /* validity period expired */
2103  code = DLR_EXPIRED;
2104  break;
2105  case 3: /* delivery failed */
2106  case 6: /* last no response */
2107  case 7: /* message cancelled */
2108  case 8: /* message deleted */
2109  case 9: /* message deleted by cancel */
2110  code = DLR_FAIL;
2111  break;
2112  case 4: /* delivery successful */
2113  code = DLR_SUCCESS;
2114  break;
2115  default:
2116  code = 0;
2117  }
2118  if(code)
2119  msg = dlr_find(conn->id, timestamp, destination, code, 1);
2120  else
2121  msg = NULL;
2122 
2123  /* recode the body into msgdata */
2124  if (msg) {
2125  msg->sms.msgdata = packet_get_parm(request, P_USER_DATA);
2126  if (!msg->sms.msgdata) {
2127  msg->sms.msgdata = statuscode;
2128  statuscode = NULL;
2129  }
2130  }
2131 
2132  octstr_destroy(statuscode);
2133  octstr_destroy(destination);
2134  octstr_destroy(timestamp);
2135 
2136  return msg;
2137  }
2138 
2139 static Msg *sms_receive(SMSCConn *conn)
2140 {
2141  PrivData *pdata = conn->data;
2142  int ret;
2143  Msg *newmsg = NULL;
2144 
2145  ret = cimd2_receive_msg(conn, &newmsg);
2146  if (ret == 1) {
2147  /* if any smsc_id available, use it */
2148  newmsg->sms.smsc_id = octstr_duplicate(conn->id);
2149  return newmsg;
2150  }
2151  else if (ret == 0) { /* no message, just retry... */
2152  return NULL;
2153  }
2154  /* error. reconnect. */
2155  msg_destroy(newmsg);
2156  mutex_lock(conn->flow_mutex);
2157  cimd2_close_socket(pdata);
2158  conn->status = SMSCCONN_DISCONNECTED;
2159  mutex_unlock(conn->flow_mutex);
2160  return NULL;
2161 }
2162 
2163 
2164 static void io_thread (void *arg)
2165 {
2166  Msg *msg;
2167  SMSCConn *conn = arg;
2168  PrivData *pdata = conn->data;
2169  double sleep = 0.0001;
2170 
2171  /* Make sure we log into our own log-file if defined */
2172  log_thread_to(conn->log_idx);
2173 
2174  /* remove messages from SMSC until we are killed */
2175  while (!pdata->quitting) {
2176 
2177  gwlist_consume(pdata->stopped); /* block here if suspended/isolated */
2178 
2179  /* check that connection is active */
2180  if (conn->status != SMSCCONN_ACTIVE) {
2181  if (cimd2_login(conn) != 0) {
2182  error(0, "CIMD2[%s]: Couldn't connect to SMSC (retrying in %ld seconds).",
2183  octstr_get_cstr(conn->id),
2184  conn->reconnect_delay);
2186  mutex_lock(conn->flow_mutex);
2187  conn->status = SMSCCONN_RECONNECTING;
2188  mutex_unlock(conn->flow_mutex);
2189  continue;
2190  }
2191  mutex_lock(conn->flow_mutex);
2192  conn->status = SMSCCONN_ACTIVE;
2193  conn->connect_time = time(NULL);
2194  bb_smscconn_connected(conn);
2195  mutex_unlock(conn->flow_mutex);
2196  }
2197 
2198  /* receive messages */
2199  do {
2200  msg = sms_receive(conn);
2201  if (msg) {
2202  sleep = 0;
2203  debug("bb.sms.cimd2", 0, "CIMD2[%s]: new message received",
2204  octstr_get_cstr(conn->id));
2205  bb_smscconn_receive(conn, msg);
2206  }
2207  } while (msg);
2208 
2209  /* send messages */
2210  do {
2212  if (msg) {
2213  sleep = 0;
2214  if (cimd2_submit_msg(conn,msg) != 0) break;
2215  }
2216  } while (msg);
2217 
2218  if (sleep > 0) {
2219 
2220  /* note that this implementations means that we sleep even
2221  * when we fail connection.. but time is very short, anyway
2222  */
2223  gwthread_sleep(sleep);
2224  /* gradually sleep longer and longer times until something starts to
2225  * happen - this of course reduces response time, but that's better than
2226  * extensive CPU usage when it is not used
2227  */
2228  sleep *= 2;
2229  if (sleep >= 2.0)
2230  sleep = 1.999999;
2231  }
2232  else {
2233  sleep = 0.0001;
2234  }
2235  }
2236 }
2237 
2238 
2239 static int cimd2_add_msg_cb (SMSCConn *conn, Msg *sms)
2240 {
2241  PrivData *pdata = conn->data;
2242  Msg *copy;
2243 
2244  copy = msg_duplicate(sms);
2245  gwlist_produce(pdata->outgoing_queue, copy);
2246  gwthread_wakeup(pdata->io_thread);
2247 
2248  return 0;
2249 }
2250 
2251 
2252 static int cimd2_shutdown_cb (SMSCConn *conn, int finish_sending)
2253 {
2254  PrivData *pdata = conn->data;
2255 
2256  debug("bb.sms", 0, "Shutting down SMSCConn CIMD2 %s (%s)",
2257  octstr_get_cstr(conn->id),
2258  finish_sending ? "slow" : "instant");
2259 
2260  /* Documentation claims this would have been done by smscconn.c,
2261  but isn't when this code is being written. */
2263  pdata->quitting = 1; /* Separate from why_killed to avoid locking, as
2264  * why_killed may be changed from outside? */
2265 
2266  if (finish_sending == 0) {
2267  Msg *msg;
2268  while ((msg = gwlist_extract_first(pdata->outgoing_queue)) != NULL) {
2270  }
2271  }
2272 
2273  cimd2_logout(conn);
2274  if (conn->is_stopped) {
2276  conn->is_stopped = 0;
2277  }
2278 
2279  if (pdata->io_thread != -1) {
2280  gwthread_wakeup(pdata->io_thread);
2281  gwthread_join(pdata->io_thread);
2282  }
2283 
2284  cimd2_close_socket(pdata);
2285  cimd2_destroy(pdata);
2286 
2287  debug("bb.sms", 0, "SMSCConn CIMD2 %s shut down.",
2288  octstr_get_cstr(conn->id));
2289  conn->status = SMSCCONN_DEAD;
2290  bb_smscconn_killed();
2291  return 0;
2292 }
2293 
2294 static void cimd2_start_cb (SMSCConn *conn)
2295 {
2296  PrivData *pdata = conn->data;
2297 
2299  /* in case there are messages in the buffer already */
2300  gwthread_wakeup(pdata->io_thread);
2301  debug("bb.sms", 0, "SMSCConn CIMD2 %s, start called",
2302  octstr_get_cstr(conn->id));
2303 }
2304 
2305 static void cimd2_stop_cb (SMSCConn *conn)
2306 {
2307  PrivData *pdata = conn->data;
2308  gwlist_add_producer(pdata->stopped);
2309  debug("bb.sms", 0, "SMSCConn CIMD2 %s, stop called",
2310  octstr_get_cstr(conn->id));
2311 }
2312 
2313 static long cimd2_queued_cb (SMSCConn *conn)
2314 {
2315  PrivData *pdata = conn->data;
2316  conn->load = (pdata ? (conn->status != SMSCCONN_DEAD ?
2317  gwlist_len(pdata->outgoing_queue) : 0) : 0);
2318  return conn->load;
2319 }
2320 
2322 {
2323  PrivData *pdata;
2324  int ok;
2325  int maxlen;
2326 
2327  pdata = gw_malloc(sizeof(PrivData));
2328  conn->data = pdata;
2329  pdata->conn = conn;
2330 
2331  pdata->no_dlr = 0;
2332  pdata->quitting = 0;
2333  pdata->socket = -1;
2334  pdata->received = gwlist_create();
2335  pdata->inbuffer = octstr_create("");
2336  pdata->send_seq = 1;
2337  pdata->receive_seq = 0;
2338  pdata->outgoing_queue = gwlist_create();
2339  pdata->stopped = gwlist_create();
2341 
2342  if (conn->is_stopped)
2343  gwlist_add_producer(pdata->stopped);
2344 
2345  pdata->host = cfg_get(grp, octstr_imm("host"));
2346  if (cfg_get_integer(&(pdata->port), grp, octstr_imm("port")) == -1)
2347  pdata->port = 0;
2348  if (cfg_get_integer(&(pdata->our_port), grp, octstr_imm("our-port")) == -1)
2349  pdata->our_port = 0;
2350  pdata->username = cfg_get(grp, octstr_imm("smsc-username"));
2351  pdata->password = cfg_get(grp, octstr_imm("smsc-password"));
2352  pdata->my_number = cfg_get(grp, octstr_imm("my-number"));
2353  if (cfg_get_integer(&(pdata->keepalive), grp,octstr_imm("keepalive")) == -1)
2354  pdata->keepalive = 0;
2355 
2356  cfg_get_bool(&pdata->no_dlr, grp, octstr_imm("no-dlr"));
2357 
2358  /* Check that config is OK */
2359  ok = 1;
2360  if (pdata->host == NULL) {
2361  error(0,"CIMD2[%s]: Configuration file doesn't specify host",
2362  octstr_get_cstr(conn->id));
2363  ok = 0;
2364  }
2365  if (pdata->port == 0) {
2366  error(0,"CIMD2[%s]: Configuration file doesn't specify port",
2367  octstr_get_cstr(conn->id));
2368  ok = 0;
2369  }
2370  if (pdata->username == NULL) {
2371  error(0, "CIMD2[%s]: Configuration file doesn't specify username.",
2372  octstr_get_cstr(conn->id));
2373  ok = 0;
2374  }
2375  if (pdata->password == NULL) {
2376  error(0, "CIMD2[%s]: Configuration file doesn't specify password.",
2377  octstr_get_cstr(conn->id));
2378  ok = 0;
2379  }
2380 
2381  if (!ok) {
2382  cimd2_destroy(pdata);
2383  return -1;
2384  }
2385 
2386  conn->name = octstr_format("CIMD2:%s:%d:%s",
2387  octstr_get_cstr(pdata->host),
2388  pdata->port,
2389  octstr_get_cstr(pdata->username));
2390 
2391 
2392  if (pdata->keepalive > 0) {
2393  debug("bb.sms.cimd2", 0, "CIMD2[%s]: Keepalive set to %ld seconds",
2394  octstr_get_cstr(conn->id),
2395  pdata->keepalive);
2396  pdata->next_ping = time(NULL) + pdata->keepalive;
2397  }
2398 
2400  if (octstr_len(pdata->username) > maxlen) {
2401  octstr_truncate(pdata->username, maxlen);
2402  warning(0, "CIMD2[%s]: Truncating username to %d chars",
2403  octstr_get_cstr(conn->id),
2404  maxlen);
2405  }
2406 
2408  if (octstr_len(pdata->password) > maxlen) {
2409  octstr_truncate(pdata->password, maxlen);
2410  warning(0, "CIMD2[%s]: Truncating password to %d chars",
2411  octstr_get_cstr(conn->id),
2412  maxlen);
2413  }
2414 
2415  pdata->io_thread = gwthread_create(io_thread, conn);
2416 
2417  if (pdata->io_thread == -1) {
2418 
2419  error(0,"CIMD2[%s]: Couldn't start I/O thread.",
2420  octstr_get_cstr(conn->id));
2421  pdata->quitting = 1;
2422  gwthread_wakeup(pdata->io_thread);
2423  gwthread_join(pdata->io_thread);
2424  cimd2_destroy(pdata);
2425  return -1;
2426  }
2427 
2428  conn->send_msg = cimd2_add_msg_cb;
2429  conn->shutdown = cimd2_shutdown_cb;
2430  conn->queued = cimd2_queued_cb;
2431  conn->start_conn = cimd2_start_cb;
2432  conn->stop_conn = cimd2_stop_cb;
2433 
2434  return 0;
2435 }
2436 
long port
Definition: smsc_cimd2.c:102
Octstr * name
Definition: smscconn_p.h:173
void error(int err, const char *fmt,...)
Definition: log.c:648
int operation
Definition: smsc_cimd2.c:444
void info(int err, const char *fmt,...)
Definition: log.c:672
int octstr_write_to_socket(int socket, Octstr *ostr)
Definition: octstr.c:1227
int number
Definition: smsc_cimd2.c:213
Msg * msg_duplicate(Msg *msg)
Definition: msg.c:111
void bb_smscconn_connected(SMSCConn *conn)
Definition: bb_smscconn.c:192
#define TAB
Definition: smsc_cimd2.c:463
#define ETX
Definition: smsc_cimd2.c:462
static Octstr * packet_get_sms_parm(struct packet *packet, int parmno)
Definition: smsc_cimd2.c:665
static int packet_check_parameter(struct packet *packet, long pos, long len, SMSCConn *conn)
Definition: smsc_cimd2.c:728
static Octstr * packet_get_hex_parm(struct packet *packet, int parmno)
Definition: smsc_cimd2.c:681
Octstr * inbuffer
Definition: smsc_cimd2.c:112
int smsc_cimd2_create(SMSCConn *conn, CfgGroup *grp)
Definition: smsc_cimd2.c:2321
gw_assert(wtls_machine->packet_to_send !=NULL)
#define TAB_str
Definition: smsc_cimd2.c:468
#define mutex_unlock(m)
Definition: thread.h:136
void gwlist_append(List *list, void *item)
Definition: list.c:179
int alt_dcs
Definition: smscconn_p.h:201
void bb_smscconn_killed(void)
Definition: bb_smscconn.c:199
int minval
Definition: smsc_cimd2.c:216
unsigned char cimd1
Definition: smsc_cimd2.c:1024
static void cimd2_send_response(struct packet *request, PrivData *pdata)
Definition: smsc_cimd2.c:1567
int octstr_check_range(Octstr *ostr, long pos, long len, octstr_func_t filter)
Definition: octstr.c:814
static void packet_add_parm(struct packet *packet, int parmtype, int parmno, Octstr *value, SMSCConn *conn)
Definition: smsc_cimd2.c:1191
unsigned char gsm
Definition: smsc_cimd2.c:1025
void gwlist_produce(List *list, void *item)
Definition: list.c:411
Octstr * id
Definition: smscconn_p.h:174
void gwthread_join(long thread)
long gwlist_len(List *list)
Definition: list.c:166
static Octstr * packet_get_parm(struct packet *packet, int parmno)
Definition: smsc_cimd2.c:579
void * data
Definition: smscconn_p.h:250
int octstr_append_from_socket(Octstr *ostr, int socket)
Definition: octstr.c:1280
static int parm_valid_address(Octstr *value)
Definition: smsc_cimd2.c:329
static void packet_parse_header(struct packet *packet)
Definition: smsc_cimd2.c:480
List * outgoing_queue
Definition: smsc_cgw.c:153
void(* stop_conn)(SMSCConn *conn)
Definition: smscconn_p.h:247
static void packet_check_can_receive(struct packet *packet, SMSCConn *conn)
Definition: smsc_cimd2.c:904
int code
Definition: smsc_cimd2.c:346
static int parm_maxlen(int parmno)
Definition: smsc_cimd2.c:287
void charset_utf8_to_gsm(Octstr *ostr)
Definition: charset.c:288
int socket
Definition: smsc_cimd2.c:108
Octstr * password
Definition: smsc_cimd2.c:100
int log_idx
Definition: smscconn_p.h:197
int type
Definition: smsc_cimd2.c:215
#define DLR_EXPIRED
Definition: dlr.h:77
static void cimd2_handle_request(struct packet *request, SMSCConn *conn)
Definition: smsc_cimd2.c:1674
int can_send
Definition: smsc_cimd2.c:347
#define cfg_get(grp, varname)
Definition: cfg.h:86
#define DC_8BIT
Definition: sms.h:111
static struct packet * cimd2_get_packet(PrivData *pdata, Octstr **ts)
Definition: smsc_cimd2.c:1526
static Octstr * packet_get_address_parm(struct packet *packet, int parmno)
Definition: smsc_cimd2.c:653
#define msg_create(type)
Definition: msg.h:136
int io_thread
Definition: smsc_cimd2.c:119
static void packet_set_checksum(struct packet *packet)
Definition: smsc_cimd2.c:1274
static void packet_add_sms_parm(struct packet *packet, int parmno, Octstr *value, SMSCConn *conn)
Definition: smsc_cimd2.c:1241
Octstr * our_host
Definition: smscconn_p.h:192
static int cimd2_shutdown_cb(SMSCConn *conn, int finish_sending)
Definition: smsc_cimd2.c:2252
void octstr_append_cstr(Octstr *ostr, const char *cstr)
Definition: octstr.c:1511
void octstr_insert_data(Octstr *ostr, long pos, const char *data, long len)
Definition: octstr.c:1461
Msg * dlr_find(const Octstr *smsc, const Octstr *ts, const Octstr *dst, int typ, int use_dst)
Definition: dlr.c:387
void dlr_add(const Octstr *smsc, const Octstr *ts, Msg *msg, int use_dst)
Definition: dlr.c:330
#define octstr_get_cstr(ostr)
Definition: octstr.h:233
#define octstr_copy(ostr, from, len)
Definition: octstr.h:178
void octstr_binary_to_hex(Octstr *ostr, int uppercase)
Definition: octstr.c:465
void(* start_conn)(SMSCConn *conn)
Definition: smscconn_p.h:246
long octstr_search_char(const Octstr *ostr, int ch, long pos)
Definition: octstr.c:1012
long reconnect_delay
Definition: smscconn_p.h:199
void log_thread_to(int idx)
Definition: log.c:759
List * stopped
Definition: smsc_cimd2.c:121
static void cimd2_logout(SMSCConn *conn)
Definition: smsc_cimd2.c:1895
int receive_seq
Definition: smsc_cimd2.c:110
time_t next_ping
Definition: smsc_cimd2.c:115
#define BOGUS_SEQUENCE
Definition: smsc_cimd2.c:471
static int packet_display_error(struct packet *packet, SMSCConn *conn)
Definition: smsc_cimd2.c:979
static void io_thread(void *arg)
Definition: smsc_cimd2.c:2164
static const char * parm_name(int parmno)
Definition: smsc_cimd2.c:297
static int operation_can_send(int operation)
Definition: smsc_cimd2.c:406
static void packet_set_send_sequence(struct packet *packet, PrivData *pdata)
Definition: smsc_cimd2.c:1511
static Msg * cimd2_accept_delivery_report_message(struct packet *request, SMSCConn *conn)
Definition: smsc_cimd2.c:2084
smscconn_killed_t why_killed
Definition: smscconn_p.h:153
#define DLR_SUCCESS
Definition: dlr.h:72
static void cimd2_close_socket(PrivData *pdata)
Definition: smsc_cimd2.c:1837
static int cimd2_request(struct packet *request, SMSCConn *conn, Octstr **ts)
Definition: smsc_cimd2.c:1718
static long packet_get_int_parm(struct packet *packet, int parmno)
Definition: smsc_cimd2.c:616
void msg_destroy_item(void *msg)
Definition: msg.c:147
Octstr * octstr_imm(const char *cstr)
Definition: octstr.c:283
static void packet_set_sequence(struct packet *packet, int seq)
Definition: smsc_cimd2.c:1302
Definition: msg.h:79
void octstr_insert(Octstr *ostr1, const Octstr *ostr2, long pos)
Definition: octstr.c:1303
static int parm_index(int parmno)
Definition: smsc_cimd2.c:260
Octstr * my_number
Definition: smsc_cimd2.c:105
static void cimd2_start_cb(SMSCConn *conn)
Definition: smsc_cimd2.c:2294
static int cimd2_send_alive(SMSCConn *conn)
Definition: smsc_cimd2.c:1912
void * gwlist_extract_first(List *list)
Definition: list.c:305
#define STX
Definition: smsc_cimd2.c:461
void octstr_delete(Octstr *ostr1, long pos, long len)
Definition: octstr.c:1527
void gwlist_remove_producer(List *list)
Definition: list.c:401
static int cimd2_receive_msg(SMSCConn *conn, Msg **msg)
Definition: smsc_cimd2.c:2002
Octstr * data
Definition: smsc_cimd2.c:446
long bb_smscconn_receive(SMSCConn *conn, Msg *sms)
Definition: bb_smscconn.c:477
char * text
Definition: smsc_cimd2.c:921
static Octstr * operation_name(int operation)
Definition: smsc_cimd2.c:384
static int isphonedigit(int c)
Definition: smsc_cimd2.c:324
#define ETX_str
Definition: smsc_cimd2.c:467
static void packet_add_string_parm(struct packet *packet, int parmno, Octstr *value, SMSCConn *conn)
Definition: smsc_cimd2.c:1227
time_t connect_time
Definition: smscconn_p.h:155
int octstr_ncompare(const Octstr *ostr1, const Octstr *ostr2, long n)
Definition: octstr.c:952
int seq
Definition: smsc_cimd2.c:445
static const struct @19 parameters[]
#define octstr_duplicate(ostr)
Definition: octstr.h:187
#define octstr_dump(ostr, level,...)
Definition: octstr.h:564
static void packet_add_hex_parm(struct packet *packet, int parmno, Octstr *value, SMSCConn *conn)
Definition: smsc_cimd2.c:1252
Mutex * flow_mutex
Definition: smscconn_p.h:157
void msg_destroy(Msg *msg)
Definition: msg.c:132
Octstr * username
Definition: smsc_cimd2.c:99
static Msg * sms_receive(SMSCConn *conn)
Definition: smsc_cimd2.c:2139
char * name
Definition: smsc_cimd2.c:212
int gw_isdigit(int c)
Definition: utils.c:988
void warning(int err, const char *fmt,...)
Definition: log.c:660
Octstr * host
Definition: smsc_cgw.c:163
int quitting
Definition: smsc_cimd2.c:120
Definition: seewbmp.c:154
long our_port
Definition: smsc_cimd2.c:103
int tcpip_connect_to_server_with_port(char *hostname, int port, int our_port, const char *source_addr)
Definition: socket.c:156
Octstr * octstr_format(const char *fmt,...)
Definition: octstr.c:2464
void octstr_destroy(Octstr *ostr)
Definition: octstr.c:324
#define gwthread_create(func, arg)
Definition: gwthread.h:90
#define octstr_create(cstr)
Definition: octstr.h:125
static int parm_type(int parmno)
Definition: smsc_cimd2.c:274
int fields_to_dcs(Msg *msg, int mode)
Definition: sms.c:73
void gwthread_sleep(double seconds)
static Msg * cimd2_accept_message(struct packet *request, SMSCConn *conn)
Definition: smsc_cimd2.c:1588
volatile sig_atomic_t is_stopped
Definition: smscconn_p.h:169
int send_seq
Definition: smsc_cimd2.c:109
static int operation_can_receive(int operation)
Definition: smsc_cimd2.c:422
int maxlen
Definition: smsc_cimd2.c:214
int no_dlr
Definition: smsc_cimd2.c:106
static void packet_add_int_parm(struct packet *packet, int parmno, long value, SMSCConn *conn)
Definition: smsc_cimd2.c:1261
static void packet_destroy(struct packet *packet)
Definition: smsc_cimd2.c:521
long octstr_len(const Octstr *ostr)
Definition: octstr.c:342
static void convert_gsm_to_cimd2(Octstr *text)
Definition: smsc_cimd2.c:1134
int cfg_get_bool(int *n, CfgGroup *grp, Octstr *varname)
Definition: cfg.c:759
Definition: octstr.c:118
void bb_smscconn_sent(SMSCConn *conn, Msg *sms, Octstr *reply)
Definition: bb_smscconn.c:281
static int packet_check(struct packet *packet, SMSCConn *conn)
Definition: smsc_cimd2.c:846
void * gwlist_consume(List *list)
Definition: list.c:427
static int cimd2_add_msg_cb(SMSCConn *conn, Msg *sms)
Definition: smsc_cimd2.c:2239
int read_available(int fd, long wait_usec)
Definition: socket.c:406
int(* shutdown)(SMSCConn *conn, int finish_sending)
Definition: smscconn_p.h:230
static void packet_add_address_parm(struct packet *packet, int parmno, Octstr *value, SMSCConn *conn)
Definition: smsc_cimd2.c:1233
static int parm_in_range(int parmno, long value)
Definition: smsc_cimd2.c:310
void debug(const char *place, int err, const char *fmt,...)
Definition: log.c:726
int cfg_get_integer(long *n, CfgGroup *grp, Octstr *varname)
Definition: cfg.c:742
Definition: wtp_tid.h:82
static int cimd2_submit_msg(SMSCConn *conn, Msg *msg)
Definition: smsc_cimd2.c:1956
int maxval
Definition: smsc_cimd2.c:216
void gwthread_wakeup(long thread)
Definition: cfg.c:73
static long cimd2_queued_cb(SMSCConn *conn)
Definition: smsc_cimd2.c:2313
#define MSG_PARAM_UNDEFINED
Definition: msg.h:71
static struct @21 cimd2_errors[]
int octstr_hex_to_binary(Octstr *ostr)
Definition: octstr.c:494
List * received
Definition: smsc_cimd2.c:113
#define STX_str
Definition: smsc_cimd2.c:466
smscconn_status_t status
Definition: smscconn_p.h:151
long octstr_parse_long(long *nump, Octstr *ostr, long pos, int base)
Definition: octstr.c:749
#define gwlist_create()
Definition: list.h:136
long(* queued)(SMSCConn *conn)
Definition: smscconn_p.h:241
void octstr_truncate(Octstr *ostr, int new_len)
Definition: octstr.c:1327
int(* send_msg)(SMSCConn *conn, Msg *msg)
Definition: smscconn_p.h:236
unsigned char cimd2
Definition: smsc_cimd2.c:1024
void bb_smscconn_send_failed(SMSCConn *conn, Msg *sms, int reason, Octstr *reply)
Definition: bb_smscconn.c:329
int dcs_to_fields(Msg **msg, int dcs)
Definition: sms.c:139
static const struct @22 cimd_combinations[]
#define DC_UNDEF
Definition: sms.h:109
static void convert_cimd2_to_gsm(Octstr *text, SMSCConn *conn)
Definition: smsc_cimd2.c:1081
static int cimd2_login(SMSCConn *conn)
Definition: smsc_cimd2.c:1854
int can_receive
Definition: smsc_cimd2.c:348
static struct packet * packet_encode_message(Msg *msg, Octstr *sender_prefix, SMSCConn *conn)
Definition: smsc_cimd2.c:1319
#define RESPONSE_TIMEOUT
Definition: smsc_cimd2.c:128
static struct packet * packet_parse(Octstr *packet_data)
Definition: smsc_cimd2.c:507
void gwlist_add_producer(List *list)
Definition: list.c:383
static int response(List *push_headers, Octstr **username, Octstr **password)
int our_port
Definition: smsc_cgw.c:161
int gw_isxdigit(int c)
Definition: utils.c:994
int octstr_get_char(const Octstr *ostr, long pos)
Definition: octstr.c:406
#define mutex_lock(m)
Definition: thread.h:130
static struct packet * packet_extract(Octstr *in, SMSCConn *conn)
Definition: smsc_cimd2.c:533
void octstr_set_char(Octstr *ostr, long pos, int ch)
Definition: octstr.c:415
static int packet_check_header(struct packet *packet, SMSCConn *conn)
Definition: smsc_cimd2.c:705
static int operation_find(int operation)
Definition: smsc_cimd2.c:371
long keepalive
Definition: smsc_cimd2.c:104
Definition: list.c:102
#define DLR_IS_SUCCESS_OR_FAIL(dlr)
Definition: dlr.h:85
static XMLRPCDocument * msg
Definition: test_xmlrpc.c:86
int charset_gsm_truncate(Octstr *gsm, long max)
Definition: charset.c:512
#define DLR_FAIL
Definition: dlr.h:73
static void cimd2_destroy(PrivData *pdata)
Definition: smsc_cimd2.c:1929
static void cimd2_stop_cb(SMSCConn *conn)
Definition: smsc_cimd2.c:2305
#define DC_UCS2
Definition: sms.h:112
static Octstr * packet_get_string_parm(struct packet *packet, int parmno)
Definition: smsc_cimd2.c:642
static void reply(HTTPClient *c, List *push_headers)
#define DC_7BIT
Definition: sms.h:110
SMSCConn * conn
Definition: smsc_cimd2.c:118
static const struct @20 operations[]
int octstr_compare(const Octstr *ostr1, const Octstr *ostr2)
Definition: octstr.c:871
struct privdata PrivData
int load
Definition: smscconn_p.h:152
void charset_gsm_to_utf8(Octstr *ostr)
Definition: charset.c:220
static struct packet * packet_create(int operation, int seq)
Definition: smsc_cimd2.c:1176
void gwlist_destroy(List *list, gwlist_item_destructor_t *destructor)
Definition: list.c:145
See file LICENSE for details about the license agreement for using, modifying, copying or deriving work from this software.