/**@file SIP Call Control -- SIP IETF RFC-3261, RTP IETF RFC-3550. */
/*
* Copyright 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
* Copyright 2011 Range Networks, Inc.
*
* This software is distributed under the terms of the GNU Affero Public License.
* See the COPYING file in the main directory for details.
*
* This use of this software may be subject to additional restrictions.
* See the LEGAL file in the main directory for details.
	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 .
*/
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include "SIPInterface.h"
#include "SIPUtility.h"
#include "SIPMessage.h"
#include "SIPEngine.h"
#include "TransactionTable.h"
#undef WARNING
using namespace std;
using namespace SIP;
using namespace Control;
int get_rtp_tev_type(char dtmf){
        switch (dtmf){
                case '1': return TEV_DTMF_1;
                case '2': return TEV_DTMF_2;
                case '3': return TEV_DTMF_3;
                case '4': return TEV_DTMF_4;
                case '5': return TEV_DTMF_5;
                case '6': return TEV_DTMF_6;
                case '7': return TEV_DTMF_7;
                case '8': return TEV_DTMF_8;
                case '9': return TEV_DTMF_9;
                case '0': return TEV_DTMF_0;
                case '*': return TEV_DTMF_STAR;
                case '#': return TEV_DTMF_POUND;
                case 'a':
                case 'A': return TEV_DTMF_A;
                case 'B':
                case 'b': return TEV_DTMF_B;
                case 'C':
                case 'c': return TEV_DTMF_C;
                case 'D':
                case 'd': return TEV_DTMF_D;
		case '!': return TEV_FLASH;
                default:
		    LOG(WARNING) << "Bad dtmf: " << dtmf;
		    return -1;
                }
}
const char* SIP::SIPStateString(SIPState s)
{
	switch(s)
	{	
		case NullState: return "Null";
		case Timeout: return "Timeout";
		case Starting: return "Starting";
		case Proceeding: return "Proceeding";
		case Ringing: return "Ringing";
		case Connecting: return "Connecting";
		case Active: return "Active";
		case Fail: return "Fail"; 
		case Busy: return "Busy";
		case MODClearing: return "MODClearing";
		case MODCanceling: return "MODCanceling";
		case MTDClearing: return "MTDClearing";
		case MTDCanceling: return "MTDCanceling";
		case Canceled: return "Canceled";
		case Cleared: return "Cleared";
		case MessageSubmit: return "SMS-Submit";
		default: return NULL;
	}
}
ostream& SIP::operator<<(ostream& os, SIPState s)
{
	const char* str = SIPStateString(s);
	if (str) os << str;
	else os << "?" << s << "?";
	return os;
}
SIPEngine::SIPEngine(const char* proxy, const char* IMSI)
	:mCSeq(random()%1000),
	mMyToFromHeader(NULL), mRemoteToFromHeader(NULL),
	mCallIDHeader(NULL),
	mSIPPort(gConfig.getNum("SIP.Local.Port")),
	mSIPIP(gConfig.getStr("SIP.Local.IP")),
	mINVITE(NULL), mLastResponse(NULL), mBYE(NULL),
	mCANCEL(NULL), mERROR(NULL), mSession(NULL), 
	mTxTime(0), mRxTime(0), mState(NullState), mInstigator(false),
	mDTMF('\0'),mDTMFDuration(0)
{
	assert(proxy);
	if (IMSI) user(IMSI);
	if (!resolveAddress(&mProxyAddr,proxy)) {
		LOG(ALERT) << "cannot resolve IP address for " << proxy;
		return;
	}
	char host[256];
	const char* ret = inet_ntop(AF_INET,&(mProxyAddr.sin_addr),host,255);
	if (!ret) {
		LOG(ALERT) << "cannot translate proxy IP address";
		return;
	}
	mProxyIP = string(host);
	mProxyPort = ntohs(mProxyAddr.sin_port);
	// generate a tag now
	char tmp[50];
	make_tag(tmp);
	mMyTag=tmp;	
	// set our CSeq in case we need one
	mCSeq = random()%600;
	//to make sure noise doesn't magically equal a valid RTP port
	mRTPPort = 0;
}
SIPEngine::~SIPEngine()
{
	if (mINVITE!=NULL) osip_message_free(mINVITE);
	if (mLastResponse!=NULL) osip_message_free(mLastResponse);
	if (mBYE!=NULL) osip_message_free(mBYE);
	if (mCANCEL!=NULL) osip_message_free(mCANCEL);
	if (mERROR!=NULL) osip_message_free(mERROR);
	// FIXME -- Do we need to dispose of the RtpSesion *mSesison?
}
void SIPEngine::saveINVITE(const osip_message_t *INVITE, bool mine)
{
	// Instead of cloning, why not just keep the old one?
	// Because that doesn't work in all calling contexts.
	// This simplifies the call-handling logic.
	if (mINVITE!=NULL) osip_message_free(mINVITE);
	osip_message_clone(INVITE,&mINVITE);
	// #238-private
	if (mINVITE==NULL){
		LOG(ALERT) << "Message cloning failed, skipping this message.";
		return;
	} 
	mCallIDHeader = mINVITE->call_id;
	// If this our own INVITE?  Did we initiate the transaciton?
	if (mine) {
		mMyToFromHeader = mINVITE->from;
		mRemoteToFromHeader = mINVITE->to;
		return;
	}
	// It's not our own.  The From: is the remote party.
	mMyToFromHeader = mINVITE->to;
	mRemoteToFromHeader = mINVITE->from;
	// We need to set our tag, too.
	osip_from_set_tag(mMyToFromHeader, strdup(mMyTag.c_str()));
}
void SIPEngine::saveResponse(osip_message_t *response)
{
	if (mLastResponse!=NULL) osip_message_free(mLastResponse);
	osip_message_clone(response,&mLastResponse);
	// The To: is the remote party and might have an new tag.
	mRemoteToFromHeader = mLastResponse->to;
}
void SIPEngine::saveBYE(const osip_message_t *BYE, bool mine)
{
	// Instead of cloning, why not just keep the old one?
	// Because that doesn't work in all calling contexts.
	// This simplifies the call-handling logic.
	if (mBYE!=NULL) osip_message_free(mBYE);
	osip_message_clone(BYE,&mBYE);
}
void SIPEngine::saveCANCEL(const osip_message_t *CANCEL, bool mine)
{
	// Instead of cloning, why not just keep the old one?
	// Because that doesn't work in all calling contexts.
	// This simplifies the call-handling logic.
	if (mCANCEL!=NULL) osip_message_free(mCANCEL);
	osip_message_clone(CANCEL,&mCANCEL);
}
void SIPEngine::saveERROR(const osip_message_t *ERROR, bool mine)
{
	// Instead of cloning, why not just keep the old one?
	// Because that doesn't work in all calling contexts.
	// This simplifies the call-handling logic.
	if (mERROR!=NULL) osip_message_free(mERROR);
	osip_message_clone(ERROR,&mERROR);
}
#if 0
This was replaced with a simple flag set during MO transactions.
/* we're going to figure if the from field is us or not */
bool SIPEngine::instigator()
{
	assert(mINVITE);
	osip_uri_t * from_uri = mINVITE->from->url;
	return (!strncmp(from_uri->username,mSIPUsername.c_str(),15) &&
		!strncmp(from_uri->host, mSIPIP.c_str(), 30));
}
#endif
void SIPEngine::user( const char * IMSI )
{
	LOG(DEBUG) << "IMSI=" << IMSI;
	unsigned id = random();
	char tmp[20];
	sprintf(tmp, "%u", id);
	mCallID = tmp; 
	// IMSI gets prefixed with "IMSI" to form a SIP username
	mSIPUsername = string("IMSI") + IMSI;
}
	
