4 * Copyright (C) 2001-2003 FhG Fokus
6 * This file is part of Kamailio, a free SIP server.
8 * Kamailio is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version
13 * Kamailio is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 * 2003-01-23: switched from t_uac to t_uac_dlg, adapted to new way of
25 * parsing for Content-Type (bogdan)
26 * 2003-02-28: protocolization of t_uac_dlg completed (jiri)
27 * 2003-08-05: adapted to the new parse_content_type_hdr function (bogdan)
28 * 2003-09-11: updated to new build_lump_rpl() interface (bogdan)
29 * 2003-09-11: force parsing to hdr when extracting destination user (bogdan)
35 #include "../../dprint.h"
37 #include "../../config.h"
38 #include "../../globals.h"
39 #include "../../mem/mem.h"
40 #include "../../mem/shm_mem.h"
41 #include "../../parser/parse_uri.h"
42 #include "../../parser/parse_content.h"
43 #include "../../parser/parse_from.h"
44 #include "../../data_lump_rpl.h"
45 #include "../../lib/kcore/km_ut.h"
46 #include "../../modules/tm/t_hooks.h"
47 #include "../../modules/tm/uac.h"
48 #include "sms_funcs.h"
49 #include "sms_report.h"
50 #include "libsms_modem.h"
51 #include "libsms_sms.h"
56 struct modem modems[MAX_MODEMS];
57 struct network networks[MAX_NETWORKS];
58 int net_pipes_in[MAX_NETWORKS];
68 #define ERR_NUMBER_TEXT " is an invalid number! Please resend your SMS "\
69 "using a number in +(country code)(area code)(local number) format. Thanks"\
70 " for using our service!"
71 #define ERR_NUMBER_TEXT_LEN (sizeof(ERR_NUMBER_TEXT)-1)
73 #define ERR_TRUNCATE_TEXT "We are sorry, but your message exceeded our "\
74 "maximum allowed length. The following part of the message wasn't sent"\
76 #define ERR_TRUNCATE_TEXT_LEN (sizeof(ERR_TRUNCATE_TEXT)-1)
78 #define ERR_MODEM_TEXT "Due to our modem temporary indisponibility, "\
79 "the following message couldn't be sent : "
80 #define ERR_MODEM_TEXT_LEN (sizeof(ERR_MODEM_TEXT)-1)
82 #define STORED_NOTE "NOTE: Your SMS received provisional confirmation"\
83 " 48 \"Delivery is not yet possible\". The SMS was store on the "\
84 "SMSCenter for further delivery. Our gateway cannot guarantee "\
85 "further information regarding your SMS delivery! Your message was: "
86 #define STORED_NOTE_LEN (sizeof(STORED_NOTE)-1)
88 #define OK_MSG "Your SMS was finally successfully delivered!"\
90 #define OK_MSG_LEN (sizeof(OK_MSG)-1)
92 #define CONTENT_TYPE_HDR "Content-Type: text/plain"
93 #define CONTENT_TYPE_HDR_LEN (sizeof(CONTENT_TYPE_HDR)-1)
95 #define is_in_sip_addr(_p) \
96 ((_p)!=' ' && (_p)!='\t' && (_p)!='(' && (_p)!='[' && (_p)!='<' \
97 && (_p)!='>' && (_p)!=']' && (_p)!=')' && (_p)!='?' && (_p)!='!' \
98 && (_p)!=';' && (_p)!=',' && (_p)!='\n' && (_p)!='\r' && (_p)!='=')
100 #define no_sip_addr_begin(_p) \
101 ( (_p)!=' ' && (_p)!='\t' && (_p)!='-' && (_p)!='=' && (_p)!='\r'\
102 && (_p)!='\n' && (_p)!=';' && (_p)!=',' && (_p)!='.' && (_p)!=':')
106 int push_on_network(struct sip_msg *msg, int net)
110 struct sms_msg *sms_messg;
111 struct to_body *from;
116 /* get the message's body
117 * anyhow we have to call this function, so let's do it at the beginning
118 * to force the parsing of all the headers - like this we avoid separate
119 * calls of parse_headers function for FROM, CONTENT_LENGTH, TO hdrs */
120 body.s = get_body( msg );
122 LM_ERR("failed to extract body from msg!\n");
126 /* content-length (if present) must be already parsed */
127 if (!msg->content_length) {
128 LM_ERR("no Content-Length header found!\n");
131 body.len = get_content_length( msg );
133 /* parse the content-type header */
134 if ( (mime=parse_content_type_hdr(msg))<1 ) {
135 LM_ERR("failed to parse Content-Type header\n");
139 /* check the content-type value */
140 if ( mime!=(TYPE_TEXT<<16)+SUBTYPE_PLAIN
141 && mime!=(TYPE_MESSAGE<<16)+SUBTYPE_CPIM ) {
142 LM_ERR("invalid content-type for a message request! type found=%d\n",
147 /* we try to get the user name (phone number) first from the RURI
148 (in our case means from new_uri or from first_line.u.request.uri);
149 if it's missing there (like in requests generated by MSN MESSENGER),
150 we go for "to" header
152 LM_DBG("string to get user from new_uri\n");
153 if ( !msg->new_uri.s||parse_uri( msg->new_uri.s,msg->new_uri.len,&uri)
156 LM_DBG("string to get user from R_uri\n");
157 if ( parse_uri( msg->first_line.u.request.uri.s,
158 msg->first_line.u.request.uri.len ,&uri)||!uri.user.len )
160 LM_DBG("string to get user from To\n");
161 if ((!msg->to&&((parse_headers(msg,HDR_TO_F,0)==-1)||!msg->to)) ||
162 parse_uri( get_to(msg)->uri.s, get_to(msg)->uri.len, &uri)<0
165 LM_ERR("failed to extract user name from RURI"
166 " and To header!\n");
171 /* check the uri.user format = '+(inter code)(number)' */
172 if (uri.user.len<2 || uri.user.s[0]!='+' || uri.user.s[1]<'1'
173 || uri.user.s[1]>'9') {
174 LM_ERR("user tel number [%.*s] does not respect international format\n"
175 ,uri.user.len,uri.user.s);
179 /* parsing from header */
180 if ( parse_from_header( msg )<0 ) {
181 LM_ERR("failed get FROM header\n");
184 from = (struct to_body*)msg->from->parsed;
186 /*-------------BUILD AND FILL THE SMS_MSG STRUCTURE --------------------*/
187 /* computes the amount of memory needed */
188 len = SMS_HDR_BF_ADDR_LEN + from->uri.len
189 + SMS_HDR_AF_ADDR_LEN + body.len + SMS_FOOTER_LEN /*text to send*/
190 + from->uri.len /* from */
191 + uri.user.len-1 /* to user (without '+') */
192 + sizeof(struct sms_msg) ; /* the sms_msg structure */
193 /* allocs a new sms_msg structure in shared memory */
194 sms_messg = (struct sms_msg*)shm_malloc(len);
196 LM_ERR("failed get shm memory!\n");
199 p = (char*)sms_messg + sizeof(struct sms_msg);
201 /* copy "from" into sms struct */
202 sms_messg->from.len = from->uri.len;
203 sms_messg->from.s = p;
204 append_str(p,from->uri.s,from->uri.len);
206 /* copy "to.user" - we have to strip out the '+' */
207 sms_messg->to.len = uri.user.len-1;
209 append_str(p,uri.user.s+1,sms_messg->to.len);
211 /* copy (and composing) sms body */
212 sms_messg->text.len = SMS_HDR_BF_ADDR_LEN + sms_messg->from.len
213 + SMS_HDR_AF_ADDR_LEN + body.len+SMS_FOOTER_LEN;
214 sms_messg->text.s = p;
215 append_str(p, SMS_HDR_BF_ADDR, SMS_HDR_BF_ADDR_LEN);
216 append_str(p, sms_messg->from.s, sms_messg->from.len);
217 append_str(p, SMS_HDR_AF_ADDR, SMS_HDR_AF_ADDR_LEN);
218 append_str(p, body.s, body.len);
219 append_str(p, SMS_FOOTER, SMS_FOOTER_LEN);
221 if (*queued_msgs>MAX_QUEUED_MESSAGES)
225 if (write(net_pipes_in[net], &sms_messg, sizeof(sms_messg))!=
228 LM_ERR("failed to write for net %d to pipe [%d] : %s\n",
229 net,net_pipes_in[net],strerror(errno) );
244 int send_sip_msg_request(str *to, str *from_user, str *body)
246 str msg_type = { "MESSAGE", 7};
254 from.len = hdrs.len = 0;
257 from.len = 6 /*"<sip:+"*/ + from_user->len/*user*/ + 1/*"@"*/
258 + domain.len /*host*/ + 1 /*">"*/ ;
259 from.s = (char*)pkg_malloc(from.len);
263 append_str(p,"<sip:+",6);
264 append_str(p,from_user->s,from_user->len);
266 append_str(p,domain.s,domain.len);
269 /* hdrs = Contact header + Content-type */
271 hdrs.len = CONTENT_TYPE_HDR_LEN + CRLF_LEN;
273 hdrs.len += 15 /*"Contact: <sip:+"*/ + from_user->len/*user*/ +
274 1/*"@"*/ + domain.len/*host*/ + 1 /*">"*/ + CRLF_LEN;
275 hdrs.s = (char*)pkg_malloc(hdrs.len);
279 append_str(p,CONTENT_TYPE_HDR,CONTENT_TYPE_HDR_LEN);
280 append_str(p,CRLF,CRLF_LEN);
282 append_str(p,"Contact: <sip:+",15);
283 append_str(p,from_user->s,from_user->len);
285 append_str(p,domain.s,domain.len);
286 append_str(p,">"CRLF,1+CRLF_LEN);
289 /* sending the request */
290 set_uac_req(&uac_r, &msg_type, &hdrs, body, 0, 0, 0, 0);
291 foo = tmb.t_request( &uac_r,
297 if (from.s) pkg_free(from.s);
298 if (hdrs.s) pkg_free(hdrs.s);
301 LM_ERR("no more pkg memory!\n");
302 if (from.s) pkg_free(from.s);
303 if (hdrs.s) pkg_free(hdrs.s);
310 inline int send_error(struct sms_msg *sms_messg, char *msg1_s, int msg1_len,
311 char *msg2_s, int msg2_len)
318 body.len = msg1_len + msg2_len;
319 body.s = (char*)pkg_malloc(body.len);
323 append_str(p, msg1_s, msg1_len );
324 append_str(p, msg2_s, msg2_len);
327 foo = send_sip_msg_request( &(sms_messg->from), &(sms_messg->to), &body);
331 LM_ERR("no more pkg memory!\n");
338 inline unsigned int split_text(str *text, unsigned char *lens,int nice)
348 k = MAX_SMS_LENGTH-(nice&&nr_chunks?SMS_EDGE_PART_LEN:0);
349 if ( len+k<text->len ) {
350 /* is not the last piece :-( */
351 if (nice && !nr_chunks) k -= SMS_EDGE_PART_LEN;
352 if (text->len-len-k<=SMS_FOOTER_LEN+4)
353 k = (text->len-len)/2;
354 /* ->looks for a point to split */
356 while( k>0 && (c=text->s[len+k-1])!='.' && c!=' ' && c!=';'
357 && c!='\r' && c!='\n' && c!='-' && c!='!' && c!='?' && c!='+'
358 && c!='=' && c!='\t' && c!='\'')
361 /* wast of space !!!!*/
367 lens[nr_chunks] = text->len-len;
371 }while (len<text->len);
379 int send_as_sms(struct sms_msg *sms_messg, struct modem *mdm)
381 static char buf[MAX_SMS_LENGTH];
382 unsigned int buf_len;
383 unsigned char len_array_1[256], len_array_2[256], *len_array;
384 unsigned int nr_chunks_1, nr_chunks_2, nr_chunks;
385 unsigned int use_nice;
391 text.s = sms_messg->text.s;
392 text.len = sms_messg->text.len;
394 nr_chunks_1 = split_text( &text, len_array_1, 0);
395 nr_chunks_2 = split_text( &text, len_array_2, 1);
396 if (nr_chunks_1==nr_chunks_2) {
397 len_array = len_array_2;
398 nr_chunks = nr_chunks_2;
401 len_array = len_array_1;
402 nr_chunks = nr_chunks_1;
407 for(i=0,p=text.s ; i<nr_chunks&&i<max_sms_parts ; p+=len_array[i++]) {
410 if (nr_chunks>1 && i) {
411 append_str(q,SMS_EDGE_PART,SMS_EDGE_PART_LEN);
412 *(q-2)=nr_chunks+'0';
415 append_str(q,p,len_array[i]);
416 if (nr_chunks>1 && !i) {
417 append_str(q,SMS_EDGE_PART,SMS_EDGE_PART_LEN);
418 *(q-2)=nr_chunks+'0';
424 append_str(q,p,len_array[i]);
425 buf_len = len_array[i];
427 if (i+1==max_sms_parts && i+1<nr_chunks) {
428 /* simply override the end of the last allowed part */
429 buf_len += SMS_TRUNCATED_LEN+SMS_FOOTER_LEN;
430 if (buf_len>MAX_SMS_LENGTH) buf_len = MAX_SMS_LENGTH;
431 q = buf + (buf_len-SMS_TRUNCATED_LEN-SMS_FOOTER_LEN);
432 append_str(q,SMS_TRUNCATED,SMS_TRUNCATED_LEN);
433 append_str(q,SMS_FOOTER,SMS_FOOTER_LEN);
434 p += buf_len-SMS_TRUNCATED_LEN-SMS_FOOTER_LEN-SMS_EDGE_PART_LEN;
435 send_error(sms_messg, ERR_TRUNCATE_TEXT, ERR_TRUNCATE_TEXT_LEN,
436 p, text.len-(p-text.s)-SMS_FOOTER_LEN);
438 LM_DBG("---%d--<%d><%d>--\n|%.*s|\n", i, len_array[i], buf_len,
440 sms_messg->text.s = buf;
441 sms_messg->text.len = buf_len;
442 if ( (ret_code=putsms(sms_messg,mdm))<0)
444 if (sms_report_type!=NO_REPORT)
445 add_sms_into_report_queue(ret_code,sms_messg,
446 p-use_nice*(nr_chunks>1)*SMS_EDGE_PART_LEN,len_array[i]);
450 /* put back the pointer to the beginning of the message*/
451 sms_messg->text.s = text.s;
452 sms_messg->text.len = text.len;
453 /* remove the sms if nobody points to it */
454 if (!sms_messg->ref){
461 send_error(sms_messg, sms_messg->to.s, sms_messg->to.len,
462 ERR_NUMBER_TEXT, ERR_NUMBER_TEXT_LEN);
463 else if (ret_code==-2)
465 send_error(sms_messg, ERR_MODEM_TEXT, ERR_MODEM_TEXT_LEN,
466 text.s+SMS_HDR_BF_ADDR_LEN+sms_messg->from.len+SMS_HDR_AF_ADDR_LEN,
467 text.len-SMS_FOOTER_LEN-SMS_HDR_BF_ADDR_LEN-sms_messg->from.len-
468 SMS_HDR_AF_ADDR_LEN );
470 if (!(--(sms_messg->ref)))
478 int send_sms_as_sip( struct incame_sms *sms )
488 /* first we have to parse the body to try to get out
489 the sip destination address;
490 The sms body can to be in the following two formats:
491 1. The entire or part of the sent header still exists - we will
492 pars it and consider the start of the sip message the first
493 character that doesn't match the header!
494 2. The sms body is totally different of the send sms -> search for a
495 sip address inside; everything before it is ignored, only the
496 part following the address being send as sip
503 /* is our logo (or a part of it) still there? */
504 if (*p==SMS_HDR_BF_ADDR[0]) {
506 /* try to match SMS_HDR_BF_ADDR */
508 while( is_pattern && p<sms->ascii+sms->userdatalength
509 && k<SMS_HDR_BF_ADDR_LEN)
510 if (*(p++)!=SMS_HDR_BF_ADDR[k++])
513 /* first header part is broken -> let's give it a chance
514 and parse for the first word delimiter */
515 while(p<sms->ascii+sms->userdatalength && no_sip_addr_begin(*p))
518 if (p+9>=sms->ascii+sms->userdatalength) {
519 LM_ERR("failed to find sip_address start in sms body [%s]!\n",
525 /* lets get the address */
526 if (p[0]!='s' || p[1]!='i' || p[2]!='p' || p[3]!=':') {
527 LM_ERR("wrong sip address format in sms body [%s]!\n",sms->ascii);
531 /* goes to the end of the address */
532 while(p<sms->ascii+sms->userdatalength && is_in_sip_addr(*p) )
534 if (p>=sms->ascii+sms->userdatalength) {
535 LM_ERR("failed to find sip address end in sms body [%s]!\n",
538 sip_addr.len = p-sip_addr.s;
539 LM_DBG("sip address found [%.*s]\n",
540 sip_addr.len,sip_addr.s);
541 /* try to match SMS_HDR_AF_ADDR */
543 while( is_pattern && p<sms->ascii+sms->userdatalength
544 && k<SMS_HDR_AF_ADDR_LEN)
545 if (*(p++)!=SMS_HDR_AF_ADDR[k++])
548 /* no trace of the pattern sent along with the orig sms*/
550 if ((p[0]=='s'||p[0]=='S') && (p[1]=='i'||p[1]=='I')
551 && (p[2]=='p'||p[2]=='P') && p[3]==':') {
552 /* we got the address beginning */
554 /* goes to the end of the address */
555 while(p<sms->ascii+sms->userdatalength && is_in_sip_addr(*p) )
557 if (p==sms->ascii+sms->userdatalength) {
558 LM_ERR("failed to find sip address end in sms body [%s]!\n",
562 sip_addr.len = p-sip_addr.s;
564 /* parse to the next word */
565 /*LM_DBG("*** Skipping word len=%d\n",sms->userdatalength);*/
566 while(p<sms->ascii+sms->userdatalength&&no_sip_addr_begin(*p)){
570 if (p+9>=sms->ascii+sms->userdatalength) {
571 LM_ERR("failed to find sip address start in sms body [%s]!\n",
575 /*LM_DBG("*** Done\n");*/
577 }while (!sip_addr.len);
580 /* the rest of the sms (if any ;-)) is the body! */
582 sip_body.len = sms->ascii + sms->userdatalength - p;
583 /* let's trim out all \n an \r from begining */
584 while ( sip_body.len && sip_body.s
585 && (sip_body.s[0]=='\n' || sip_body.s[0]=='\r') ) {
589 if (sip_body.len==0) {
590 LM_WARN("empty body for sms [%s]", sms->ascii);
593 LM_DBG("extracted body is: [%.*s]\n",sip_body.len, sip_body.s);
595 /* finally, let's send it as sip message */
596 sip_from.s = sms->sender;
597 sip_from.len = strlen(sms->sender);
598 /* patch the body with date and time */
599 if (sms->userdatalength + CRLF_LEN + 1 /*'('*/ + DATE_LEN
600 + 1 /*','*/ + TIME_LEN + 1 /*')'*/< sizeof(sms->ascii)) {
601 p = sip_body.s + sip_body.len;
602 append_str( p, CRLF, CRLF_LEN);
604 append_str( p, sms->date, DATE_LEN);
606 append_str( p, sms->time, TIME_LEN);
608 sip_body.len += CRLF_LEN + DATE_LEN + TIME_LEN + 3;
610 send_sip_msg_request( &sip_addr, &sip_from, &sip_body);
620 int check_sms_report( struct incame_sms *sms )
622 struct sms_msg *sms_messg;
627 LM_DBG("Report for sms number %d.\n",sms->sms_id);
628 res=relay_report_to_queue( sms->sms_id, sms->sender, sms->ascii[0], &old);
629 if (res==3) { /* error */
630 /* the sms was confirmed with an error code -> we have to send a
631 message to the SIP user */
632 s1 = get_error_str(sms->ascii[0]);
633 s2 = get_text_from_report_queue(sms->sms_id);
634 sms_messg = get_sms_from_report_queue(sms->sms_id);
635 send_error( sms_messg, s1->s, s1->len, s2->s, s2->len);
636 } else if (res==1 && sms->ascii[0]==48 && old!=48) { /* provisional 48 */
637 /* the sms was provisional confirmed with a 48 code -> was stored
638 by SMSC -> no further real-time tracing possible */
639 s2 = get_text_from_report_queue(sms->sms_id);
640 sms_messg = get_sms_from_report_queue(sms->sms_id);
641 send_error( sms_messg, STORED_NOTE, STORED_NOTE_LEN, s2->s, s2->len);
642 } else if (res==2 && old==48) {
643 /* we received OK for a SMS that had received prev. an 48 code.
644 The note that we send for 48 has to be now clarify */
645 s2 = get_text_from_report_queue(sms->sms_id);
646 sms_messg = get_sms_from_report_queue(sms->sms_id);
647 send_error( sms_messg, OK_MSG, OK_MSG_LEN, s2->s, s2->len);
649 if (res>1) /* final response */
650 remove_sms_from_report_queue(sms->sms_id);
658 int check_cds_report( struct modem *mdm, char *cds, int cds_len)
660 struct incame_sms sms;
662 if (cds2sms( &sms, mdm, cds, cds_len)==-1)
664 check_sms_report( &sms );
671 void modem_process(struct modem *mdm)
673 struct sms_msg *sms_messg;
674 struct incame_sms sms;
681 int max_mem=0, used_mem=0;
686 /* let's open/init the modem */
687 LM_DBG("opening modem\n");
688 if (openmodem(mdm)==-1) {
689 LM_ERR("failed to open modem %s!"
690 " %s \n",mdm->name,strerror(errno));
695 initmodem(mdm,check_cds_report);
697 if ( (max_mem=check_memory(mdm,MAX_MEM))==-1 ) {
698 LM_WARN("CPMS command unsuported! using default values (10,10)\n");
699 used_mem = max_mem = 10;
702 LM_DBG("modem maximum memory is %d\n",max_mem);
704 set_gettime_function();
709 for (i=0;i<nr_of_networks && mdm->net_list[i]!=-1;i++)
713 net = &(networks[mdm->net_list[i]]);
714 /*getting msgs from pipe*/
715 while( counter<net->max_sms_per_call && !empty_pipe )
717 /* let's read a sms from pipe */
718 len = read(net->pipe_out, &sms_messg,
720 if (len!=sizeof(sms_messg)) {
722 LM_ERR("truncated message read from pipe! "
724 else if (errno==EAGAIN)
727 LM_ERR("pipe reading failed: %s\n",strerror(errno));
734 /* compute and send the sms */
735 LM_DBG("%s processing sms for net %s:"
736 " \n\tTo:[%.*s]\n\tBody=<%d>[%.*s]\n",
737 mdm->device, net->name,
738 sms_messg->to.len,sms_messg->to.s,
739 sms_messg->text.len,sms_messg->text.len,sms_messg->text.s);
740 send_as_sms( sms_messg , mdm);
743 /* if I reached the limit -> set not to wait */
744 if (counter==net->max_sms_per_call)
749 /* let's see if we have incoming sms */
750 if ( !cpms_unsuported )
751 if ((used_mem = check_memory(mdm,USED_MEM))==-1) {
752 LM_ERR("CPMS command failed! cannot get used mem->using 10\n");
756 /* if any, let's get them */
758 LM_DBG("%d new SMS on modem\n",used_mem);
759 for(i=1,k=1;k<=used_mem && i<=max_mem;i++) {
760 if (getsms(&sms,mdm,i)!=-1) {
762 LM_DBG("SMS Get from location %d\n",i);
763 /*for test ;-) -> to be remove*/
764 LM_DBG("SMS RECEIVED:\n\rFrom: %s %s\n\r%.*s %.*s"
765 "\n\r\"%.*s\"\n\r",sms.sender,sms.name,
766 DATE_LEN,sms.date,TIME_LEN,sms.time,
767 sms.userdatalength,sms.ascii);
768 if (!sms.is_statusreport)
769 send_sms_as_sip(&sms);
771 check_sms_report(&sms);
775 /* if reports are used, checks for expired records in report queue */
776 if (sms_report_type!=NO_REPORT)
777 check_timeout_in_report_queue();
779 /* sleep -> if it's needed */
781 sleep(mdm->looping_interval);