laforge
/
openbts-osmo
Archived
1
0
Fork 0

Checking in forgotten smsc.cpp and smsc.h files.

master
Alexander Chemeris 12 years ago committed by Thomas Tsou
parent 970beeb816
commit 2b26d6cf26
  1. 394
      public-trunk/smqueue/smsc.cpp
  2. 39
      public-trunk/smqueue/smsc.h

@ -0,0 +1,394 @@
/*
* SMSC.h - SMS Center implementation for OpenBTS.
* Written by Alexander Chemeris, 2010.
*
* Copyright 2010 Free Software Foundation, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* See the COPYING file in the main directory for details.
*/
//#include <stdio.h>
//#include <GSMLogicalChannel.h>
//#include <GSML3MMMessages.h>
#include <GSML3Message.h>
//#include <GSML3CommonElements.h>
//#include "ControlCommon.h"
#include <Regexp.h>
#include <Logger.h>
using namespace std;
using namespace GSM;
//using namespace Control;
//#include "SIPInterface.h"
//#include "SIPUtility.h"
//#include "SIPMessage.h"
//#include "SIPEngine.h"
//using namespace SIP;
//#include "CollectMSInfo.h"
#include "smsc.h"
// FORWARD DECLARATIONS
void set_to_for_smsc(const char *address, short_msg_p_list::iterator &smsg);
/**@name Functions for transmitting through various gateways. */
//@{
/** Substitute spaces with +'s for compatibility with some protocols. */
void convertText(char *dest, const char *src)
{
// FIXME -- We should just do full "percent encoding" here.
while (*src != '\0') {
if (*src == ' ') *dest++ = '+';
else *dest++ = *src;
src++;
}
*dest = '\0';
}
/** Send SMS via and HTTP interface. */
short_code_action sendHTTP(const char* destination, const std::string &message)
{
char convMessage[message.length()+2];
convertText(convMessage,message.data());
char command[2048];
// FIXME -- Check specs for a good timeout value here.
sprintf(command,"wget -T 5 -C -q -O - \"http://%s/http/%s&to=%s&text=%s\" >& /dev/null",
gConfig.getStr("SMS.HTTP.Gateway"),
gConfig.getStr("SMS.HTTP.AccessString"),
destination, convMessage);
LOG(DEBUG) << "MOSMS: sendHTTP sending with " << command;
// HTTP "GET" method with wget.
// FIXME -- Look at the output of wget to check success.
FILE* wget = popen(command,"r");
if (!wget) {
LOG(ALARM) << "cannot open wget with " << command;
return SCA_INTERNAL_ERROR;
}
pclose(wget);
return SCA_DONE;
}
/** Send e-mail with local sendmail program. */
short_code_action sendEMail(const char* address, const char* body, const char* subject=NULL)
{
// We're not checking for overflow because the TPDU can't be more than a few hundred bytes.
// Build the command line.
// FIXME -- Use sendmail to have better header control.
char command[1024];
if (subject) sprintf(command,"mail -s \"%s\" %s",subject,address);
else sprintf(command,"mail %s",address);
LOG(INFO) << "sending SMTP: \"" << body << "\" via \"" << command << "\"";
// Send the mail.
FILE* mail = popen(command,"w");
if (!mail) {
LOG(ALARM) << "cannot send mail with \"" << command << "\"";
return SCA_INTERNAL_ERROR;
}
// FIXME -- We should be sure body is 7-bit clean.
fprintf(mail,"%s",body);
if (pclose(mail) == -1) return SCA_INTERNAL_ERROR;
return SCA_DONE;
}
short_code_action sendSIP_init(const char *imsi, const TLSubmit& submit,
const std::string &body, short_code_params *scp)
{
const char *address = submit.DA().digits();
const TLUserData& tl_ud = submit.UD();
const char *from = scp->scp_qmsg_it->parsed->from->url->username;
LOG(INFO) << "from " << imsi << " to " << address;
if (scp == NULL)
{
LOG(WARN) << "short_code_params is NULL. Error.";
return SCA_INTERNAL_ERROR;
}
// START OF THE SIP PROCESSING
osip_message_t *omsg = scp->scp_qmsg_it->parsed;
// Req.URI
osip_free(omsg->req_uri->username);
omsg->req_uri->username = (char *)osip_malloc (strlen(address)+1);
strcpy(omsg->req_uri->username, address);
// To:
set_to_for_smsc(address, scp->scp_qmsg_it);
// Let them know that parsed part has been changed.
scp->scp_qmsg_it->parsed_was_changed();
if (ISLOGGING(DEBUG)) {
// Call make_text_valid() is needed for debug only.
scp->scp_qmsg_it->make_text_valid();
LOG(DEBUG) << "Updated SMS message: " << scp->scp_qmsg_it->text;
}
return SCA_RESTART_PROCESSING;
}
void create_sms_delivery(const std::string &body,
const TLUserData &UD,
short_msg_p_list::iterator &smsg)
{
RPData *rp_data_new = NULL;
TLDeliver *deliver = NULL;
const char *from = smsg->parsed->from->url->username;
// HACK
// Check for "Easter Eggs"
// TL-PID
// See 03.40 9.2.3.9.
unsigned TLPID=0;
if (strncmp(body.data(),"#!TLPID",7)==0) sscanf(body.data(),"#!TLPID%d",&TLPID);
// Generate RP-DATA with SMS-DELIVER
{
unsigned reference = random() % 255;
deliver = new TLDeliver(from,UD,TLPID);
rp_data_new = new RPData(reference, RPAddress(gConfig.getStr("SMS.FakeSrcSMSC")),
*deliver);
LOG(DEBUG) << "New RPData: " << *rp_data_new;
}
// Replace RP-DATA in the message
delete smsg->rp_data;
delete smsg->tl_message;
smsg->rp_data = rp_data_new;
smsg->tl_message = deliver;
}
void pack_tpdu(short_msg_p_list::iterator &smsg)
{
// Pack RP-DATA to bitstream
RLFrame RPDU_new(smsg->rp_data->bitsNeeded());
smsg->rp_data->write(RPDU_new);
LOG(DEBUG) << "New RLFrame: " << RPDU_new;
// START OF THE SIP PROCESSING
osip_message_t *omsg = smsg->parsed;
// Message body
osip_body_t *bod1 = (osip_body_t *)omsg->bodies.node->element;
osip_free(bod1->body);
ostringstream body_stream;
RPDU_new.hex(body_stream);
bod1->length = body_stream.str().length();
bod1->body = (char *)osip_malloc (bod1->length+1);
strcpy(bod1->body, body_stream.str().data());
// Let them know that parsed part has been changed.
smsg->parsed_was_changed();
// It's SC->MS now
smsg->ms_to_sc = false;
}
void set_to_for_smsc(const char *address, short_msg_p_list::iterator &smsg)
{
osip_message_t *omsg = smsg->parsed;
// Set To field
osip_free(omsg->to->url->username);
osip_free(omsg->to->displayname);
omsg->to->url->username = (char *)osip_malloc (strlen(address)+1);
omsg->to->displayname = (char *)osip_malloc (strlen(omsg->req_uri->username)+1);
strcpy(omsg->to->url->username, address);
strcpy(omsg->to->displayname, omsg->req_uri->username);
// Let them know that parsed part has been changed.
smsg->parsed_was_changed();
}
//@}
/** Send a TPDU through whatever gateway is available. */
short_code_action submitSMS(const char *imsi, const TLSubmit& submit,
const std::string &body, short_code_params *scp)
{
LOG(INFO) << "from " << imsi << " message: " << submit;
const TLAddress& address = submit.DA();
// Check for direct e-mail address at start of message body.
// FIXME -- This doesn't really follow the spec. See GSM 03.40 3.8.
static const Regexp emailAddress("^[[:graph:]]+@[[:graph:]]+ ");
if (emailAddress.match(body.data())) {
// FIXME -- Get the sender's E.164 to put in the subject line.
char bodyCopy[body.length()+2];
strcpy(bodyCopy,body.data());
char* SMTPAddress = bodyCopy;
char* term = strchr(bodyCopy,' ');
// If term's NULL, the regexp is broken.
assert(term);
*term = '\0';
char* SMTPPayload = term+1;
LOG(INFO) << "sending SMTP to " << SMTPAddress << ": " << SMTPPayload;
if (SMTPPayload) return sendEMail(SMTPAddress,SMTPPayload,"from OpenBTS gateway");
else return sendEMail(SMTPAddress,"(empty)","from OpenBTS gateway");
}
// Send to smqueue or HTTP gateway, depending on what's defined in the config.
if (gConfig.defines("SMS.HTTP.Gateway"))
// If there is an external HTTP gateway, use it.
return sendHTTP(address.digits(), body);
else
// Otherwise, we are looking for a SIP interface to smqueue.
return sendSIP_init(imsi, submit, body, scp);
}
short_code_action shortcode_smsc(const char *imsi, const char *msgtext,
short_code_params *scp)
{
short_code_action return_action = SCA_TREAT_AS_ORDINARY;
short_msg_p_list::iterator smsg = scp->scp_qmsg_it;
if (smsg->content_type != short_msg::VND_3GPP_SMS)
{
LOG(WARN) << "We support only TPDU-coded SMS messages. Plain text ones are to be supported later.";
return SCA_INTERNAL_ERROR;
}
if (smsg->tl_message == NULL)
{
LOG(WARN) << "TLMessage is not available. Error during SMS decoding occurred?";
return SCA_INTERNAL_ERROR;
}
if (((TLMessage::MessageType)smsg->tl_message->MTI()) != TLMessage::SUBMIT)
{
LOG(WARN) << "TPDU must be of SMS-SUBMIT type, we have MTI="
<< (TLMessage::MessageType)smsg->tl_message->MTI();
return SCA_INTERNAL_ERROR;
}
return_action = submitSMS(imsi, *((TLSubmit*)smsg->tl_message), msgtext, scp);
return return_action;
}
bool pack_text_to_tpdu(const std::string &body,
short_msg_p_list::iterator &smsg)
{
create_sms_delivery(body, TLUserData(body.data()), smsg);
pack_tpdu(smsg);
// Set Content-Type field
const char *type = "application";
const char *subtype = "vnd.3gpp.sms";
osip_free(smsg->parsed->content_type->type);
osip_free(smsg->parsed->content_type->subtype);
smsg->parsed->content_type->type = (char *)osip_malloc (strlen(type)+1);
smsg->parsed->content_type->subtype = (char *)osip_malloc (strlen(subtype)+1);
strcpy(smsg->parsed->content_type->type, type);
strcpy(smsg->parsed->content_type->subtype, subtype);
// Let them know that parsed part has been changed.
smsg->parsed_was_changed();
return true;
}
bool recode_tpdu(const std::string &body,
short_msg_p_list::iterator &smsg)
{
bool return_action = true;
// Safety check
if (smsg->tl_message == NULL)
{
LOG(WARN) << "TLMessage is not available. Error during SMS decoding occurred?";
return false;
}
switch ((TLMessage::MessageType)smsg->tl_message->MTI()) {
case TLMessage::SUBMIT: {
TLSubmit *submit = (TLSubmit*)smsg->tl_message;
const TLUserData& tl_ud = submit->UD();
create_sms_delivery(body, tl_ud, smsg);
pack_tpdu(smsg);
return_action = true;
break;
}
case TLMessage::DELIVER_REPORT:
case TLMessage::STATUS_REPORT:
// TODO
LOG(WARN) << "TPDU must be of SMS-SUBMIT type, we have MTI="
<< (TLMessage::MessageType)smsg->tl_message->MTI();
return false;
}
// Now we have MS->SC message
smsg->ms_to_sc = false;
return return_action;
}
bool pack_sms_for_delivery(short_msg_p_list::iterator &smsg)
{
bool return_action = true;
std::string msgtext;
if (!smsg->need_repack) {
// Nothing to do.
return true;
}
// Parse message if not parsed yet.
smsg->parse();
// Get message text in plain text form
msgtext = smsg->get_text();
switch (smsg->content_type) {
case short_msg::TEXT_PLAIN:
return_action = pack_text_to_tpdu(msgtext, smsg);
break;
case short_msg::VND_3GPP_SMS:
// No need to recode if it's SC->MS already
if (smsg->ms_to_sc)
{
return_action = recode_tpdu(msgtext, smsg);
}
break;
case short_msg::UNSUPPORTED_CONTENT:
default:
LOG(WARN) << "Unsupported SIP-messages content.";
return false;
}
// Successful repack
if (return_action) {
smsg->need_repack = false;
}
if (ISLOGGING(DEBUG)) {
// Call make_text_valid() is needed for debug only.
smsg->make_text_valid();
LOG(DEBUG) << "Updated SMS message: " << smsg->text;
}
return return_action;
}

@ -0,0 +1,39 @@
/*
* SMSC.h - SMS Center implementation for OpenBTS.
* Written by Alexander Chemeris, 2010.
*
* Copyright 2010 Free Software Foundation, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* See the COPYING file in the main directory for details.
*/
#ifndef SMSC_H
#define SMSC_H
#include "smqueue.h"
using namespace SMqueue;
/** Unhex and parse msgtext to RPData struct.
@param msgttext RPData encoded into hex-string.
@return Pointer to parsed RPData or NULL on failure.
*/
RPData *hex2rpdata(const char *msgtext);
enum short_code_action shortcode_smsc(const char *imsi, const char *msgtext,
short_code_params *scp);
bool pack_sms_for_delivery(short_msg_p_list::iterator &smsg);
#endif