void SIPEngine::user( const char * wCallID, const char * IMSI, const char *origID, const char *origHost) 
{
	LOG(DEBUG) << "IMSI=" << IMSI << " " << wCallID << " " << origID << "@" << origHost;  
	mSIPUsername = string("IMSI") + IMSI;
	mCallID = string(wCallID);
	mRemoteUsername = string(origID);
	mRemoteDomain = string(origHost);
}
void SIPEngine::writePrivateHeaders(osip_message_t *msg, const GSM::LogicalChannel *chan)
{
	// P-PHY-Info
	// This is a non-standard private header in OpenBTS.
	// TA= TE= UpRSSI= TxPwr= DnRSSIdBm=
	// Get the values
#if 0
	if (chan) {
		char phy_info[200];
		sprintf(phy_info,"OpenBTS; TA=%d TE=%f UpRSSI=%f TxPwr=%d DnRSSIdBm=%d",
			chan->actualMSTiming(), chan->timingError(),
			chan->RSSI(), chan->actualMSPower(),
			chan->measurementResults().RXLEV_FULL_SERVING_CELL_dBm());
		osip_message_set_header(msg,"P-PHY-Info",phy_info);
	}
#endif
	// P-Access-Network-Info
	// See 3GPP 24.229 7.2.
	char cgi_3gpp[50];
	sprintf(cgi_3gpp,"3GPP-GERAN; cgi-3gpp=%s%s%04x%04x",
		gConfig.getStr("GSM.Identity.MCC").c_str(),gConfig.getStr("GSM.Identity.MNC").c_str(),
		(unsigned)gConfig.getNum("GSM.Identity.LAC"),(unsigned)gConfig.getNum("GSM.Identity.CI"));
	osip_message_set_header(msg,"P-Access-Network-Info",cgi_3gpp);
 
	// P-Preferred-Identity
	// See RFC-3325.
	char pref_id[50];
	sprintf(pref_id,"",
		mSIPUsername.c_str(),
		gConfig.getStr("SIP.Proxy.Speech").c_str());
	osip_message_set_header(msg,"P-Preferred-Identity",pref_id);
	// FIXME -- Use the subscriber registry to look up the E.164
	// and make a second P-Preferred-Identity header.
}
bool SIPEngine::Register( Method wMethod )
{
	LOG(INFO) << "user " << mSIPUsername << " state " << mState << " " << wMethod << " callID " << mCallID;
	// Before start, need to add mCallID
	gSIPInterface.addCall(mCallID);
	// Initial configuration for sip message.
	// Make a new from tag and new branch.
	// make new mCSeq.
	
	// Generate SIP Message 
	// Either a register or unregister. Only difference 
	// is expiration period.
	osip_message_t * reg; 
	if (wMethod == SIPRegister ){
		reg = sip_register( mSIPUsername.c_str(), 
			60*gConfig.getNum("SIP.RegistrationPeriod"),
			mSIPPort, mSIPIP.c_str(), 
			mProxyIP.c_str(), mMyTag.c_str(), 
			mViaBranch.c_str(), mCallID.c_str(), mCSeq
		); 
	} else if (wMethod == SIPUnregister ) {
		reg = sip_register( mSIPUsername.c_str(), 
			0,
			mSIPPort, mSIPIP.c_str(), 
			mProxyIP.c_str(), mMyTag.c_str(), 
			mViaBranch.c_str(), mCallID.c_str(), mCSeq
		);
	} else { assert(0); }
 
	LOG(DEBUG) << "writing registration " << reg;
	gSIPInterface.write(&mProxyAddr,reg);	
	bool success = false;
	osip_message_t *msg = NULL;
	Timeval timeout(gConfig.getNum("SIP.Timer.F"));
	while (!timeout.passed()) {
		try {
			// SIPInterface::read will throw SIPTIimeout if it times out.
			// It should not return NULL.
			msg = gSIPInterface.read(mCallID, gConfig.getNum("SIP.Timer.E"));
		} catch (SIPTimeout) {
			// send again
			gSIPInterface.write(&mProxyAddr,reg);	
			continue;
		}
		assert(msg);
		int status = msg->status_code;
		LOG(INFO) << "received status " << msg->status_code << " " << msg->reason_phrase;
		// specific status
		if (status==200) {
			LOG(INFO) << "REGISTER success";
			success = true;
			break;
		}
		if (status==401) {
			LOG(INFO) << "REGISTER fail -- unauthorized";
			break;
		}
		if (status==404) {
			LOG(INFO) << "REGISTER fail -- not found";
			break;
		}
		if (status>=200) {
			LOG(NOTICE) << "REGISTER unexpected response " << status;
			break;
		}
	}
	if (!msg) {
		LOG(ALERT) << "SIP REGISTER timed out; is the registration server " << mProxyIP << ":" << mProxyPort << " OK?";
		throw SIPTimeout();
	}
	osip_message_free(reg);
	osip_message_free(msg);
	// We remove the call FIFO here because there
	// is no transaction entry associated with the REGISTER.
	gSIPInterface.removeCall(mCallID);	
	return success;
}
const char* geoprivTemplate = 
"\n"
 "\n"
  "\n"
   "\n"
    "\n"
     "\n"
      "\n"
       "\n"
        "%s\n"
       "\n"
      "\n"
     "\n"
     "\n"
      "no\n"
     "\n"
    "\n"
   "\n"
  "\n"
 "\n";
