Checking in forgotten smsc.cpp and smsc.h files.
parent
970beeb816
commit
2b26d6cf26
|
@ -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
|
Reference in New Issue