Kannel: Open Source WAP and SMS gateway  $Revision: 5037 $
smsc_emi_x25.c
Go to the documentation of this file.
1 /* ====================================================================
2  * The Kannel Software License, Version 1.0
3  *
4  * Copyright (c) 2001-2016 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 /*****************************************************************************
58 * smsc_emi.c - implement interface to the CMG SMS Center (UCP/EMI).
59 * Mikael Gueck for WapIT Ltd.
60 */
61 
62 /* This file implements two smsc interfaces: EMI_X25 */
63 
64 #include <errno.h>
65 #include <string.h>
66 #include <stdio.h>
67 #include <unistd.h>
68 #include <fcntl.h>
69 #include <termios.h>
70 #include <stdarg.h>
71 #include <stdlib.h>
72 #include <string.h>
73 #include <strings.h>
74 
75 #include <sys/time.h>
76 #include <sys/types.h>
77 #include <sys/socket.h>
78 #include <sys/param.h>
79 #include <sys/ioctl.h>
80 
81 #include "gwlib/gwlib.h"
82 #include "smsc.h"
83 #include "smsc_p.h"
84 #include "alt_charsets.h"
85 #include "sms.h"
86 
87 #ifndef CRTSCTS
88 #define CRTSCTS 0
89 #endif
90 
91 /******************************************************************************
92 * Static functions
93 */
94 static int get_data(SMSCenter *smsc, char *buff, int length);
95 
96 static int put_data(SMSCenter *smsc, char *buff, int length, int is_backup);
97 
98 static int memorybuffer_append_data(SMSCenter *smsc, char *buff, int length);
99 
100 static int memorybuffer_insert_data(SMSCenter *smsc, char *buff, int length);
101 
102 static int memorybuffer_has_rawmessage(SMSCenter *smsc, int type, char auth);
103 
104 static int memorybuffer_cut_rawmessage(SMSCenter *smsc, char *buff, int length);
105 
106 static int parse_rawmessage_to_msg(SMSCenter *smsc, Msg **msg,
107  char *rawmessage, int length);
108 
109 static int parse_msg_to_rawmessage(SMSCenter *smsc, Msg *msg,
110  char *rawmessage, int length);
111 
112 static int acknowledge_from_rawmessage(SMSCenter *smsc,
113  char *rawmessage, int length);
114 
115 static int parse_emi_to_iso88591(char *from, char *to,
116  int length, int alt_charset);
117 
118 static int parse_iso88591_to_emi(char *from, char *to,
119  int length, int alt_charset);
120 static int parse_binary_to_emi(char *from, char *to, int length);
121 
122 static int at_dial(char *device, char *phonenum,
123  char *at_prefix, time_t how_long);
124 static int guarantee_link(SMSCenter *smsc);
125 
126 
127 static void generate_checksum(const unsigned char *buffer,
128  unsigned char *checksum_out);
129 static int wait_for_ack(SMSCenter *smsc, int op_type);
130 
131 
132 static char char_iso_to_sms(unsigned char from, int alt_charset);
133 static char char_sms_to_iso(unsigned char from, int alt_charset);
134 
135 /******************************************************************************
136 * Open the connection and log in - handshake baby
137 */
139 {
140  char tmpbuff[1024];
141 
142  sprintf(tmpbuff, "/dev/%s", smsc->emi_serialdevice);
143  smsc->emi_fd = at_dial(tmpbuff, smsc->emi_phonenum, "ATD", 30);
144 
145  if (smsc->emi_fd <= 0)
146  return -1;
147 
148  return 0;
149 }
150 
151 /* open EMI smscenter */
152 
153 SMSCenter *emi_open(char *phonenum, char *serialdevice, char *username, char *password)
154 {
155  SMSCenter *smsc;
156 
157  smsc = smscenter_construct();
158  if (smsc == NULL)
159  goto error;
160 
161  smsc->type = SMSC_TYPE_EMI_X25;
162 
163  smsc->emi_phonenum = gw_strdup(phonenum);
164  smsc->emi_serialdevice = gw_strdup(serialdevice);
165  smsc->emi_username = gw_strdup(username);
166  smsc->emi_password = gw_strdup(password);
167 
168  smsc->emi_current_msg_number = 0;
169 
170  if (emi_open_connection(smsc) < 0)
171  goto error;
172 
173  sprintf(smsc->name, "EMI:%s:%s", smsc->emi_phonenum,
174  smsc->emi_username);
175  return smsc;
176 
177 error:
178  error(0, "emi_open failed");
179  smscenter_destruct(smsc);
180  return NULL;
181 }
182 
184 {
185  emi_close(smsc);
186 
187  if (emi_open_connection(smsc) < 0) {
188  error(0, "emi_reopen failed");
189  return -1;
190  }
191  return 0;
192 }
193 
195 {
196  return emi_close_ip(smsc);
197 }
198 
199 static int emi_fill_ucp60_login(char *buf, char *OAdC, char *passwd) {
200  int max_ia5passwd_len;
201  char *ia5passwd;
202 
203  max_ia5passwd_len = strlen(passwd) * 2 + 1;
204  ia5passwd = gw_malloc(max_ia5passwd_len);
205 
206  if (parse_binary_to_emi(passwd, ia5passwd, strlen(passwd)) < 0) {
207  error(0, "parse_binary_to_emi failed");
208  gw_free(ia5passwd);
209  return -1;
210  }
211 
212  sprintf(buf, "%s/%c/%c/%c/%s//%s/////",
213  OAdC, /* OAdC: Address code originator */
214  '6', /* OTON: 6 = Abbreviated number (short number alias) */
215  '5', /* ONPI: 5 = Private (TCP/IP address/abbreviated number address) */
216  '1', /* STYP: 1 = open session */
217  ia5passwd, /* PWD: Current password encoded into IA5 characters */
218  "0100" /* VERS: Version number 0100 */
219  );
220 
221  gw_free(ia5passwd);
222  return 0;
223 }
224 
225 static int emi_open_session(SMSCenter *smsc)
226 {
227  char message_whole [1024];
228  char message_body [1024];
229  char message_header [50];
230  char message_footer [10];
231  char my_buffer [1024];
232  int length;
233 
234  memset(message_whole, 0, sizeof(message_whole));
235  memset(message_body, 0, sizeof(message_body));
236  memset(message_header, 0, sizeof(message_header));
237  memset(message_footer, 0, sizeof(message_footer));
238 
239  if (emi_fill_ucp60_login(message_body, smsc->emi_username, smsc->emi_password) < 0) {
240  error(0, "emi_fill_ucp60_login failed");
241  return -1;
242  }
243 
244  length = strlen(message_body);
245  length += 13; /* header (fixed) */
246  length += 2; /* footer (fixed) */
247  length += 2; /* slashes between header, body, footer */
248 
249  sprintf(message_header, "%02i/%05i/O/60",
250  (smsc->emi_current_msg_number++ % 100), length);
251 
252  /* FOOTER */
253 
254  sprintf(my_buffer, "%s/%s/", message_header, message_body);
255  generate_checksum((unsigned char *)my_buffer, (unsigned char *)message_footer);
256 
257  sprintf(message_whole, "\x02%s/%s/%s\x03", message_header,
258  message_body, message_footer);
259 
260  debug("bb.sms.emi", 0, "final UCP60 msg: <%s>", message_whole);
261 
262  put_data(smsc, message_whole, strlen(message_whole), 0);
263 
264  if (!wait_for_ack(smsc, 60)) {
265  info(0, "emi_open_session: wait for ack failed!");
266  return -1;
267  }
268 
269  return 0;
270 }
271 
272 
273 /*******************************************************
274  * the actual protocol open... quite simple here */
275 
277 {
278  smsc->emi_fd =
280  smsc->emi_port, smsc->emi_our_port,
281  NULL);
282  /* XXX add interface_name if required */
283  if (smsc->emi_fd < 0)
284  return -1;
285 
286  if (smsc->emi_username && smsc->emi_password) {
287  return emi_open_session(smsc);
288  }
289 
290  return 0;
291 }
292 
293 
295 {
296  emi_close_ip(smsc);
297 
298  return emi_open_connection_ip(smsc);
299 }
300 
301 
303 {
304 
305  if (smsc->emi_fd == -1) {
306  info(0, "Trying to close already closed EMI, ignoring");
307  return 0;
308  }
309  close(smsc->emi_fd);
310  smsc->emi_fd = -1;
311 
312  return 0;
313 }
314 
315 
316 /******************************************************************************
317 * Check if the buffers contain any messages
318 */
320 {
321 
322  char *tmpbuff;
323  int n = 0;
324  /* time_t timenow; */
325 
326  /* Block until we have a connection */
327  guarantee_link(smsc);
328 
329  /* If we have MO-message, then act (return 1) */
330  if (memorybuffer_has_rawmessage(smsc, 52, 'O') > 0 ||
331  memorybuffer_has_rawmessage(smsc, 1, 'O') > 0 )
332  return 1;
333 
334  tmpbuff = gw_malloc(10 * 1024);
335  memset(tmpbuff, 0, 10*1024);
336 
337  /* check for data */
338  n = get_data(smsc, tmpbuff, 10 * 1024);
339  if (n > 0)
340  memorybuffer_insert_data(smsc, tmpbuff, n);
341 
342  /* delete all ACKs/NACKs/whatever */
343  while (memorybuffer_has_rawmessage(smsc, 51, 'R') > 0 ||
344  memorybuffer_has_rawmessage(smsc, 1, 'R') > 0)
345  memorybuffer_cut_rawmessage(smsc, tmpbuff, 10*1024);
346 
347  gw_free(tmpbuff);
348 
349  /* If we have MO-message, then act (return 1) */
350 
351  if (memorybuffer_has_rawmessage(smsc, 52, 'O') > 0 ||
352  memorybuffer_has_rawmessage(smsc, 1, 'O') > 0)
353  return 1;
354 
355  /*
356  time(&timenow);
357  if( (smsc->emi_last_spoke + 60*20) < timenow) {
358  time(&smsc->emi_last_spoke);
359  }
360  */
361 
362  return 0;
363 
364 }
365 
366 
367 
368 
369 /******************************************************************************
370  * Submit (send) a Mobile Terminated message to the EMI server
371  */
372 int emi_submit_msg(SMSCenter *smsc, Msg *omsg)
373 {
374  char *tmpbuff = NULL;
375 
376  if (smsc == NULL) goto error;
377  if (omsg == NULL) goto error;
378 
379  tmpbuff = gw_malloc(10 * 1024);
380  memset(tmpbuff, 0, 10*1024);
381 
382  if (parse_msg_to_rawmessage(smsc, omsg, tmpbuff, 10*1024) < 1)
383  goto error;
384 
385  if (put_data(smsc, tmpbuff, strlen(tmpbuff), 0) < 0) {
386  info(0, "put_data failed!");
387  goto error;
388  }
389 
390  wait_for_ack(smsc, 51);
391 
392  /* smsc->emi_current_msg_number += 1; */
393  debug("bb.sms.emi", 0, "Submit Ok...");
394 
395  gw_free(tmpbuff);
396  return 0;
397 
398 error:
399  debug("bb.sms.emi", 0, "Submit Error...");
400 
401  gw_free(tmpbuff);
402  return -1;
403 }
404 
405 /******************************************************************************
406 * Receive a Mobile Terminated message to the EMI server
407 */
408 int emi_receive_msg(SMSCenter *smsc, Msg **tmsg)
409 {
410  char *tmpbuff;
411  Msg *msg = NULL;
412 
413  *tmsg = NULL;
414 
415  tmpbuff = gw_malloc(10 * 1024);
416  memset(tmpbuff, 0, 10*1024);
417 
418  /* get and delete message from buffer */
419  memorybuffer_cut_rawmessage(smsc, tmpbuff, 10*1024);
420  parse_rawmessage_to_msg(smsc, &msg, tmpbuff, strlen(tmpbuff));
421 
422  /* yeah yeah, I got the message... */
423  acknowledge_from_rawmessage(smsc, tmpbuff, strlen(tmpbuff));
424 
425  /* return with the joyful news */
426  gw_free(tmpbuff);
427 
428  if (msg == NULL) goto error;
429 
430  *tmsg = msg;
431 
432  return 1;
433 
434 error:
435  gw_free(tmpbuff);
436  msg_destroy(msg);
437  return -1;
438 }
439 
440 
441 /******************************************************************************
442 * Internal functions
443 */
444 
445 
446 /******************************************************************************
447 * Guarantee that we have a link
448 */
449 static int guarantee_link(SMSCenter *smsc)
450 {
451  int need_to_connect = 0;
452 
453  /* If something is obviously wrong. */
454  if (strstr(smsc->buffer, "OK")) need_to_connect = 1;
455  if (strstr(smsc->buffer, "NO CARRIER")) need_to_connect = 1;
456  if (strstr(smsc->buffer, "NO DIALTONE")) need_to_connect = 1;
457 
458  /* Clear the buffer */
459  while (need_to_connect) {
460  /* Connect */
461  need_to_connect = emi_open_connection(smsc) < 0;
462 
463  /* Clear the buffer so that the next call to guarantee
464  doesn't find the "NO CARRIER" string again. */
465  smsc->buflen = 0;
466  memset(smsc->buffer, 0, smsc->bufsize);
467  }
468 
469  return 0;
470 }
471 
472 static int at_dial(char *device, char *phonenum, char *at_prefix, time_t how_long)
473 {
474  char tmpbuff[1024];
475  int howmanyread = 0;
476  int thistime = 0;
477  int redial;
478  int fd = -1;
479  int ret;
480  time_t timestart;
481  struct termios tios;
482 
483  /* The time at the start of the function is used when
484  determining whether we have used up our allotted
485  dial time and have to abort. */
486  time(&timestart);
487 
488  /* Open the device properly. Remember to set the
489  access codes correctly. */
490  fd = open(device, O_RDWR | O_NONBLOCK | O_NOCTTY);
491  if (fd == -1) {
492  error(errno, "at_dial: error opening character device <%s>", device);
493  goto error;
494  }
495  tcflush(fd, TCIOFLUSH);
496 
497  /* The speed initialisation is pretty important. */
498  tcgetattr(fd, &tios);
499 #if defined(B115200)
500  cfsetospeed(&tios, B115200);
501  cfsetispeed(&tios, B115200);
502 #elif defined(B76800)
503  cfsetospeed(&tios, B76800);
504  cfsetispeed(&tios, B76800);
505 #elif defined(B57600)
506  cfsetospeed(&tios, B57600);
507  cfsetispeed(&tios, B57600);
508 #elif defined(B38400)
509  cfsetospeed(&tios, B38400);
510  cfsetispeed(&tios, B38400);
511 #elif defined(B19200)
512  cfsetospeed(&tios, B19200);
513  cfsetispeed(&tios, B19200);
514 #elif defined(B9600)
515  cfsetospeed(&tios, B9600);
516  cfsetispeed(&tios, B9600);
517 #endif
518  kannel_cfmakeraw(&tios);
519  tios.c_cflag |= (HUPCL | CREAD | CRTSCTS);
520  ret = tcsetattr(fd, TCSANOW, &tios);
521  if (ret == -1) {
522  error(errno, "EMI[X25]: at_dial: fail to set termios attribute");
523  }
524 
525  /* Dial using an AT command string. */
526  for (redial = 1; redial; ) {
527  info(0, "at_dial: dialing <%s> on <%s> for <%i> seconds",
528  phonenum, device,
529  (int)(how_long - (time(NULL) - timestart)));
530 
531  /* Send AT dial request. */
532  howmanyread = 0;
533  sprintf(tmpbuff, "%s%s\r\n", at_prefix, phonenum);
534  ret = write(fd, tmpbuff, strlen(tmpbuff)); /* errors... -mg */
535  memset(&tmpbuff, 0, sizeof(tmpbuff));
536 
537  /* Read the answer to the AT command and react accordingly. */
538  for (; ; ) {
539  /* We don't want to dial forever */
540  if (how_long != 0 && time(NULL) > timestart + how_long)
541  goto timeout;
542 
543  /* We don't need more space for dialout */
544  if (howmanyread >= (int) sizeof(tmpbuff))
545  goto error;
546 
547  /* We read 1 char a time so that we don't
548  accidentally read past the modem chat and
549  into the SMSC datastream -mg */
550  thistime = read(fd, &tmpbuff[howmanyread], 1);
551  if (thistime == -1) {
552  if (errno == EAGAIN) continue;
553  if (errno == EINTR) continue;
554  goto error;
555  } else {
556  howmanyread += thistime;
557  }
558 
559  /* Search for the newline on the AT status line. */
560  if (tmpbuff[howmanyread - 1] == '\r'
561  || tmpbuff[howmanyread - 1] == '\n') {
562 
563  /* XXX ADD ALL POSSIBLE CHAT STRINGS XXX */
564 
565  if (strstr(tmpbuff, "CONNECT") != NULL) {
566  debug("bb.sms.emi", 0, "at_dial: CONNECT");
567  redial = 0;
568  break;
569 
570  } else if (strstr(tmpbuff, "NO CARRIER") != NULL) {
571  debug("bb.sms.emi", 0, "at_dial: NO CARRIER");
572  redial = 1;
573  break;
574 
575  } else if (strstr(tmpbuff, "BUSY") != NULL) {
576  debug("bb.sms.emi", 0, "at_dial: BUSY");
577  redial = 1;
578  break;
579 
580  } else if (strstr(tmpbuff, "NO DIALTONE") != NULL) {
581  debug("bb.sms.emi", 0, "at_dial: NO DIALTONE");
582  redial = 1;
583  break;
584 
585  }
586 
587  } /* End of if lastchr=='\r'||'\n'. */
588 
589  /* Thou shall not consume all system resources
590  by repeatedly looping a strstr search when
591  the string update latency is very high as it
592  is in serial communication. -mg */
593  usleep(1000);
594 
595  } /* End of read loop. */
596 
597  /* Thou shall not flood the modem with dial requests. -mg */
598  sleep(1);
599 
600  } /* End of dial loop. */
601 
602  debug("bb.sms.emi", 0, "at_dial: done with dialing");
603  return fd;
604 
605 timeout:
606  error(0, "at_dial timed out");
607  close(fd);
608  return -1;
609 
610 error:
611  error(0, "at_dial failed");
612  close(fd);
613  return -1;
614 }
615 
616 /******************************************************************************
617  * Wait for an ACK or NACK from the remote
618  *
619  * REQUIRED by the protocol that it must be waited...
620  */
621 static int wait_for_ack(SMSCenter *smsc, int op_type)
622 {
623  char *tmpbuff;
624  int found = 0;
625  int n;
626  time_t start;
627 
628  tmpbuff = gw_malloc(10 * 1024);
629  memset(tmpbuff, 0, 10*1024);
630  start = time(NULL);
631  do {
632  /* check for data */
633  n = get_data(smsc, tmpbuff, 1024 * 10);
634 
635  /* At least the X.31 interface wants to append the data.
636  Kalle, what about the TCP/IP interface? Am I correct
637  that you are assuming that the message arrives in a
638  single read(2)? -mg */
639  if (n > 0)
640  memorybuffer_append_data(smsc, tmpbuff, n);
641 
642  /* act on data */
643  if (memorybuffer_has_rawmessage(smsc, op_type, 'R') > 0) {
644  memorybuffer_cut_rawmessage(smsc, tmpbuff, 10*1024);
645  debug("bb.sms.emi", 0, "Found ACK/NACK: <%s>", tmpbuff);
646  found = 1;
647  }
648  } while (!found && ((time(NULL) - start) < 5));
649 
650  gw_free(tmpbuff);
651  return found;
652 }
653 
654 
655 /******************************************************************************
656  * Get the modem buffer data to buff, return the amount read
657  *
658  * Reads from main fd, but also from backup-fd - does accept if needed
659  */
660 static int get_data(SMSCenter *smsc, char *buff, int length)
661 {
662  int n = 0;
663 
664  struct sockaddr_in client_addr;
665  socklen_t client_addr_len;
666 
667  fd_set rf;
668  struct timeval to;
669  int ret;
670 
671  memset(buff, 0, length);
672 
673  if (smsc->type == SMSC_TYPE_EMI_X25) {
674  tcdrain(smsc->emi_fd);
675  n = read(smsc->emi_fd, buff, length);
676  return n;
677  }
678 
679  FD_ZERO(&rf);
680  if (smsc->emi_fd >= 0) FD_SET(smsc->emi_fd, &rf);
681  if (smsc->emi_secondary_fd >= 0) FD_SET(smsc->emi_secondary_fd, &rf);
682  if (smsc->emi_backup_fd > 0) FD_SET(smsc->emi_backup_fd, &rf);
683 
684  FD_SET(0, &rf);
685  to.tv_sec = 0;
686  to.tv_usec = 100;
687 
688  ret = select(FD_SETSIZE, &rf, NULL, NULL, &to);
689 
690  if (ret > 0) {
691  if (smsc->emi_secondary_fd >= 0 && FD_ISSET(smsc->emi_secondary_fd, &rf)) {
692  n = read(smsc->emi_secondary_fd, buff, length - 1);
693 
694  if (n == -1) {
695  error(errno, "Error - Secondary socket closed");
696  close(smsc->emi_secondary_fd);
697  smsc->emi_secondary_fd = -1;
698  } else if (n == 0) {
699  info(0, "Secondary socket closed by SMSC");
700  close(smsc->emi_secondary_fd);
701  smsc->emi_secondary_fd = -1;
702  } else { /* UGLY! We put 'X' after message */
703  buff[n] = 'X'; /* if it is from secondary fd!!! */
704  n++;
705  }
706  } else if (smsc->emi_fd >= 0 && FD_ISSET(smsc->emi_fd, &rf)) {
707  n = read(smsc->emi_fd, buff, length);
708  if (n == 0) {
709  close(smsc->emi_fd);
710  info(0, "Main EMI socket closed by SMSC");
711  smsc->emi_fd = -1; /* ready to be re-opened */
712  }
713  }
714  if ((smsc->emi_backup_fd > 0) && FD_ISSET(smsc->emi_backup_fd, &rf)) {
715  if (smsc->emi_secondary_fd == -1) {
716  Octstr *ip, *allow;
717 
718  smsc->emi_secondary_fd = accept(smsc->emi_backup_fd,
719  (struct sockaddr *)&client_addr, &client_addr_len);
720 
721  ip = host_ip(client_addr);
722  if (smsc->emi_backup_allow_ip == NULL)
723  allow = NULL;
724  else
725  allow = octstr_create(smsc->emi_backup_allow_ip);
726  if (is_allowed_ip(allow, octstr_imm("*.*.*.*"), ip) == 0) {
727  info(0, "SMSC secondary connection tried from <%s>, "
728  "disconnected",
729  octstr_get_cstr(ip));
730  octstr_destroy(ip);
731  octstr_destroy(allow);
732  close(smsc->emi_secondary_fd);
733  smsc->emi_secondary_fd = -1;
734  return 0;
735  }
736  info(0, "Secondary socket opened by SMSC from <%s>",
737  octstr_get_cstr(ip));
738  octstr_destroy(ip);
739  octstr_destroy(allow);
740  } else
741  info(0, "New connection request while old secondary is open!");
742  }
743  }
744  if (n > 0) {
745  debug("bb.sms.emi", 0, "get_data:Read %d bytes: <%.*s>", n, n, buff);
746  debug("bb.sms.emi", 0, "get_data:smsc->buffer == <%s>", smsc->buffer);
747  }
748  return n;
749 
750 }
751 
752 /******************************************************************************
753 * Put the buff data to the modem buffer, return the amount of data put
754 */
755 static int put_data(SMSCenter *smsc, char *buff, int length, int is_backup)
756 {
757  size_t len = length;
758  int ret;
759  int fd = -1;
760 
761  fd = smsc->emi_fd;
762  tcdrain(smsc->emi_fd);
763 
764  /* Write until all data has been successfully written to the fd. */
765  while (len > 0) {
766  ret = write(fd, buff, len);
767  if (ret == -1) {
768  if (errno == EINTR) continue;
769  if (errno == EAGAIN) continue;
770  error(errno, "Writing to fd failed");
771  return -1;
772  }
773  /* ret may be less than len, if the writing
774  was interrupted by a signal. */
775  len -= ret;
776  buff += ret;
777  }
778 
779  if (smsc->type == SMSC_TYPE_EMI_X25) {
780  /* Make sure the data gets written immediately.
781  Wait a while just to add some latency so
782  that the modem (or the UART) doesn't choke
783  on the data. */
784  tcdrain(smsc->emi_fd);
785  usleep(1000);
786  }
787 
788  return 0;
789 }
790 
791 /******************************************************************************
792 * Append the buff data to smsc->buffer
793 */
794 static int memorybuffer_append_data(SMSCenter *smsc, char *buff, int length)
795 {
796  while (smsc->bufsize < (smsc->buflen + length)) { /* buffer too small */
797  char *p = gw_realloc(smsc->buffer, smsc->bufsize * 2);
798  smsc->buffer = p;
799  smsc->bufsize *= 2;
800  }
801 
802  memcpy(smsc->buffer + smsc->buflen, buff, length);
803  smsc->buflen += length;
804  return 0;
805 
806 }
807 
808 /******************************************************************************
809 * Insert (put to head) the buff data to smsc->buffer
810 */
811 static int memorybuffer_insert_data(SMSCenter *smsc, char *buff, int length)
812 {
813  while (smsc->bufsize < (smsc->buflen + length)) { /* buffer too small */
814  char *p = gw_realloc(smsc->buffer, smsc->bufsize * 2);
815  smsc->buffer = p;
816  smsc->bufsize *= 2;
817  }
818  memmove(smsc->buffer + length, smsc->buffer, smsc->buflen);
819  memcpy(smsc->buffer, buff, length);
820  smsc->buflen += length;
821  return 0;
822 
823 }
824 
825 /******************************************************************************
826 * Check the smsc->buffer for a raw STX...ETX message
827 */
828 static int memorybuffer_has_rawmessage(SMSCenter *smsc, int type, char auth)
829 {
830  char tmpbuff[1024], tmpbuff2[1024];
831  char *stx, *etx;
832 
833  stx = memchr(smsc->buffer, '\2', smsc->buflen);
834  etx = memchr(smsc->buffer, '\3', smsc->buflen);
835 
836  if (stx && etx && stx < etx) {
837  strncpy(tmpbuff, stx, etx - stx + 1);
838  tmpbuff[etx - stx + 1] = '\0';
839  if (auth)
840  sprintf(tmpbuff2, "/%c/%02i/", auth, type);
841  else
842  sprintf(tmpbuff2, "/%02i/", type);
843 
844  if (strstr(tmpbuff, tmpbuff2) != NULL) {
845  debug("bb.sms.emi", 0, "found message <%c/%02i>...msg <%s>", auth, type, tmpbuff);
846  return 1;
847  }
848  }
849  return 0;
850 
851 }
852 
853 /******************************************************************************
854 * Cut the first raw message from the smsc->buffer
855 * and put it in buff, return success 0, failure -1
856 */
857 static int memorybuffer_cut_rawmessage(SMSCenter *smsc, char *buff, int length)
858 {
859 
860  char *stx, *etx;
861  int size_of_cut_piece;
862 
863  /* We don't check for NULLs since we're sure that nobody has fooled
864  around with smsc->buffer since has_rawmessage was last called... */
865 
866  stx = memchr(smsc->buffer, '\2', smsc->buflen);
867  etx = memchr(smsc->buffer, '\3', smsc->buflen);
868 
869  if (*(etx + 1) == 'X') /* secondary! UGLY KLUDGE */
870  etx++;
871 
872  size_of_cut_piece = (etx - stx) + 1;
873 
874  if (length < size_of_cut_piece) {
875  error(0, "the buffer you provided for cutting was too small");
876  return -1;
877  }
878 
879  /* move the part before our magic rawmessage to the safe house */
880  memcpy(buff, stx, size_of_cut_piece);
881  buff[size_of_cut_piece] = '\0'; /* NULL-terminate */
882 
883  /* move the stuff in membuffer one step down */
884  memmove(stx, etx + 1, (smsc->buffer + smsc->bufsize) - stx );
885 
886  smsc->buflen -= size_of_cut_piece;
887 
888  return 0;
889 
890 }
891 
892 /******************************************************************************
893 * Parse the raw message to the Msg structure
894 */
896  char *rawmessage, int length)
897 {
898 
899  char emivars[128][1024];
900  char *leftslash, *rightslash;
901  char isotext[2048];
902  int msgnbr;
903  int tmpint;
904 
905  msgnbr = -1;
906 
907  memset(isotext, 0, sizeof(isotext));
908 
909  strncpy(isotext, rawmessage, length);
910  leftslash = isotext;
911 
912  for (tmpint = 0; leftslash != NULL; tmpint++) {
913  rightslash = strchr(leftslash + 1, '/');
914 
915  if (rightslash == NULL)
916  rightslash = strchr(leftslash + 1, '\3');
917 
918  if (rightslash == NULL)
919  break;
920 
921  *rightslash = '\0';
922  strcpy(emivars[tmpint], leftslash + 1);
923  leftslash = rightslash;
924  }
925 
926  if (strcmp(emivars[3], "01") == 0) {
927  if (strcmp(emivars[7], "2") == 0) {
928  strcpy(isotext, emivars[8]);
929  } else if (strcmp(emivars[7], "3") == 0) {
930  parse_emi_to_iso88591(emivars[8], isotext, sizeof(isotext),
931  smsc->alt_charset);
932  } else {
933  error(0, "Unknown 01-type EMI SMS (%s)", emivars[7]);
934  strcpy(isotext, "");
935  }
936  } else if (strcmp(emivars[3], "51") == 0) {
937  parse_emi_to_iso88591(emivars[24], isotext, sizeof(isotext),
938  smsc->alt_charset);
939  } else if (strcmp(emivars[3], "52") == 0) {
940  parse_emi_to_iso88591(emivars[24], isotext, sizeof(isotext),
941  smsc->alt_charset);
942  } else {
943  error(0, "HEY WE SHOULD NOT BE HERE!! Type = %s", emivars[3]);
944  strcpy(isotext, "");
945  }
946 
947  *msg = msg_create(sms);
948  if (*msg == NULL) goto error;
949 
950  (*msg)->sms.sender = octstr_create(emivars[5]);
951  (*msg)->sms.receiver = octstr_create(emivars[4]);
952  (*msg)->sms.msgdata = octstr_create(isotext);
953  (*msg)->sms.udhdata = NULL;
954 
955  return msgnbr;
956 
957 error:
958  return -1;
959 }
960 
961 /*
962  * notify the SMSC that we got the message
963  */
965  char *rawmessage, int length)
966 {
967 
968  char emivars[128][1024];
969  char timestamp[2048], sender[2048], receiver[2048];
970  char emitext[2048], isotext[2048];
971  char *leftslash, *rightslash;
972  int msgnbr;
973  int tmpint;
974  int is_backup = 0;
975 
976  msgnbr = -1;
977  memset(&sender, 0, sizeof(sender));
978  memset(&receiver, 0, sizeof(receiver));
979  memset(&emitext, 0, sizeof(emitext));
980  memset(&isotext, 0, sizeof(isotext));
981  memset(&timestamp, 0, sizeof(timestamp));
982 
983  strncpy(isotext, rawmessage, length);
984  leftslash = isotext;
985 
986  if (isotext[length - 1] == 'X')
987  is_backup = 1;
988 
989  for (tmpint = 0; leftslash != NULL; tmpint++) {
990  rightslash = strchr(leftslash + 1, '/');
991 
992  if (rightslash == NULL)
993  rightslash = strchr(leftslash + 1, '\3');
994 
995  if (rightslash == NULL)
996  break;
997 
998  *rightslash = '\0';
999  strcpy(emivars[tmpint], leftslash + 1);
1000  leftslash = rightslash;
1001  }
1002 
1003  /* BODY */
1004  sprintf(isotext, "A//%s:%s", emivars[4], emivars[18]);
1005  sprintf(isotext, "A//%s:", emivars[5]);
1006  is_backup = 0;
1007 
1008  /* HEADER */
1009 
1010  debug("bb.sms.emi", 0, "acknowledge: type = '%s'", emivars[3]);
1011 
1012  sprintf(emitext, "%s/%05i/%s/%s", emivars[0], (int) strlen(isotext) + 17,
1013  "R", emivars[3]);
1014 
1015  smsc->emi_current_msg_number = atoi(emivars[0]) + 1;
1016 
1017  /* FOOTER */
1018  sprintf(timestamp, "%s/%s/", emitext, isotext);
1019  generate_checksum((unsigned char *)timestamp, (unsigned char *)receiver);
1020 
1021  sprintf(sender, "%c%s/%s/%s%c", 0x02, emitext, isotext, receiver, 0x03);
1022  put_data(smsc, sender, strlen(sender), is_backup);
1023 
1024  return msgnbr;
1025 
1026 }
1027 
1028 
1029 /******************************************************************************
1030 * Parse the Msg structure to the raw message format
1031 */
1032 static int parse_msg_to_rawmessage(SMSCenter *smsc, Msg *msg, char *rawmessage, int rawmessage_length)
1033 {
1034  char message_whole[10*1024];
1035  char message_body[10*1024];
1036  char message_header[1024];
1037  char message_footer[1024];
1038 
1039  char my_buffer[10*1024];
1040  char my_buffer2[10*1024];
1041  char msgtext[1024];
1042  int length;
1043  char mt;
1044  char mcl[20];
1045  char snumbits[20];
1046  char xser[1024];
1047  int udh_len;
1048 
1049  memset(&message_whole, 0, sizeof(message_whole));
1050  memset(&message_body, 0, sizeof(message_body));
1051  memset(&message_header, 0, sizeof(message_header));
1052  memset(&message_footer, 0, sizeof(message_footer));
1053  memset(&my_buffer, 0, sizeof(my_buffer));
1054  memset(&my_buffer2, 0, sizeof(my_buffer2));
1055  mt = '3';
1056  memset(&snumbits, 0, sizeof(snumbits));
1057  memset(&xser, 0, sizeof(xser));
1058 
1059  /* XXX parse_iso88591_to_emi shouldn't use NUL terminated
1060  * strings, but Octstr directly, or a char* and a length.
1061  */
1062  if (octstr_len(msg->sms.udhdata)) {
1063  char xserbuf[258];
1064  /* we need a properly formated UDH here, there first byte contains his length
1065  * this will be formatted in the xser field of the EMI Protocol
1066  */
1067  udh_len = octstr_get_char(msg->sms.udhdata, 0) + 1;
1068  xserbuf[0] = 1;
1069  xserbuf[1] = udh_len;
1070  octstr_get_many_chars(&xserbuf[2], msg->sms.udhdata, 0, udh_len);
1071  parse_binary_to_emi(xserbuf, xser, udh_len + 2);
1072  } else {
1073  udh_len = 0;
1074  }
1075 
1076  if (msg->sms.coding == DC_7BIT || msg->sms.coding == DC_UNDEF) {
1077  octstr_get_many_chars(msgtext, msg->sms.msgdata, 0, octstr_len(msg->sms.msgdata));
1078  msgtext[octstr_len(msg->sms.msgdata)] = '\0';
1079  parse_iso88591_to_emi(msgtext, my_buffer2,
1080  octstr_len(msg->sms.msgdata),
1081  smsc->alt_charset);
1082 
1083  strcpy(snumbits, "");
1084  mt = '3';
1085  strcpy(mcl, "");
1086  } else {
1087  octstr_get_many_chars(msgtext, msg->sms.msgdata, 0, octstr_len(msg->sms.msgdata));
1088 
1089  parse_binary_to_emi(msgtext, my_buffer2, octstr_len(msg->sms.msgdata));
1090 
1091  sprintf(snumbits, "%04ld", octstr_len(msg->sms.msgdata)*8);
1092  mt = '4';
1093  strcpy(mcl, "1");
1094  }
1095 
1096  /* XXX Where is DCS ? Is it in XSER like in emi2 ?
1097  * Please someone encode it with fields_to_dcs
1098  */
1099 
1100  sprintf(message_body,
1101  "%s/%s/%s/%s/%s//%s////////////%c/%s/%s////%s//////%s//",
1102  octstr_get_cstr(msg->sms.receiver),
1103  msg->sms.sender ? octstr_get_cstr(msg->sms.sender) : "",
1104  "",
1105  "",
1106  "",
1107  "0100",
1108  mt,
1109  snumbits,
1110  my_buffer2,
1111  mcl,
1112  xser);
1113 
1114  /* HEADER */
1115 
1116  length = strlen(message_body);
1117  length += 13; /* header (fixed) */
1118  length += 2; /* footer (fixed) */
1119  length += 2; /* slashes between header, body, footer */
1120 
1121  sprintf(message_header, "%02i/%05i/%s/%s", (smsc->emi_current_msg_number++ % 100), length, "O", "51");
1122 
1123  /* FOOTER */
1124 
1125  sprintf(my_buffer, "%s/%s/", message_header, message_body);
1126  generate_checksum((unsigned char *)my_buffer, (unsigned char *)message_footer);
1127 
1128  sprintf(message_whole, "%c%s/%s/%s%c", 0x02, message_header, message_body, message_footer, 0x03);
1129 
1130  strncpy(rawmessage, message_whole, rawmessage_length);
1131 
1132  if (smsc->type == SMSC_TYPE_EMI_X25) {
1133  /* IC3S braindead EMI stack chokes on this... must fix it at the next time... */
1134  strcat(rawmessage, "\r");
1135  }
1136  debug("bb.sms.emi", 0, "emi %d message %s",
1137  smsc->emi_current_msg_number, rawmessage);
1138  return strlen(rawmessage);
1139 }
1140 
1141 /******************************************************************************
1142 * Parse the data from the two byte EMI code to normal ISO-8869-1
1143 */
1144 static int parse_emi_to_iso88591(char *from, char *to, int length,
1145  int alt_charset)
1146 {
1147  int hmtg = 0;
1148  unsigned int mychar;
1149  char tmpbuff[128];
1150 
1151  for (hmtg = 0; hmtg <= (int)strlen(from); hmtg += 2) {
1152  strncpy(tmpbuff, from + hmtg, 2);
1153  sscanf(tmpbuff, "%x", &mychar);
1154  to[hmtg / 2] = char_sms_to_iso(mychar, alt_charset);
1155  }
1156 
1157  to[(hmtg / 2)-1] = '\0';
1158 
1159  return 0;
1160 
1161 }
1162 
1163 /******************************************************************************
1164 * Parse the data from normal ISO-8869-1 to the two byte EMI code
1165 */
1166 static int parse_iso88591_to_emi(char *from, char *to,
1167  int length, int alt_charset)
1168 {
1169  char buf[10];
1170  unsigned char tmpchar;
1171  char *ptr;
1172 
1173  if (!from || !to || length <= 0)
1174  return -1;
1175 
1176  *to = '\0';
1177 
1178  debug("bb.sms.emi", 0, "emi parsing <%s> to emi, length %d", from, length);
1179 
1180  for (ptr = from; length > 0; ptr++, length--) {
1181  tmpchar = char_iso_to_sms(*ptr, alt_charset);
1182  sprintf(buf, "%02X", tmpchar);
1183  strncat(to, buf, 2);
1184  }
1185  return 0;
1186 }
1187 
1188 /******************************************************************************
1189 * Parse the data from binary to the two byte EMI code
1190 */
1191 static int parse_binary_to_emi(char *from, char *to, int length)
1192 {
1193  char buf[10];
1194  char *ptr;
1195 
1196  if (!from || !to || length <= 0)
1197  return -1;
1198 
1199  *to = '\0';
1200 
1201  for (ptr = from; length > 0; ptr++, length--) {
1202  sprintf(buf, "%02X", (unsigned char)*ptr);
1203  strncat(to, buf, 2);
1204  }
1205 
1206  return 0;
1207 }
1208 
1209 
1210 /******************************************************************************
1211 * Generate the EMI message checksum
1212 */
1213 static void generate_checksum(const unsigned char *buf, unsigned char *out)
1214 {
1215  const unsigned char *p;
1216  int j;
1217 
1218  j = 0;
1219  for (p = buf; *p != '\0'; p++) {
1220  j += *p;
1221 
1222  if (j >= 256)
1223  j -= 256;
1224  }
1225 
1226  sprintf((char *)out, "%02X", j);
1227 }
1228 
1229 
1230 
1231 /******************************************************************************
1232 * Translate character from iso to emi_mt
1233 * PGrnholm
1234 */
1235 static char char_iso_to_sms(unsigned char from, int alt_charset)
1236 {
1237 
1238  switch ((char)from) {
1239 
1240  case 'A':
1241  return 0x41;
1242  case 'B':
1243  return 0x42;
1244  case 'C':
1245  return 0x43;
1246  case 'D':
1247  return 0x44;
1248  case 'E':
1249  return 0x45;
1250  case 'F':
1251  return 0x46;
1252  case 'G':
1253  return 0x47;
1254  case 'H':
1255  return 0x48;
1256  case 'I':
1257  return 0x49;
1258  case 'J':
1259  return 0x4A;
1260  case 'K':
1261  return 0x4B;
1262  case 'L':
1263  return 0x4C;
1264  case 'M':
1265  return 0x4D;
1266  case 'N':
1267  return 0x4E;
1268  case 'O':
1269  return 0x4F;
1270  case 'P':
1271  return 0x50;
1272  case 'Q':
1273  return 0x51;
1274  case 'R':
1275  return 0x52;
1276  case 'S':
1277  return 0x53;
1278  case 'T':
1279  return 0x54;
1280  case 'U':
1281  return 0x55;
1282  case 'V':
1283  return 0x56;
1284  case 'W':
1285  return 0x57;
1286  case 'X':
1287  return 0x58;
1288  case 'Y':
1289  return 0x59;
1290  case 'Z':
1291  return 0x5A;
1292 
1293  case 'a':
1294  return 0x61;
1295  case 'b':
1296  return 0x62;
1297  case 'c':
1298  return 0x63;
1299  case 'd':
1300  return 0x64;
1301  case 'e':
1302  return 0x65;
1303  case 'f':
1304  return 0x66;
1305  case 'g':
1306  return 0x67;
1307  case 'h':
1308  return 0x68;
1309  case 'i':
1310  return 0x69;
1311  case 'j':
1312  return 0x6A;
1313  case 'k':
1314  return 0x6B;
1315  case 'l':
1316  return 0x6C;
1317  case 'm':
1318  return 0x6D;
1319  case 'n':
1320  return 0x6E;
1321  case 'o':
1322  return 0x6F;
1323  case 'p':
1324  return 0x70;
1325  case 'q':
1326  return 0x71;
1327  case 'r':
1328  return 0x72;
1329  case 's':
1330  return 0x73;
1331  case 't':
1332  return 0x74;
1333  case 'u':
1334  return 0x75;
1335  case 'v':
1336  return 0x76;
1337  case 'w':
1338  return 0x77;
1339  case 'x':
1340  return 0x78;
1341  case 'y':
1342  return 0x79;
1343  case 'z':
1344  return 0x7A;
1345 
1346  case '0':
1347  return 0x30;
1348  case '1':
1349  return 0x31;
1350  case '2':
1351  return 0x32;
1352  case '3':
1353  return 0x33;
1354  case '4':
1355  return 0x34;
1356  case '5':
1357  return 0x35;
1358  case '6':
1359  return 0x36;
1360  case '7':
1361  return 0x37;
1362  case '8':
1363  return 0x38;
1364  case '9':
1365  return 0x39;
1366  case ':':
1367  return 0x3A;
1368  case ';':
1369  return 0x3B;
1370  case '<':
1371  return 0x3C;
1372  case '=':
1373  return 0x3D;
1374  case '>':
1375  return 0x3E;
1376  case '?':
1377  return 0x3F;
1378 
1379  case '':
1380  return '[';
1381  case '':
1382  return '\\';
1383  case '':
1384  return 0x0E;
1385  case '':
1386  return ']';
1387  case '':
1388  return '{';
1389  case '':
1390  return '|';
1391  case '':
1392  return 0x0F;
1393  case '':
1394  return '}';
1395  case '':
1396  return '~';
1397  case '':
1398  return '^';
1399  case '':
1400  return 0x5F;
1401  case '':
1402  return 0x0C;
1403 
1404  /* case 'Delta': return 0x10; */
1405  /* case 'Fii': return 0x12; */
1406  /* case 'Lambda': return 0x13; */
1407  /* case 'Alpha': return 0x14; */
1408  /* case 'Omega': return 0x15; */
1409  /* case 'Pii': return 0x16; */
1410  /* case 'Pii': return 0x17; */
1411  /* case 'Delta': return 0x18; */
1412  /* case 'Delta': return 0x19; */
1413  /* case 'Delta': return 0x1A; */
1414 
1415  case ' ':
1416  return 0x20;
1417  case '@':
1418  if (alt_charset == EMI_SWAPPED_CHARS)
1419  return 0x00;
1420  else
1421  return 0x40;
1422  case '':
1423  return 0x01;
1424  case '$':
1425  return 0x24;
1426  case '':
1427  return 0x03;
1428  case '':
1429  return 0x04;
1430  case '':
1431  return 0x05;
1432  case '':
1433  return 0x06;
1434  case '':
1435  return 0x07;
1436  case '':
1437  return 0x08;
1438  case '':
1439  return 0x09;
1440  case '\r':
1441  return 0x0A;
1442  case '':
1443  return 0x0B;
1444  case '\n':
1445  return 0x0D;
1446  case '':
1447  return 0x1C;
1448  case '':
1449  return 0x1D;
1450  case '':
1451  return 0x1F;
1452 
1453  case '!':
1454  return 0x21;
1455  case '"':
1456  return 0x22;
1457  case '#':
1458  return 0x23;
1459  case '':
1460  return 0x02;
1461  case '%':
1462  return 0x25;
1463 
1464  case '&':
1465  return 0x26;
1466  case '\'':
1467  return 0x27;
1468  case '(':
1469  return 0x28;
1470  case ')':
1471  return 0x29;
1472  case '*':
1473  return 0x2A;
1474 
1475  case '+':
1476  return 0x2B;
1477  case ',':
1478  return 0x2C;
1479  case '-':
1480  return 0x2D;
1481  case '.':
1482  return 0x2E;
1483  case '/':
1484  return 0x2F;
1485 
1486  case '':
1487  return 0x60;
1488  case '':
1489  return 0x1E;
1490  case '':
1491  return 0x7F;
1492  case '':
1493  if (alt_charset == EMI_SWAPPED_CHARS)
1494  return 0x40;
1495  else
1496  return 0x00;
1497  case '_':
1498  return 0x11;
1499 
1500  default:
1501  return 0x20; /* space */
1502 
1503  } /* switch */
1504 }
1505 
1506 
1507 /******************************************************************************
1508 * Translate character from emi_mo to iso
1509 * PGrnholm
1510 */
1511 static char char_sms_to_iso(unsigned char from, int alt_charset)
1512 {
1513 
1514  switch ((int)from) {
1515 
1516  case 0x41:
1517  return 'A';
1518  case 0x42:
1519  return 'B';
1520  case 0x43:
1521  return 'C';
1522  case 0x44:
1523  return 'D';
1524  case 0x45:
1525  return 'E';
1526  case 0x46:
1527  return 'F';
1528  case 0x47:
1529  return 'G';
1530  case 0x48:
1531  return 'H';
1532  case 0x49:
1533  return 'I';
1534  case 0x4A:
1535  return 'J';
1536  case 0x4B:
1537  return 'K';
1538  case 0x4C:
1539  return 'L';
1540  case 0x4D:
1541  return 'M';
1542  case 0x4E:
1543  return 'N';
1544  case 0x4F:
1545  return 'O';
1546  case 0x50:
1547  return 'P';
1548  case 0x51:
1549  return 'Q';
1550  case 0x52:
1551  return 'R';
1552  case 0x53:
1553  return 'S';
1554  case 0x54:
1555  return 'T';
1556  case 0x55:
1557  return 'U';
1558  case 0x56:
1559  return 'V';
1560  case 0x57:
1561  return 'W';
1562  case 0x58:
1563  return 'X';
1564  case 0x59:
1565  return 'Y';
1566  case 0x5A:
1567  return 'Z';
1568 
1569  case 0x61:
1570  return 'a';
1571  case 0x62:
1572  return 'b';
1573  case 0x63:
1574  return 'c';
1575  case 0x64:
1576  return 'd';
1577  case 0x65:
1578  return 'e';
1579  case 0x66:
1580  return 'f';
1581  case 0x67:
1582  return 'g';
1583  case 0x68:
1584  return 'h';
1585  case 0x69:
1586  return 'i';
1587  case 0x6A:
1588  return 'j';
1589  case 0x6B:
1590  return 'k';
1591  case 0x6C:
1592  return 'l';
1593  case 0x6D:
1594  return 'm';
1595  case 0x6E:
1596  return 'n';
1597  case 0x6F:
1598  return 'o';
1599  case 0x70:
1600  return 'p';
1601  case 0x71:
1602  return 'q';
1603  case 0x72:
1604  return 'r';
1605  case 0x73:
1606  return 's';
1607  case 0x74:
1608  return 't';
1609  case 0x75:
1610  return 'u';
1611  case 0x76:
1612  return 'v';
1613  case 0x77:
1614  return 'w';
1615  case 0x78:
1616  return 'x';
1617  case 0x79:
1618  return 'y';
1619  case 0x7A:
1620  return 'z';
1621 
1622  case 0x30:
1623  return '0';
1624  case 0x31:
1625  return '1';
1626  case 0x32:
1627  return '2';
1628  case 0x33:
1629  return '3';
1630  case 0x34:
1631  return '4';
1632  case 0x35:
1633  return '5';
1634  case 0x36:
1635  return '6';
1636  case 0x37:
1637  return '7';
1638  case 0x38:
1639  return '8';
1640  case 0x39:
1641  return '9';
1642  case 0x3A:
1643  return ':';
1644  case 0x3B:
1645  return ';';
1646  case 0x3C:
1647  return '<';
1648  case 0x3D:
1649  return '=';
1650  case 0x3E:
1651  return '>';
1652  case 0x3F:
1653  return '?';
1654 
1655  case '[':
1656  return '';
1657  case '\\':
1658  return '';
1659  case '\xC5':
1660  return '';
1661  case ']':
1662  return '';
1663  case '{':
1664  return '';
1665  case '|':
1666  return '';
1667  case 0xE5:
1668  return '';
1669  case '}':
1670  return '';
1671  case '~':
1672  return '';
1673  case 0xA7:
1674  return '';
1675  case 0xD1:
1676  return '';
1677  case 0xF8:
1678  return '';
1679 
1680  /* case 'Delta': return 0x10; */
1681  /* case 'Fii': return 0x12; */
1682  /* case 'Lambda': return 0x13; */
1683  /* case 'Alpha': return 0x14; */
1684  /* case 'Omega': return 0x15; */
1685  /* case 'Pii': return 0x16; */
1686  /* case 'Pii': return 0x17; */
1687  /* case 'Delta': return 0x18; */
1688  /* case 'Delta': return 0x19; */
1689  /* case 'Delta': return 0x1A; */
1690 
1691  case 0x20:
1692  return ' ';
1693  case 0x40:
1694  return '@';
1695  case 0xA3:
1696  return '';
1697  case 0x24:
1698  return '$';
1699  case 0xA5:
1700  return '';
1701  case 0xE8:
1702  return '';
1703  case 0xE9:
1704  return '';
1705  case 0xF9:
1706  return '';
1707  case 0xEC:
1708  return '';
1709  case 0xF2:
1710  return '';
1711  case 0xC7:
1712  return '';
1713  case 0x0A:
1714  return '\r';
1715  case 0xD8:
1716  return '';
1717  case 0x0D:
1718  return '\n';
1719  case 0xC6:
1720  return '';
1721  case 0xE6:
1722  return '';
1723  case 0x1F:
1724  return '';
1725 
1726  case 0x21:
1727  return '!';
1728  case 0x22:
1729  return '"';
1730  case 0x23:
1731  return '#';
1732  case 0xA4:
1733  return '';
1734  case 0x25:
1735  return '%';
1736 
1737  case 0x26:
1738  return '&';
1739  case 0x27:
1740  return '\'';
1741  case 0x28:
1742  return '(';
1743  case 0x29:
1744  return ')';
1745  case 0x2A:
1746  return '*';
1747 
1748  case 0x2B:
1749  return '+';
1750  case 0x2C:
1751  return ',';
1752  case 0x2D:
1753  return '-';
1754  case 0x2E:
1755  return '.';
1756  case 0x2F:
1757  return '/';
1758 
1759  case 0xBF:
1760  return '';
1761  case 0xF1:
1762  return '';
1763  case 0xE0:
1764  return '';
1765  case 0xA1:
1766  return '';
1767  case 0x5F:
1768  return '_';
1769 
1770  default:
1771  return ' ';
1772 
1773  } /* switch */
1774 }
static int emi_open_connection_ip(SMSCenter *smsc)
Definition: smsc_emi_x25.c:276
void error(int err, const char *fmt,...)
Definition: log.c:612
void info(int err, const char *fmt,...)
Definition: log.c:636
size_t bufsize
Definition: smsc_p.h:185
static int parse_binary_to_emi(char *from, char *to, int length)
char * emi_password
Definition: smsc_p.h:152
char * emi_hostname
Definition: smsc_p.h:149
static char char_sms_to_iso(unsigned char from, int alt_charset)
static char char_iso_to_sms(unsigned char from, int alt_charset)
size_t buflen
Definition: smsc_p.h:186
#define EMI_SWAPPED_CHARS
Definition: alt_charsets.h:77
int type
Definition: smsc_cimd2.c:215
static int parse_iso88591_to_emi(char *from, char *to, int length, int alt_charset)
#define msg_create(type)
Definition: msg.h:136
static void generate_checksum(const unsigned char *buffer, unsigned char *checksum_out)
int emi_submit_msg(SMSCenter *smsc, Msg *omsg)
Definition: smsc_emi_x25.c:372
int emi_pending_smsmessage(SMSCenter *smsc)
Definition: smsc_emi_x25.c:319
static int acknowledge_from_rawmessage(SMSCenter *smsc, char *rawmessage, int length)
Definition: smsc_emi_x25.c:964
#define octstr_get_cstr(ostr)
Definition: octstr.h:233
static struct pid_list * found
int is_allowed_ip(Octstr *allow_ip, Octstr *deny_ip, Octstr *ip)
Definition: utils.c:815
unsigned char * username
Definition: test_cimd2.c:99
static int emi_fill_ucp60_login(char *buf, char *OAdC, char *passwd)
Definition: smsc_emi_x25.c:199
int emi_secondary_fd
Definition: smsc_p.h:159
static Octstr * from
Definition: mtbatch.c:95
unsigned char * password
Definition: test_cimd2.c:100
SMSCenter * emi_open(char *phonenum, char *serialdevice, char *username, char *password)
Definition: smsc_emi_x25.c:153
Octstr * octstr_imm(const char *cstr)
Definition: octstr.c:281
Definition: msg.h:79
static int memorybuffer_insert_data(SMSCenter *smsc, char *buff, int length)
Definition: smsc_emi_x25.c:811
static int parse_msg_to_rawmessage(SMSCenter *smsc, Msg *msg, char *rawmessage, int length)
int emi_receive_msg(SMSCenter *smsc, Msg **tmsg)
Definition: smsc_emi_x25.c:408
static int guarantee_link(SMSCenter *smsc)
Definition: smsc_emi_x25.c:449
int emi_reopen_ip(SMSCenter *smsc)
Definition: smsc_emi_x25.c:294
static int memorybuffer_cut_rawmessage(SMSCenter *smsc, char *buff, int length)
Definition: smsc_emi_x25.c:857
static int parse_rawmessage_to_msg(SMSCenter *smsc, Msg **msg, char *rawmessage, int length)
Definition: smsc_emi_x25.c:895
char * emi_phonenum
Definition: smsc_p.h:147
void msg_destroy(Msg *msg)
Definition: msg.c:132
SMSCenter * smscenter_construct(void)
Definition: smsc.c:101
int emi_backup_fd
Definition: smsc_p.h:155
char * emi_username
Definition: smsc_p.h:151
void smscenter_destruct(SMSCenter *smsc)
Definition: smsc.c:168
int tcpip_connect_to_server_with_port(char *hostname, int port, int our_port, const char *source_addr)
Definition: socket.c:156
void octstr_destroy(Octstr *ostr)
Definition: octstr.c:322
#define octstr_create(cstr)
Definition: octstr.h:125
char * emi_serialdevice
Definition: smsc_p.h:148
static int get_data(SMSCenter *smsc, char *buff, int length)
Definition: smsc_emi_x25.c:660
static int memorybuffer_has_rawmessage(SMSCenter *smsc, int type, char auth)
Definition: smsc_emi_x25.c:828
static int emi_open_connection(SMSCenter *smsc)
Definition: smsc_emi_x25.c:138
int emi_reopen(SMSCenter *smsc)
Definition: smsc_emi_x25.c:183
static int at_dial(char *device, char *phonenum, char *at_prefix, time_t how_long)
Definition: smsc_emi_x25.c:472
int emi_close(SMSCenter *smsc)
Definition: smsc_emi_x25.c:194
long octstr_len(const Octstr *ostr)
Definition: octstr.c:340
static int wait_for_ack(SMSCenter *smsc, int op_type)
Definition: smsc_emi_x25.c:621
Definition: octstr.c:118
static int emi_open_session(SMSCenter *smsc)
Definition: smsc_emi_x25.c:225
char * emi_backup_allow_ip
Definition: smsc_p.h:157
Octstr * host_ip(struct sockaddr_in addr)
Definition: socket.c:615
void debug(const char *place, int err, const char *fmt,...)
Definition: log.c:690
int type
Definition: smsc_p.h:93
#define CRTSCTS
Definition: smsc_emi_x25.c:88
static int parse_emi_to_iso88591(char *from, char *to, int length, int alt_charset)
char * buffer
Definition: smsc_p.h:184
long alt_charset
Definition: smsc_p.h:106
int socklen_t
Definition: socket.h:73
void kannel_cfmakeraw(struct termios *tio)
Definition: utils.c:951
static int put_data(SMSCenter *smsc, char *buff, int length, int is_backup)
Definition: smsc_emi_x25.c:755
int emi_fd
Definition: smsc_p.h:145
#define DC_UNDEF
Definition: sms.h:109
int emi_our_port
Definition: smsc_p.h:158
char name[1024]
Definition: smsc_p.h:96
void octstr_get_many_chars(char *buf, Octstr *ostr, long pos, long len)
Definition: octstr.c:423
int octstr_get_char(const Octstr *ostr, long pos)
Definition: octstr.c:404
int emi_close_ip(SMSCenter *smsc)
Definition: smsc_emi_x25.c:302
static XMLRPCDocument * msg
Definition: test_xmlrpc.c:86
static int start
int emi_current_msg_number
Definition: smsc_p.h:153
static int memorybuffer_append_data(SMSCenter *smsc, char *buff, int length)
Definition: smsc_emi_x25.c:794
int emi_port
Definition: smsc_p.h:150
#define DC_7BIT
Definition: sms.h:110
See file LICENSE for details about the license agreement for using, modifying, copying or deriving work from this software.