SIPState SIPEngine::SOSSendINVITE(short wRtp_port, unsigned  wCodec, const GSM::LogicalChannel *chan)
{
	LOG(INFO) << "user " << mSIPUsername << " state " << mState;
	// Before start, need to add mCallID
	gSIPInterface.addCall(mCallID);
	
	// Set Invite params. 
	// new CSEQ and codec 
	char tmp[50];
	make_branch(tmp);
	mViaBranch = tmp;
	mCodec = wCodec;
	mCSeq++;
	mRemoteDomain = gConfig.getStr("Control.Emergency.Destination.Host");
	mRemoteUsername = gConfig.getStr("Control.Emergency.Destination.User");
	mRTPPort= wRtp_port;
	
	LOG(DEBUG) << "To: " << mRemoteUsername << "@" << mRemoteDomain;
	LOG(DEBUG) << "From: " << mSIPUsername << "@" << mSIPIP;
	osip_message_t *invite;
	if (gConfig.defines("Control.Emergency.RFC5031")) {
		invite = sip_invite5031(
			mRTPPort, mSIPUsername.c_str(), 
			mSIPPort, mSIPIP.c_str(), mProxyIP.c_str(),
			mMyTag.c_str(), mViaBranch.c_str(), mCallID.c_str(), mCSeq, mCodec); 
	} else {
		invite = sip_invite(
			mRemoteUsername.c_str(), mRTPPort, mSIPUsername.c_str(), 
			mSIPPort, mSIPIP.c_str(), mProxyIP.c_str(), 
			mMyTag.c_str(), mViaBranch.c_str(), mCallID.c_str(), mCSeq, mCodec); 
	}
	writePrivateHeaders(invite,chan);
	// Add RFC-4119 geolocation XML to content area, if available.
	if (gConfig.defines("Control.Emergency.Geolocation")) {
		char xml[strlen(geoprivTemplate) + 100];
		sprintf(xml,geoprivTemplate,
			mSIPUsername.c_str(), gConfig.getStr("Control.Emergency.GatewaySwitch").c_str(),
			gConfig.getStr("Control.Emergency.Geolocation").c_str());
		osip_message_set_content_type(invite, strdup("application/pidf+xml"));
		char tmp[20];
		sprintf(tmp,"%u",strlen(xml));
		osip_message_set_content_length(invite, strdup(tmp));
		osip_message_set_body(invite,xml,strlen(xml));
	}
	
	// Send Invite to Asterisk.
	gSIPInterface.write(&mProxyAddr,invite);
	saveINVITE(invite,true);
	osip_message_free(invite);
	mState = Starting;
	return mState;
};
SIPState SIPEngine::MOCSendINVITE( const char * wCalledUsername, 
	const char * wCalledDomain , short wRtp_port, unsigned  wCodec,
	const GSM::LogicalChannel *chan)
{
	LOG(INFO) << "user " << mSIPUsername << " state " << mState;
	// Before start, need to add mCallID
	gSIPInterface.addCall(mCallID);
	mInstigator = true;
	
	// Set Invite params. 
	// new CSEQ and codec 
	char tmp[50];
	make_branch(tmp);
	mViaBranch = tmp;
	mCodec = wCodec;
	mCSeq++;
	mRemoteUsername = wCalledUsername;
	mRemoteDomain = wCalledDomain;
	mRTPPort= wRtp_port;
	
	LOG(DEBUG) << "mRemoteUsername=" << mRemoteUsername;
	LOG(DEBUG) << "mSIPUsername=" << mSIPUsername;
	osip_message_t * invite = sip_invite(
		mRemoteUsername.c_str(), mRTPPort, mSIPUsername.c_str(), 
		mSIPPort, mSIPIP.c_str(), mProxyIP.c_str(), 
		mMyTag.c_str(), mViaBranch.c_str(), mCallID.c_str(), mCSeq, mCodec); 
	writePrivateHeaders(invite,chan);
	
	// Send Invite.
	gSIPInterface.write(&mProxyAddr,invite);
	saveINVITE(invite,true);
	osip_message_free(invite);
	mState = Starting;
	return mState;
};
SIPState SIPEngine::MOCResendINVITE()
{
	assert(mINVITE);
	LOG(INFO) << "user " << mSIPUsername << " state " << mState;
	gSIPInterface.write(&mProxyAddr,mINVITE);
	return mState;
}
SIPState  SIPEngine::MOCCheckForOK(Mutex *lock)
{
	LOG(INFO) << "user " << mSIPUsername << " state " << mState;
	osip_message_t * msg;
	// Read off the fifo. if time out will
	// clean up and return false.
	try {
		msg = gSIPInterface.read(mCallID, gConfig.getNum("SIP.Timer.A"),lock);
	}
	catch (SIPTimeout& e) { 
		LOG(DEBUG) << "timeout";
		//if we got a 100 TRYING (SIP::Proceeding)
		//don't time out
		if (mState != SIP::Proceeding){
			mState = Timeout;
		}
		return mState;
	}
	int status = msg->status_code;
	LOG(DEBUG) << "received status " << status;
	saveResponse(msg);
	switch (status) {
		// class 1XX: Provisional messages
		case 100:	// Trying
		case 181:	// Call Is Being Forwarded
		case 182:	// Queued
		case 183:	// Session Progress FIXME we need to setup the sound channel (early media)
			mState = Proceeding;
			break;
		case 180:	// Ringing
			mState = Ringing;
			break;
		case 200:	// OK
			// Save the response and update the state,
			// but the ACK doesn't happen until the call connects.
			mState = Active;
			break;
		// Anything 400 or above terminates the call, so we ACK.
		// FIXME -- It would be nice to save more information about the
		// specific failure cause.
		case 486:
		case 503:
			mState = Busy;
			MOCSendACK();
			break;
		default:
			LOG(NOTICE) << "unhandled status code " << status;
			mState = Fail;
			MOCSendACK();
	}
	osip_message_free(msg);
	LOG(DEBUG) << " new state: " << mState;
	return mState;
}
SIPState SIPEngine::MOCSendACK()
{
	assert(mLastResponse);
	LOG(INFO) << "user " << mSIPUsername << " state " << mState;
	osip_message_t* ack = sip_ack( mRemoteDomain.c_str(),
		mRemoteUsername.c_str(), 
		mSIPUsername.c_str(),
		mSIPPort, mSIPIP.c_str(), mProxyIP.c_str(), 
		mMyToFromHeader, mRemoteToFromHeader,
		mViaBranch.c_str(), mCallIDHeader, mCSeq
	);
	gSIPInterface.write(&mProxyAddr,ack);
	osip_message_free(ack);	
	return mState;
}
SIPState SIPEngine::MODSendBYE()
{
	LOG(INFO) << "user " << mSIPUsername << " state " << mState;
	assert(mINVITE);
	char tmp[50];
	make_branch(tmp);
	mViaBranch = tmp;
	mCSeq++;
	osip_message_t * bye = sip_bye(mRemoteDomain.c_str(), mRemoteUsername.c_str(), 
		mSIPUsername.c_str(),
		mSIPPort, mSIPIP.c_str(), mProxyIP.c_str(), mProxyPort,
		mMyToFromHeader, mRemoteToFromHeader,
		mViaBranch.c_str(), mCallIDHeader, mCSeq );
	gSIPInterface.write(&mProxyAddr,bye);
	saveBYE(bye,true);
	osip_message_free(bye);
	mState = MODClearing;
	return mState;
}
SIPState SIPEngine::MODSendERROR(osip_message_t * cause, int code, const char * reason, bool cancel)
{
	LOG(INFO) << "user " << mSIPUsername << " state " << mState;
	if (NULL == cause){
		assert(mINVITE);
		cause = mINVITE;
	}
	
	/* 480 is unavail */
	osip_message_t * unavail = sip_error(cause, mSIPIP.c_str(),
					     mSIPUsername.c_str(), mSIPPort, 
					     code, reason);
	gSIPInterface.write(&mProxyAddr,unavail);
	saveERROR(unavail, true);
	osip_message_free(unavail);
	if (cancel){
		mState = MODCanceling;
	}
	return mState;
}
SIPState SIPEngine::MODSendCANCEL()
{
	LOG(INFO) << "user " << mSIPUsername << " state " << mState;
	assert(mINVITE);
	osip_message_t * cancel = sip_cancel(mINVITE, mSIPIP.c_str(),
					     mSIPUsername.c_str(), mSIPPort);
	gSIPInterface.write(&mProxyAddr,cancel);
	saveCANCEL(cancel, true);
	osip_message_free(cancel);
	mState = MODCanceling;
	return mState;
}
	
