1 /* ====================================================================
2  * The Kannel Software License, Version 1.0
3  *
4  * Copyright (c) 2001-2014 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 */
emi_open_connection(SMSCenter * smsc)138 static int emi_open_connection(SMSCenter *smsc)
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 
emi_open(char * phonenum,char * serialdevice,char * username,char * password)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 
emi_reopen(SMSCenter * smsc)183 int emi_reopen(SMSCenter *smsc)
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 
emi_close(SMSCenter * smsc)194 int emi_close(SMSCenter *smsc)
195 {
196     return emi_close_ip(smsc);
197 }
198 
emi_fill_ucp60_login(char * buf,char * OAdC,char * passwd)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 
emi_open_session(SMSCenter * smsc)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 
emi_open_connection_ip(SMSCenter * smsc)276 static int emi_open_connection_ip(SMSCenter *smsc)
277 {
278     smsc->emi_fd =
279         tcpip_connect_to_server_with_port(smsc->emi_hostname,
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 
emi_reopen_ip(SMSCenter * smsc)294 int emi_reopen_ip(SMSCenter *smsc)
295 {
296     emi_close_ip(smsc);
297 
298     return emi_open_connection_ip(smsc);
299 }
300 
301 
emi_close_ip(SMSCenter * smsc)302 int emi_close_ip(SMSCenter *smsc)
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 */
emi_pending_smsmessage(SMSCenter * smsc)319 int emi_pending_smsmessage(SMSCenter *smsc)
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  */
emi_submit_msg(SMSCenter * smsc,Msg * omsg)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 */
emi_receive_msg(SMSCenter * smsc,Msg ** tmsg)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 */
guarantee_link(SMSCenter * smsc)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 
at_dial(char * device,char * phonenum,char * at_prefix,time_t how_long)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  */
wait_for_ack(SMSCenter * smsc,int op_type)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  */
get_data(SMSCenter * smsc,char * buff,int length)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 */
put_data(SMSCenter * smsc,char * buff,int length,int is_backup)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 */
memorybuffer_append_data(SMSCenter * smsc,char * buff,int length)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 */
memorybuffer_insert_data(SMSCenter * smsc,char * buff,int length)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 */
memorybuffer_has_rawmessage(SMSCenter * smsc,int type,char auth)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 */
memorybuffer_cut_rawmessage(SMSCenter * smsc,char * buff,int length)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 */
parse_rawmessage_to_msg(SMSCenter * smsc,Msg ** msg,char * rawmessage,int length)895 static int parse_rawmessage_to_msg(SMSCenter *smsc, Msg **msg,
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  */
acknowledge_from_rawmessage(SMSCenter * smsc,char * rawmessage,int length)964 static int acknowledge_from_rawmessage(SMSCenter *smsc,
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 */
parse_msg_to_rawmessage(SMSCenter * smsc,Msg * msg,char * rawmessage,int rawmessage_length)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 */
parse_emi_to_iso88591(char * from,char * to,int length,int alt_charset)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 */
parse_iso88591_to_emi(char * from,char * to,int length,int alt_charset)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 */
parse_binary_to_emi(char * from,char * to,int length)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 */
generate_checksum(const unsigned char * buf,unsigned char * out)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 * PGr�nholm
1234 */
char_iso_to_sms(unsigned char from,int alt_charset)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 * PGr�nholm
1510 */
char_sms_to_iso(unsigned char from,int alt_charset)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 }
1775