SIPState SIPEngine::MODResendBYE()
{
	LOG(INFO) << "user " << mSIPUsername << " state " << mState;
	assert(mState==MODClearing);
	assert(mBYE);
	gSIPInterface.write(&mProxyAddr,mBYE);
	return mState;
}
SIPState SIPEngine::MODResendCANCEL()
{
	LOG(INFO) << "user " << mSIPUsername << " state " << mState;
	assert(mState==MODCanceling);
	assert(mCANCEL);
	gSIPInterface.write(&mProxyAddr,mCANCEL);
	return mState;
}
SIPState SIPEngine::MODResendERROR(bool cancel)
{
	LOG(INFO) << "user " << mSIPUsername << " state " << mState;
	if (cancel){
		if (mState!=MODCanceling) LOG(ERR) << "incorrect state for this method";
	}
	assert(mERROR);
	gSIPInterface.write(&mProxyAddr,mERROR);
	return mState;
}
/* there shouldn't be any more communications on this fifo, but we might
   get a 487 RequestTerminated. We only need to respond and move on -kurtis */
SIPState SIPEngine::MODWaitFor487(Mutex *lock)
{
	LOG(INFO) << "user " << mSIPUsername << " state " << mState;
	osip_message_t * msg;
	try {
		msg = gSIPInterface.read(mCallID, gConfig.getNum("SIP.Timer.E"), lock);
	}
	catch (SIPTimeout& e) {
		LOG(NOTICE) << "487 Timeout";
		return mState;
	}
	//ok, message arrived
	if (msg->status_code != 487){
		LOG(WARNING) << "unexpected " << msg->status_code << 
		  " response to CANCEL, from proxy " << mProxyIP << ":" << mProxyPort;
		return mState;
	} else {
		osip_message_t* ack = sip_ack( mRemoteDomain.c_str(),
					       mRemoteUsername.c_str(), 
					       mSIPUsername.c_str(),
					       mSIPPort, mSIPIP.c_str(), mProxyIP.c_str(), 
					       mMyToFromHeader, mRemoteToFromHeader,
					       mViaBranch.c_str(), mCallIDHeader, mCSeq
	);
		gSIPInterface.write(&mProxyAddr,ack);
		osip_message_free(ack);
		return mState;
	}
}
SIPState SIPEngine::MODWaitForBYEOK(Mutex *lock)
{
	LOG(INFO) << "user " << mSIPUsername << " state " << mState;
	bool responded = false;
	Timeval timeout(gConfig.getNum("SIP.Timer.F")); 
	while (!timeout.passed()) {
		try {
			osip_message_t * ok = gSIPInterface.read(mCallID, gConfig.getNum("SIP.Timer.E"),lock);
			responded = true;
			unsigned code = ok->status_code;
			saveResponse(ok);
			osip_message_free(ok);
			if (code!=200) {
				LOG(WARNING) << "unexpected " << code << " response to BYE, from proxy " << mProxyIP << ":" << mProxyPort << ". Assuming other end has cleared";
			}
			break;
		}
		catch (SIPTimeout& e) {
			LOG(NOTICE) << "response timeout, resending BYE";
			MODResendBYE();
		}
	}
	if (!responded) { LOG(ALERT) << "lost contact with proxy " << mProxyIP << ":" << mProxyPort; }
	mState = Cleared;
	return mState;
}
SIPState SIPEngine::MODWaitForCANCELOK(Mutex *lock)
{
	LOG(INFO) << "user " << mSIPUsername << " state " << mState;
	bool responded = false;
	Timeval timeout(gConfig.getNum("SIP.Timer.F")); 
	while (!timeout.passed()) {
		try {
			osip_message_t * ok = gSIPInterface.read(mCallID, gConfig.getNum("SIP.Timer.E"),lock);
			responded = true;
			unsigned code = ok->status_code;
			saveResponse(ok);
			osip_message_free(ok);
			if (code!=200) {
				LOG(WARNING) << "unexpected " << code << " response to CANCEL, from proxy " << mProxyIP << ":" << mProxyPort << ". Assuming other end has cleared";
			}
			break;
		}
		catch (SIPTimeout& e) {
			LOG(NOTICE) << "response timeout, resending CANCEL";
			MODResendCANCEL();
		}
	}
	if (!responded) { LOG(ALERT) << "lost contact with proxy " << mProxyIP << ":" << mProxyPort; }
	mState = Canceled;
	return mState;
}
static bool containsResponse(vector *validResponses, unsigned code)
{
	for (int i = 0; i < validResponses->size(); i++) {
		if (validResponses->at(i) == code)
			return true;
	}
	return false;
}
SIPState SIPEngine::MODWaitForResponse(vector *validResponses, Mutex *lock)
{
	LOG(INFO) << "user " << mSIPUsername << " state " << mState;
	assert(validResponses);
	bool responded = false;
	Timeval timeout(gConfig.getNum("SIP.Timer.F")); 
	while (!timeout.passed()) {
		try {
			osip_message_t * resp = gSIPInterface.read(mCallID, gConfig.getNum("SIP.Timer.E"),lock);
			responded = true;
			unsigned code = resp->status_code;
			if (code==200) {
				saveResponse(resp);
				mState = Canceled;
			}
			if (code==487) {
				osip_message_t* ack = sip_ack( mRemoteDomain.c_str(),
					       mRemoteUsername.c_str(), 
					       mSIPUsername.c_str(),
					       mSIPPort, mSIPIP.c_str(), mProxyIP.c_str(), 
					       mMyToFromHeader, mRemoteToFromHeader,
					       mViaBranch.c_str(), mCallIDHeader, mCSeq);
				gSIPInterface.write(&mProxyAddr,ack);
				osip_message_free(ack);
			}
			osip_message_free(resp);
			if (!containsResponse(validResponses, code)) {
				LOG(WARNING) << "unexpected " << code << " response to CANCEL, from proxy " << mProxyIP << ":" << mProxyPort << ". Assuming other end has cleared";
			}
			break;
		}
		catch (SIPTimeout& e) {
			LOG(NOTICE) << "response timeout, resending CANCEL";
			MODResendCANCEL();
		}
	}
	if (!responded) { LOG(ALERT) << "lost contact with proxy " << mProxyIP << ":" << mProxyPort; }
	return mState;
}
SIPState SIPEngine::MODWaitForERRORACK(bool cancel, Mutex *lock)
{
	LOG(INFO) << "user " << mSIPUsername << " state " << mState;
	bool responded = false;
	Timeval timeout(gConfig.getNum("SIP.Timer.F")); 
	while (!timeout.passed()) {
		try {
			osip_message_t * ack = gSIPInterface.read(mCallID, gConfig.getNum("SIP.Timer.E"),lock);
			responded = true;
			saveResponse(ack);
			if ((NULL == ack->sip_method) || !strncmp(ack->sip_method,"ACK", 4)) {
				LOG(WARNING) << "unexpected response to ERROR, from proxy " << mProxyIP << ":" << mProxyPort << ". Assuming other end has cleared";
			}
			osip_message_free(ack);
			break;
		}
		catch (SIPTimeout& e) {
			LOG(NOTICE) << "response timeout, resending ERROR";
			MODResendERROR(cancel);
		}
	}
	if (!responded) { LOG(ALERT) << "lost contact with proxy " << mProxyIP << ":" << mProxyPort; }
	if (cancel){
		mState = Canceled;
	}
	return mState;
}
SIPState SIPEngine::MTDCheckBYE()
{
	//LOG(DEBUG) << "user " << mSIPUsername << " state " << mState;
	// If the call is not active, there should be nothing to check.
	if (mState!=Active) return mState;
	// Need to check size of osip_message_t* fifo,
	// so need to get fifo pointer and get size.
	// HACK -- reach deep inside to get damn thing
	int fifoSize = gSIPInterface.fifoSize(mCallID);
	// Size of -1 means the FIFO does not exist.
	// Treat the call as cleared.
	if (fifoSize==-1) {
		LOG(NOTICE) << "MTDCheckBYE attempt to check BYE on non-existant SIP FIFO";
		mState=Cleared;
		return mState;
	}
	// If no messages, there is no change in state.
	if (fifoSize==0) return mState;	
		
	osip_message_t * msg = gSIPInterface.read(mCallID);
	
	if (msg->sip_method) {
		if (strcmp(msg->sip_method,"BYE")==0) { 
			LOG(DEBUG) << "found msg="<sip_method;	
			saveBYE(msg,false);
			mState =  MTDClearing;
		}
		//repeated ACK, send OK
		//pretty sure this never happens, but someone else left a fixme before... -kurtis
		if (strcmp(msg->sip_method,"ACK")==0) { 	
			LOG(DEBUG) << "Not responding to repeated ACK. FIXME";
		}
	}
	//repeated OK, send ack
	//MOC because that's the only time we ACK
	if (msg->status_code==200){
		LOG(DEBUG) << "Repeated OK, resending ACK";
		MOCSendACK();
	}
	osip_message_free(msg);
	return mState;
} 
SIPState SIPEngine::MTDSendBYEOK()
{
	LOG(INFO) << "user " << mSIPUsername << " state " << mState;
	assert(mBYE);
	osip_message_t * okay = sip_b_okay(mBYE);
	gSIPInterface.write(&mProxyAddr,okay);
	osip_message_free(okay);
	mState = Cleared;
	return mState;
}
SIPState SIPEngine::MTDSendCANCELOK()
{
	LOG(INFO) << "user " << mSIPUsername << " state " << mState;
	assert(mCANCEL);
	osip_message_t * okay = sip_b_okay(mCANCEL);
	gSIPInterface.write(&mProxyAddr,okay);
	osip_message_free(okay);
	mState = Canceled;
	return mState;
}
SIPState SIPEngine::MTCSendTrying()
{
	LOG(INFO) << "user " << mSIPUsername << " state " << mState;
	if (mINVITE==NULL) mState=Fail;
	if (mState==Fail) return mState;
	osip_message_t * trying = sip_trying(mINVITE, mSIPUsername.c_str(), mProxyIP.c_str());
	gSIPInterface.write(&mProxyAddr,trying);
	osip_message_free(trying);
	mState=Proceeding;
	return mState;
}
SIPState SIPEngine::MTCSendRinging()
{
	LOG(INFO) << "user " << mSIPUsername << " state " << mState;
	assert(mINVITE);
	LOG(DEBUG) << "send ringing";
	osip_message_t * ringing = sip_ringing(mINVITE, 
		mSIPUsername.c_str(), mProxyIP.c_str());
	gSIPInterface.write(&mProxyAddr,ringing);
	osip_message_free(ringing);
	mState = Proceeding;
	return mState;
}
SIPState SIPEngine::MTCSendOK( short wRTPPort, unsigned wCodec, const GSM::LogicalChannel *chan)
{
	LOG(INFO) << "user " << mSIPUsername << " state " << mState;
	assert(mINVITE);
	mRTPPort = wRTPPort;
	mCodec = wCodec;
	LOG(DEBUG) << "port=" << wRTPPort << " codec=" << mCodec;
	// Form ack from invite and new parameters.
	osip_message_t * okay = sip_okay_sdp(mINVITE, mSIPUsername.c_str(),
		mSIPIP.c_str(), mSIPPort, mRTPPort, mCodec);
	writePrivateHeaders(okay,chan);
	gSIPInterface.write(&mProxyAddr,okay);
	osip_message_free(okay);
	mState=Connecting;
	return mState;
}
SIPState SIPEngine::MTCCheckForACK(Mutex *lock)
{
	// wait for ack,set this to timeout of 
	// of call channel.  If want a longer timeout 
	// period, need to split into 2 handle situation 
	// like MOC where this fxn if called multiple times. 
	LOG(INFO) << "user " << mSIPUsername << " state " << mState;
	osip_message_t * ack;
	// FIXME -- This is supposed to retransmit BYE on timer I.
	try {
		ack = gSIPInterface.read(mCallID, gConfig.getNum("SIP.Timer.H"), lock);
	}
	catch (SIPTimeout& e) {
		LOG(NOTICE) << "timeout";
		mState = Timeout;	
		return mState;
	}
	catch (SIPError& e) {
		LOG(NOTICE) << "read error";
		mState = Fail;
		return mState;
	}
	if (ack->sip_method==NULL) {
		LOG(NOTICE) << "SIP message with no method, status " <<  ack->status_code;
		mState = Fail;
		osip_message_free(ack);
		return mState;	
	}
	LOG(INFO) << "received sip_method="<sip_method;
	// check for duplicated INVITE
	if( strcmp(ack->sip_method,"INVITE") == 0){ 
		LOG(NOTICE) << "received duplicate INVITE";
	}
	// check for the ACK
	else if( strcmp(ack->sip_method,"ACK") == 0){ 
		LOG(INFO) << "received ACK";
		mState=Active;
	}
	// check for the CANCEL
	else if( strcmp(ack->sip_method,"CANCEL") == 0){ 
		LOG(INFO) << "received CANCEL";
		saveCANCEL(ack, false);
		mState=MTDCanceling;
	}
	// check for strays
	else {
		LOG(NOTICE) << "unexpected Message "<sip_method; 
		mState = Fail;
	}
	osip_message_free(ack);
	return mState;	
}
SIPState SIPEngine::MTCCheckForCancel()
{
	// wait for ack,set this to timeout of 
	// of call channel.  If want a longer timeout 
	// period, need to split into 2 handle situation 
	// like MOC where this fxn if called multiple times. 
	LOG(INFO) << "user " << mSIPUsername << " state " << mState;
	osip_message_t * msg;
	try {
		//block for very small amount of time
		msg = gSIPInterface.read(mCallID,1);
	}
	catch (SIPTimeout& e) {
		return mState;
	}
	catch (SIPError& e) {
		LOG(NOTICE) << "read error";
		mState = Fail;
		return mState;
	}
	if (msg->sip_method==NULL) {
		LOG(NOTICE) << "SIP message with no method, status " <<  msg->status_code;
		mState = Fail;
		osip_message_free(msg);
		return mState;	
	}
	LOG(INFO) << "received sip_method=" << msg->sip_method;
	// check for duplicated INVITE
	if (strcmp(msg->sip_method,"INVITE")==0) { 
		LOG(NOTICE) << "received duplicate INVITE";
	}
	// check for the CANCEL
	else if (strcmp(msg->sip_method,"CANCEL")==0) { 
		LOG(INFO) << "received CANCEL";
		saveCANCEL(msg, false);
		mState=MTDCanceling;
	}
	// check for strays
	else {
		LOG(NOTICE) << "unexpected Message " << msg->sip_method; 
		mState = Fail;
	}
	osip_message_free(msg);
	return mState;
}
void SIPEngine::InitRTP(const osip_message_t * msg )
{
	if(mSession == NULL)
		mSession = rtp_session_new(RTP_SESSION_SENDRECV);
	bool rfc2833 = gConfig.defines("SIP.DTMF.RFC2833");
	if (rfc2833) {
		RtpProfile* profile = rtp_session_get_send_profile(mSession);
		int index = gConfig.getNum("SIP.DTMF.RFC2833.PayloadType");
		rtp_profile_set_payload(profile,index,&payload_type_telephone_event);
		// Do we really need this next line?
		rtp_session_set_send_profile(mSession,profile);
	}
	rtp_session_set_blocking_mode(mSession, TRUE);
	rtp_session_set_scheduling_mode(mSession, TRUE);
	rtp_session_set_connected_mode(mSession, TRUE);
	rtp_session_set_symmetric_rtp(mSession, TRUE);
	// Hardcode RTP session type to GSM full rate (GSM 06.10).
	// FIXME -- Make this work for multiple vocoder types.
	rtp_session_set_payload_type(mSession, 3);
	char d_ip_addr[20];
	char d_port[10];
	get_rtp_params(msg, d_port, d_ip_addr);
	LOG(DEBUG) << "IP="< 0) return true;
	// Error?  Turn off DTMF sending.
	LOG(WARNING) << "DTMF RFC-2833 failed on start.";
	mDTMF = '\0';
	return false;
}
void SIPEngine::stopDTMF()
{
	//false means not start
	mblk_t *m = rtp_session_create_telephone_event_packet(mSession,false);
	//volume 10 for some magic reason, end is true
	int code = rtp_session_add_telephone_event(mSession,m,get_rtp_tev_type(mDTMF),true,10,mDTMFDuration);
	int bytes = rtp_session_sendm_with_ts(mSession,m,mDTMFStartTime);
	mDTMFDuration += 160;
	LOG (DEBUG) << "DTMF RFC-2833 sending " << mDTMF << " " << mDTMFDuration;
	// Turn it off if there's an error.
	if (code || bytes <= 0) {
	    LOG(ERR) << "DTMF RFC-2833 failed at end";
	}
	mDTMF='\0';
}
void SIPEngine::txFrame(unsigned char* frame )
{
	if(mState!=Active) return;
	// HACK -- Hardcoded for GSM/8000.
	// FIXME -- Make this work for multiple vocoder types.
	rtp_session_send_with_ts(mSession, frame, 33, mTxTime);
	mTxTime += 160;
	if (mDTMF) {
		//false means not start
		mblk_t *m = rtp_session_create_telephone_event_packet(mSession,false);
		//volume 10 for some magic reason, false means not end
		int code = rtp_session_add_telephone_event(mSession,m,get_rtp_tev_type(mDTMF),false,10,mDTMFDuration);
		int bytes = rtp_session_sendm_with_ts(mSession,m,mDTMFStartTime);
		mDTMFDuration += 160;
		LOG (DEBUG) << "DTMF RFC-2833 sending " << mDTMF << " " << mDTMFDuration;
		// Turn it off if there's an error.
		if (code || bytes <=0) {
			LOG(ERR) << "DTMF RFC-2833 failed after start.";
			mDTMF='\0';
		}
	}
}
int SIPEngine::rxFrame(unsigned char* frame)
{
	if(mState!=Active) return 0; 
	int more;
	int ret=0;
	// HACK -- Hardcoded for GSM/8000.
	// FIXME -- Make this work for multiple vocoder types.
	ret = rtp_session_recv_with_ts(mSession, frame, 33, mRxTime, &more);
	mRxTime += 160;
	return ret;
}
SIPState SIPEngine::MOSMSSendMESSAGE(const char * wCalledUsername, 
	const char * wCalledDomain , const char *messageText, const char *contentType,
	const GSM::LogicalChannel *chan)
{
	LOG(DEBUG) << "mState=" << mState;
	LOG(INFO) << "SIP send to " << wCalledUsername << "@" << wCalledDomain << " MESSAGE " << messageText;
	// Before start, need to add mCallID
	gSIPInterface.addCall(mCallID);
	mInstigator = true;
	
	// Set MESSAGE params. 
	char tmp[50];
	make_branch(tmp);
	mViaBranch = tmp;
	mCSeq++;
	mRemoteUsername = wCalledUsername;
	mRemoteDomain = wCalledDomain;
	osip_message_t * message = sip_message(
		mRemoteUsername.c_str(), mSIPUsername.c_str(), 
		mSIPPort, mSIPIP.c_str(), mProxyIP.c_str(), 
		mMyTag.c_str(), mViaBranch.c_str(), mCallID.c_str(), mCSeq,
		messageText, contentType); 
	writePrivateHeaders(message,chan);
	// Send Invite to the SIP proxy.
	gSIPInterface.write(&mProxyAddr,message);
	saveINVITE(message,true);
	osip_message_free(message);
	mState = MessageSubmit;
	return mState;
};
SIPState SIPEngine::MOSMSWaitForSubmit(Mutex *lock)
{
	LOG(INFO) << "user " << mSIPUsername << " state " << mState;
	Timeval timeout(gConfig.getNum("SIP.Timer.B"));
	assert(mINVITE);
	osip_message_t *ok = NULL;
	// have we received a 100 TRYING message? If so, don't retransmit after timeout
	bool recv_trying = false;
	while (!timeout.passed()) {
		try {
			// SIPInterface::read will throw SIPTIimeout if it times out.
			// It should not return NULL.
			ok = gSIPInterface.read(mCallID, gConfig.getNum("SIP.Timer.A"),lock);
		}
		catch (SIPTimeout& e) {
			if (!recv_trying){
				LOG(NOTICE) << "SIP MESSAGE packet to " << mProxyIP << ":" << mProxyPort << " timedout; resending"; 
				gSIPInterface.write(&mProxyAddr,mINVITE);
			} else {
			  	LOG(NOTICE) << "SIP MESSAGE packet to " << mProxyIP << ":" << mProxyPort << " timedout; ignoring (got 100 TRYING)"; 
			}
			continue;
		}
		assert(ok);
		if((ok->status_code==100)) {
			recv_trying = true;
			LOG(INFO) << "received TRYING MESSAGE";
		}
		if((ok->status_code==200) || (ok->status_code==202) ) {
			mState = Cleared;
			LOG(INFO) << "successful SIP MESSAGE SMS submit to " << mProxyIP << ":" << mProxyPort << ": " << mINVITE;
			break;
		}
		//demonstrate that these are not forwarded correctly
		if (ok->status_code >= 400){
			mState = Fail;
			LOG (ALERT) << "SIP MESSAGE rejected: " << ok->status_code << " " << ok->reason_phrase;
			break;
		}
		LOG(WARNING) << "unhandled response " << ok->status_code;
		osip_message_free(ok);
		ok = NULL;
	}
	if (!ok) {
		//changed from "throw SIPTimeout()", as this seems more correct -k
		mState = Fail;
		LOG(ALERT) << "SIP MESSAGE timed out; is the smqueue server " << mProxyIP << ":" << mProxyPort << " OK?";
	} else {
		osip_message_free(ok);
	}
	return mState;
}
SIPState SIPEngine::MTSMSSendOK(const GSM::LogicalChannel *chan)
{
	LOG(INFO) << "user " << mSIPUsername << " state " << mState;
	// If this operation was initiated from the CLI, there was no INVITE.
	if (!mINVITE) {
		LOG(INFO) << "clearing CLI-generated transaction";
		mState=Cleared;
		return mState;
	}
	// Form ack from invite and new parameters.
	osip_message_t * okay = sip_okay(mINVITE, mSIPUsername.c_str(),
		mSIPIP.c_str(), mSIPPort);
	writePrivateHeaders(okay,chan);
	gSIPInterface.write(&mProxyAddr,okay);
	osip_message_free(okay);
	mState=Cleared;
	return mState;
}
bool SIPEngine::sendINFOAndWaitForOK(unsigned wInfo, Mutex *lock)
{
	LOG(INFO) << "user " << mSIPUsername << " state " << mState;
	char tmp[50];
	make_branch(tmp);
	mViaBranch = tmp;
	mCSeq++;
	osip_message_t * info = sip_info( wInfo,
		mRemoteUsername.c_str(), mRTPPort, mSIPUsername.c_str(), 
		mSIPPort, mSIPIP.c_str(), mProxyIP.c_str(), 
		mMyTag.c_str(), mViaBranch.c_str(), mCallIDHeader, mCSeq); 
	gSIPInterface.write(&mProxyAddr,info);
	Timeval timeout(gConfig.getNum("SIP.Timer.F"));
	osip_message_t *ok = NULL;
	while (!timeout.passed()) {
		try {
			// This will timeout on failure.  It will not return NULL.
			ok = gSIPInterface.read(mCallID, gConfig.getNum("SIP.Timer.E"), lock);
			LOG(DEBUG) << "received status " << ok->status_code << " " << ok->reason_phrase;
		}
		catch (SIPTimeout& e) { 
			LOG(NOTICE) << "SIP RFC-2967 INFO packet to " << mProxyIP << ":" << mProxyPort << " timedout; resending"; 
			gSIPInterface.write(&mProxyAddr,info);
			continue;
		}
	}
	osip_message_free(info);
	if (!ok) {
		LOG(ALERT) << "SIP RFC-2967 INFO timed out; is the proxy at " << mProxyIP << ":" << mProxyPort << " OK?";
		return false;
	}
	LOG(DEBUG) << "received status " << ok->status_code << " " << ok->reason_phrase;
	bool retVal = (ok->status_code==200);
	osip_message_free(ok);
	if (!retVal) LOG(WARNING) << "SIP RFC-2967 INFO failed on server " << mProxyIP << ":" << mProxyPort << " OK?";
	return retVal;
}
/* reinvite stuff */
/* return true if this is the same invite as the one we have stored */
bool SIPEngine::sameINVITE(osip_message_t * msg){
	assert(mINVITE);
	if (NULL == msg){
		LOG(NOTICE) << "trying to compare empty message";
		return false;
	}
	// We are assuming that the callids match.
	// Otherwise, this would not have been called.
	// FIXME -- Check callids and assrt if they down match.
	// So we just check the CSeq.
	// FIXME -- Check all of the pointers along these chains and log ERR if anthing is missing.
	const char *cn1 = msg->cseq->number;
	if (!cn1) {
		LOG(ERR) << "no cseq in msg";
		return false;
	}
	int n1 = atoi(cn1);
	const char *cn2 = mINVITE->cseq->number;
	if (!cn2) {
		LOG(ERR) << "no cseq in mINVITE";
		return false;
	}
	int n2 = atoi(cn2);
	if (n1!=n2) {
		LOG(NOTICE) << "possible reinvite CSeq A " << cn1 << " (" << n1 << ") CSeq B " << cn2 << " (" << n2 << ")";
	}
	return n1==n2;
}
// vim: ts=4 sw=4