Index: pbx.c =================================================================== RCS file: /usr/cvsroot/asterisk/pbx.c,v retrieving revision 1.259 diff -u -r1.259 pbx.c --- pbx.c 12 Jul 2005 01:34:05 -0000 1.259 +++ pbx.c 15 Jul 2005 15:34:53 -0000 @@ -1740,6 +1740,8 @@ int res = -1; int allunavailable = 1, allbusy = 1, allfree = 1; int busy = 0; + int inuse = 0; + int ring = 0; if (!e) return -1; @@ -1750,7 +1752,7 @@ do { rest = strchr(cur, '&'); if (rest) { - *rest = 0; + *rest = 0; rest++; } @@ -1761,7 +1763,15 @@ allbusy = 0; break; case AST_DEVICE_INUSE: - return AST_EXTENSION_INUSE; + inuse = 1; + allunavailable = 0; + allfree = 0; + break; + case AST_DEVICE_RINGING: + ring = 1; + allunavailable = 0; + allfree = 0; + break; case AST_DEVICE_BUSY: allunavailable = 0; allfree = 0; @@ -1780,7 +1790,13 @@ cur = rest; } while (cur); - if (allfree) + if (!inuse && ring) { + return AST_EXTENSION_RINGING;} + if (inuse && ring) { + return AST_EXTENSION_RINGING_AND_INUSE;} + if (inuse) + return AST_EXTENSION_INUSE; + if (allfree) return AST_EXTENSION_NOT_INUSE; if (allbusy) return AST_EXTENSION_BUSY; Index: channels/chan_sip.c =================================================================== RCS file: /usr/cvsroot/asterisk/channels/chan_sip.c,v retrieving revision 1.779 diff -u -r1.779 chan_sip.c --- channels/chan_sip.c 13 Jul 2005 18:06:49 -0000 1.779 +++ channels/chan_sip.c 15 Jul 2005 15:34:56 -0000 @@ -78,23 +78,23 @@ /* #define VOCAL_DATA_HACK */ +#define SIP_RETVAL_IGNORE 1 #define SIPDUMPER -#define DEFAULT_DEFAULT_EXPIRY 120 -#define DEFAULT_MAX_EXPIRY 3600 -#define DEFAULT_REGISTRATION_TIMEOUT 20 -#define DEFAULT_REGATTEMPTS_MAX 10 +#define DEFAULT_DEFAULT_EXPIRY 120 +#define DEFAULT_MAX_EXPIRY 3600 +#define DEFAULT_REGISTRATION_TIMEOUT 20 +#define DEFAULT_REGATTEMPTS_MAX 10 /* guard limit must be larger than guard secs */ /* guard min must be < 1000, and should be >= 250 */ -#define EXPIRY_GUARD_SECS 15 /* How long before expiry do we reregister */ -#define EXPIRY_GUARD_LIMIT 30 /* Below here, we use EXPIRY_GUARD_PCT instead of - EXPIRY_GUARD_SECS */ -#define EXPIRY_GUARD_MIN 500 /* This is the minimum guard time applied. If - GUARD_PCT turns out to be lower than this, it - will use this time instead. - This is in milliseconds. */ -#define EXPIRY_GUARD_PCT 0.20 /* Percentage of expires timeout to use when - below EXPIRY_GUARD_LIMIT */ +#define EXPIRY_GUARD_SECS 15 /* How long before expiry do we reregister */ +#define EXPIRY_GUARD_LIMIT 30 /* Below here, we use EXPIRY_GUARD_PCT instead of EXPIRY_GUARD_SECS */ +#define EXPIRY_GUARD_MIN 500 /* This is the minimum guard time applied. If + GUARD_PCT turns out to be lower than this, it + will use this time instead. + This is in milliseconds. */ +#define EXPIRY_GUARD_PCT 0.20 /* Percentage of expires timeout to use when + below EXPIRY_GUARD_LIMIT */ static int max_expiry = DEFAULT_MAX_EXPIRY; static int default_expiry = DEFAULT_DEFAULT_EXPIRY; @@ -105,39 +105,43 @@ #define CALLERID_UNKNOWN "Unknown" +#define DEFAULT_MAXMS 2000 /* Must be faster than 2 seconds by default */ +#define DEFAULT_FREQ_OK 60 * 1000 /* How often to check for the host to be up */ +#define DEFAULT_FREQ_NOTOK 10 * 1000 /* How often to check, if the host is down... */ +#define DEFAULT_RETRANS 2000 /* How frequently to retransmit */ +#define MAX_RETRANS 5 /* Try only 5 times for retransmissions */ -#define DEFAULT_MAXMS 2000 /* Must be faster than 2 seconds by default */ -#define DEFAULT_FREQ_OK 60 * 1000 /* How often to check for the host to be up */ -#define DEFAULT_FREQ_NOTOK 10 * 1000 /* How often to check, if the host is down... */ +#define DEFAULT_MAX_FORWARDS 70 -#define DEFAULT_RETRANS 2000 /* How frequently to retransmit */ -#define MAX_RETRANS 5 /* Try only 5 times for retransmissions */ - - -#define DEBUG_READ 0 /* Recieved data */ -#define DEBUG_SEND 1 /* Transmit data */ +#define DEBUG_READ 0 /* Recieved data */ +#define DEBUG_SEND 1 /* Transmit data */ static const char desc[] = "Session Initiation Protocol (SIP)"; static const char channeltype[] = "SIP"; static const char config[] = "sip.conf"; static const char notify_config[] = "sip_notify.conf"; -#define SIP_REGISTER 1 -#define SIP_OPTIONS 2 -#define SIP_NOTIFY 3 -#define SIP_INVITE 4 -#define SIP_ACK 5 -#define SIP_PRACK 6 -#define SIP_BYE 7 -#define SIP_REFER 8 -#define SIP_SUBSCRIBE 9 -#define SIP_MESSAGE 10 -#define SIP_UPDATE 11 -#define SIP_INFO 12 -#define SIP_CANCEL 13 -#define SIP_PUBLISH 14 -#define SIP_RESPONSE 100 +#define SIP_REGISTER 1 +#define SIP_OPTIONS 2 +#define SIP_NOTIFY 3 +#define SIP_INVITE 4 +#define SIP_ACK 5 +#define SIP_PRACK 6 +#define SIP_BYE 7 +#define SIP_REFER 8 +#define SIP_SUBSCRIBE 9 +#define SIP_MESSAGE 10 +#define SIP_UPDATE 11 +#define SIP_INFO 12 +#define SIP_CANCEL 13 +#define SIP_PUBLISH 14 +#define SIP_RESPONSE 100 + +#define SUBSCRIBE_XPIDF_XML 1 +#define SUBSCRIBE_DIALOG_INFO_XML 2 +#define SUBSCRIBE_CPIM_PIDF_XML 3 +#define SUBSCRIBE_PIDF_XML 4 #define RTP 1 #define NO_RTP 0 @@ -147,20 +151,20 @@ char *text; } sip_methods[] = { { 0, RTP, "-UNKNOWN-" }, - { SIP_REGISTER, NO_RTP, "REGISTER" }, - { SIP_OPTIONS, NO_RTP, "OPTIONS" }, - { SIP_NOTIFY, NO_RTP, "NOTIFY" }, - { SIP_INVITE, RTP, "INVITE" }, - { SIP_ACK, NO_RTP, "ACK" }, - { SIP_PRACK, NO_RTP, "PRACK" }, - { SIP_BYE, NO_RTP, "BYE" }, - { SIP_REFER, NO_RTP, "REFER" }, + { SIP_REGISTER, NO_RTP, "REGISTER" }, + { SIP_OPTIONS, NO_RTP, "OPTIONS" }, + { SIP_NOTIFY, NO_RTP, "NOTIFY" }, + { SIP_INVITE, RTP, "INVITE" }, + { SIP_ACK, NO_RTP, "ACK" }, + { SIP_PRACK, NO_RTP, "PRACK" }, + { SIP_BYE, NO_RTP, "BYE" }, + { SIP_REFER, NO_RTP, "REFER" }, { SIP_SUBSCRIBE, NO_RTP, "SUBSCRIBE" }, - { SIP_MESSAGE, NO_RTP, "MESSAGE" }, - { SIP_UPDATE, NO_RTP, "UPDATE" }, - { SIP_INFO, NO_RTP, "INFO" }, - { SIP_CANCEL, NO_RTP, "CANCEL" }, - { SIP_PUBLISH, NO_RTP, "PUBLISH" } + { SIP_MESSAGE, NO_RTP, "MESSAGE" }, + { SIP_UPDATE, NO_RTP, "UPDATE" }, + { SIP_INFO, NO_RTP, "INFO" }, + { SIP_CANCEL, NO_RTP, "CANCEL" }, + { SIP_PUBLISH, NO_RTP, "PUBLISH" } }; /* Structure for conversion between compressed SIP and "normal" SIP */ @@ -168,20 +172,24 @@ char *fullname; char *shortname; } aliases[] = { - { "Content-Type", "c" }, - { "Content-Encoding", "e" }, - { "From", "f" }, - { "Call-ID", "i" }, - { "Contact", "m" }, - { "Content-Length", "l" }, - { "Subject", "s" }, - { "To", "t" }, - { "Supported", "k" }, - { "Refer-To", "r" }, - { "Referred-By", "b" }, - { "Allow-Events", "u" }, - { "Event", "o" }, - { "Via", "v" }, + { "Content-Type", "c" }, + { "Content-Encoding", "e" }, + { "From", "f" }, + { "Call-ID", "i" }, + { "Contact", "m" }, + { "Content-Length", "l" }, + { "Subject", "s" }, + { "To", "t" }, + { "Supported", "k" }, + { "Refer-To", "r" }, + { "Referred-By", "b" }, + { "Allow-Events", "u" }, + { "Event", "o" }, + { "Via", "v" }, + { "Accept-Contact", "a" }, + { "Reject-Contact", "j" }, + { "Request-Disposition", "d" }, + { "Session-Expires", "x" }, }; /* Define SIP option tags, used in Require: and Supported: headers */ @@ -194,23 +202,23 @@ We are not using many of these today, but will in the future. This is documented in RFC 3261 */ -#define SUPPORTED 1 -#define NOT_SUPPORTED 0 +#define SUPPORTED 1 +#define NOT_SUPPORTED 0 -#define SIP_OPT_REPLACES (1 << 0) -#define SIP_OPT_100REL (1 << 1) -#define SIP_OPT_TIMER (1 << 2) -#define SIP_OPT_EARLY_SESSION (1 << 3) -#define SIP_OPT_JOIN (1 << 4) -#define SIP_OPT_PATH (1 << 5) -#define SIP_OPT_PREF (1 << 6) -#define SIP_OPT_PRECONDITION (1 << 7) -#define SIP_OPT_PRIVACY (1 << 8) -#define SIP_OPT_SDP_ANAT (1 << 9) -#define SIP_OPT_SEC_AGREE (1 << 10) -#define SIP_OPT_EVENTLIST (1 << 11) -#define SIP_OPT_GRUU (1 << 12) -#define SIP_OPT_TARGET_DIALOG (1 << 13) +#define SIP_OPT_REPLACES (1 << 0) +#define SIP_OPT_100REL (1 << 1) +#define SIP_OPT_TIMER (1 << 2) +#define SIP_OPT_EARLY_SESSION (1 << 3) +#define SIP_OPT_JOIN (1 << 4) +#define SIP_OPT_PATH (1 << 5) +#define SIP_OPT_PREF (1 << 6) +#define SIP_OPT_PRECONDITION (1 << 7) +#define SIP_OPT_PRIVACY (1 << 8) +#define SIP_OPT_SDP_ANAT (1 << 9) +#define SIP_OPT_SEC_AGREE (1 << 10) +#define SIP_OPT_EVENTLIST (1 << 11) +#define SIP_OPT_GRUU (1 << 12) +#define SIP_OPT_TARGET_DIALOG (1 << 13) /* List of well-known SIP options. If we get this in a require, we should check the list and answer accordingly. */ @@ -220,33 +228,33 @@ char *text; /* Text id, as in standard */ } sip_options[] = { /* Replaces: header for transfer */ - { SIP_OPT_REPLACES, SUPPORTED, "replaces" }, + { SIP_OPT_REPLACES, SUPPORTED, "replaces" }, /* RFC3262: PRACK 100% reliability */ - { SIP_OPT_100REL, NOT_SUPPORTED, "100rel" }, + { SIP_OPT_100REL, NOT_SUPPORTED, "100rel" }, /* SIP Session Timers */ - { SIP_OPT_TIMER, NOT_SUPPORTED, "timer" }, + { SIP_OPT_TIMER, NOT_SUPPORTED, "timer" }, /* RFC3959: SIP Early session support */ - { SIP_OPT_EARLY_SESSION, NOT_SUPPORTED, "early-session" }, + { SIP_OPT_EARLY_SESSION, NOT_SUPPORTED, "early-session" }, /* SIP Join header support */ - { SIP_OPT_JOIN, NOT_SUPPORTED, "join" }, + { SIP_OPT_JOIN, NOT_SUPPORTED, "join" }, /* RFC3327: Path support */ - { SIP_OPT_PATH, NOT_SUPPORTED, "path" }, + { SIP_OPT_PATH, NOT_SUPPORTED, "path" }, /* RFC3840: Callee preferences */ - { SIP_OPT_PREF, NOT_SUPPORTED, "pref" }, + { SIP_OPT_PREF, NOT_SUPPORTED, "pref" }, /* RFC3312: Precondition support */ - { SIP_OPT_PRECONDITION, NOT_SUPPORTED, "precondition" }, + { SIP_OPT_PRECONDITION, NOT_SUPPORTED, "precondition" }, /* RFC3323: Privacy with proxies*/ - { SIP_OPT_PRIVACY, NOT_SUPPORTED, "privacy" }, + { SIP_OPT_PRIVACY, NOT_SUPPORTED, "privacy" }, /* Not yet RFC, but registred with IANA */ - { SIP_OPT_SDP_ANAT, NOT_SUPPORTED, "sdp_anat" }, + { SIP_OPT_SDP_ANAT, NOT_SUPPORTED, "sdp_anat" }, /* RFC3329: Security agreement mechanism */ - { SIP_OPT_SEC_AGREE, NOT_SUPPORTED, "sec_agree" }, + { SIP_OPT_SEC_AGREE, NOT_SUPPORTED, "sec_agree" }, /* SIMPLE events: draft-ietf-simple-event-list-07.txt */ - { SIP_OPT_EVENTLIST, NOT_SUPPORTED, "eventlist" }, + { SIP_OPT_EVENTLIST, NOT_SUPPORTED, "eventlist" }, /* GRUU: Globally Routable User Agent URI's */ - { SIP_OPT_GRUU, NOT_SUPPORTED, "gruu" }, + { SIP_OPT_GRUU, NOT_SUPPORTED, "gruu" }, /* Target-dialog: draft-ietf-sip-target-dialog-00.txt */ - { SIP_OPT_TARGET_DIALOG,NOT_SUPPORTED, "target-dialog" }, + { SIP_OPT_TARGET_DIALOG, NOT_SUPPORTED, "target-dialog" }, }; @@ -256,44 +264,33 @@ /* SIP Extensions we support */ #define SUPPORTED_EXTENSIONS "replaces" -#define DEFAULT_SIP_PORT 5060 /* From RFC 3261 (former 2543) */ -#define SIP_MAX_PACKET 4096 /* Also from RFC 3261 (2543), should sub headers tho */ +#define DEFAULT_SIP_PORT 5060 /* From RFC 3261 (former 2543) */ +#define SIP_MAX_PACKET 4096 /* Also from RFC 3261 (2543), should sub headers tho */ static char default_useragent[AST_MAX_EXTENSION] = DEFAULT_USERAGENT; - #define DEFAULT_CONTEXT "default" static char default_context[AST_MAX_CONTEXT] = DEFAULT_CONTEXT; - +static char default_subscribecontext[AST_MAX_CONTEXT]; +static char regcontext[AST_MAX_CONTEXT] = ""; /* Context for auto-extensions */ static char default_language[MAX_LANGUAGE] = ""; - #define DEFAULT_CALLERID "asterisk" static char default_callerid[AST_MAX_EXTENSION] = DEFAULT_CALLERID; - +#define DEFAULT_VMEXTEN DEFAULT_CALLERID +static char global_vmexten[AST_MAX_EXTENSION] = DEFAULT_VMEXTEN; static char default_fromdomain[AST_MAX_EXTENSION] = ""; - #define DEFAULT_NOTIFYMIME "application/simple-message-summary" static char default_notifymime[AST_MAX_EXTENSION] = DEFAULT_NOTIFYMIME; - - +static int global_notifyringing = 1; /* Send notifications on ringing */ static int default_qualify = 0; /* Default Qualify= setting */ - static struct ast_flags global_flags = {0}; /* global SIP_ flags */ static struct ast_flags global_flags_page2 = {0}; /* more global SIP_ flags */ - static int srvlookup = 0; /* SRV Lookup on or off. Default is off, RFC behavior is on */ - static int pedanticsipchecking = 0; /* Extra checking ? Default off */ - static int autocreatepeer = 0; /* Auto creation of peers at registration? Default off. */ - static int relaxdtmf = 0; - static int global_rtptimeout = 0; - static int global_rtpholdtimeout = 0; - static int global_rtpkeepalive = 0; - static int global_reg_timeout = DEFAULT_REGISTRATION_TIMEOUT; static int global_regattempts_max = DEFAULT_REGATTEMPTS_MAX; @@ -313,7 +310,6 @@ static int usecnt =0; AST_MUTEX_DEFINE_STATIC(usecnt_lock); - /* Protect the interface list (of sip_pvt's) */ AST_MUTEX_DEFINE_STATIC(iflock); @@ -336,22 +332,15 @@ static struct in_addr __ourip; static struct sockaddr_in outboundproxyip; static int ourport; - static int sipdebug = 0; static struct sockaddr_in debugaddr; - static int tos = 0; - static int videosupport = 0; - static int compactheaders = 0; /* send compact sip headers */ - static int recordhistory = 0; /* Record SIP history. Off by default */ - static char global_musicclass[MAX_MUSICCLASS] = ""; /* Global music on hold class */ #define DEFAULT_REALM "asterisk" static char global_realm[MAXHOSTNAMELEN] = DEFAULT_REALM; /* Default realm */ -static char regcontext[AST_MAX_CONTEXT] = ""; /* Context for auto-extensions */ /* Expire slowly */ #define DEFAULT_EXPIRY 900 @@ -362,13 +351,13 @@ /* The private structures of the sip channels are linked for selecting outgoing channels */ -#define SIP_MAX_HEADERS 64 -#define SIP_MAX_LINES 64 +#define SIP_MAX_HEADERS 64 +#define SIP_MAX_LINES 64 -#define DEC_IN_USE 0 -#define INC_IN_USE 1 -#define DEC_OUT_USE 2 -#define INC_OUT_USE 3 +#define DEC_IN_USE 0 +#define INC_IN_USE 1 +#define DEC_OUT_USE 2 +#define INC_OUT_USE 3 static struct ast_codec_pref prefs; @@ -418,179 +407,181 @@ struct sip_auth *next; /* Next auth structure in list */ }; -#define SIP_ALREADYGONE (1 << 0) /* Whether or not we've already been destroyed by our peer */ -#define SIP_NEEDDESTROY (1 << 1) /* if we need to be destroyed */ -#define SIP_NOVIDEO (1 << 2) /* Didn't get video in invite, don't offer */ -#define SIP_RINGING (1 << 3) /* Have sent 180 ringing */ -#define SIP_PROGRESS_SENT (1 << 4) /* Have sent 183 message progress */ -#define SIP_NEEDREINVITE (1 << 5) /* Do we need to send another reinvite? */ -#define SIP_PENDINGBYE (1 << 6) /* Need to send bye after we ack? */ -#define SIP_GOTREFER (1 << 7) /* Got a refer? */ -#define SIP_PROMISCREDIR (1 << 8) /* Promiscuous redirection */ -#define SIP_TRUSTRPID (1 << 9) /* Trust RPID headers? */ -#define SIP_USEREQPHONE (1 << 10) /* Add user=phone to numeric URI. Default off */ -#define SIP_REALTIME (1 << 11) /* Flag for realtime users */ -#define SIP_USECLIENTCODE (1 << 12) /* Trust X-ClientCode info message */ -#define SIP_OUTGOING (1 << 13) /* Is this an outgoing call? */ -#define SIP_SELFDESTRUCT (1 << 14) -#define SIP_DYNAMIC (1 << 15) /* Is this a dynamic peer? */ +#define SIP_ALREADYGONE (1 << 0) /* Whether or not we've already been destroyed by our peer */ +#define SIP_NEEDDESTROY (1 << 1) /* if we need to be destroyed */ +#define SIP_NOVIDEO (1 << 2) /* Didn't get video in invite, don't offer */ +#define SIP_RINGING (1 << 3) /* Have sent 180 ringing */ +#define SIP_PROGRESS_SENT (1 << 4) /* Have sent 183 message progress */ +#define SIP_NEEDREINVITE (1 << 5) /* Do we need to send another reinvite? */ +#define SIP_PENDINGBYE (1 << 6) /* Need to send bye after we ack? */ +#define SIP_GOTREFER (1 << 7) /* Got a refer? */ +#define SIP_PROMISCREDIR (1 << 8) /* Promiscuous redirection */ +#define SIP_TRUSTRPID (1 << 9) /* Trust RPID headers? */ +#define SIP_USEREQPHONE (1 << 10) /* Add user=phone to numeric URI. Default off */ +#define SIP_REALTIME (1 << 11) /* Flag for realtime users */ +#define SIP_USECLIENTCODE (1 << 12) /* Trust X-ClientCode info message */ +#define SIP_OUTGOING (1 << 13) /* Is this an outgoing call? */ +#define SIP_SELFDESTRUCT (1 << 14) +#define SIP_DYNAMIC (1 << 15) /* Is this a dynamic peer? */ /* --- Choices for DTMF support in SIP channel */ -#define SIP_DTMF (3 << 16) /* three settings, uses two bits */ -#define SIP_DTMF_RFC2833 (0 << 16) /* RTP DTMF */ -#define SIP_DTMF_INBAND (1 << 16) /* Inband audio, only for ULAW/ALAW */ -#define SIP_DTMF_INFO (2 << 16) /* SIP Info messages */ +#define SIP_DTMF (3 << 16) /* three settings, uses two bits */ +#define SIP_DTMF_RFC2833 (0 << 16) /* RTP DTMF */ +#define SIP_DTMF_INBAND (1 << 16) /* Inband audio, only for ULAW/ALAW */ +#define SIP_DTMF_INFO (2 << 16) /* SIP Info messages */ /* NAT settings */ -#define SIP_NAT (3 << 18) /* four settings, uses two bits */ -#define SIP_NAT_NEVER (0 << 18) /* No nat support */ -#define SIP_NAT_RFC3581 (1 << 18) -#define SIP_NAT_ROUTE (2 << 18) -#define SIP_NAT_ALWAYS (3 << 18) +#define SIP_NAT (3 << 18) /* four settings, uses two bits */ +#define SIP_NAT_NEVER (0 << 18) /* No nat support */ +#define SIP_NAT_RFC3581 (1 << 18) +#define SIP_NAT_ROUTE (2 << 18) +#define SIP_NAT_ALWAYS (3 << 18) /* re-INVITE related settings */ -#define SIP_REINVITE (3 << 20) /* two bits used */ -#define SIP_CAN_REINVITE (1 << 20) /* allow peers to be reinvited to send media directly p2p */ -#define SIP_REINVITE_UPDATE (2 << 20) /* use UPDATE (RFC3311) when reinviting this peer */ +#define SIP_REINVITE (3 << 20) /* two bits used */ +#define SIP_CAN_REINVITE (1 << 20) /* allow peers to be reinvited to send media directly p2p */ +#define SIP_REINVITE_UPDATE (2 << 20) /* use UPDATE (RFC3311) when reinviting this peer */ /* "insecure" settings */ -#define SIP_INSECURE_PORT (1 << 22) /* don't require matching port for incoming requests */ -#define SIP_INSECURE_INVITE (1 << 23) /* don't require authentication for incoming INVITEs */ +#define SIP_INSECURE_PORT (1 << 22) /* don't require matching port for incoming requests */ +#define SIP_INSECURE_INVITE (1 << 23) /* don't require authentication for incoming INVITEs */ /* Sending PROGRESS in-band settings */ -#define SIP_PROG_INBAND (3 << 24) /* three settings, uses two bits */ -#define SIP_PROG_INBAND_NEVER (0 << 24) -#define SIP_PROG_INBAND_NO (1 << 24) -#define SIP_PROG_INBAND_YES (2 << 24) +#define SIP_PROG_INBAND (3 << 24) /* three settings, uses two bits */ +#define SIP_PROG_INBAND_NEVER (0 << 24) +#define SIP_PROG_INBAND_NO (1 << 24) +#define SIP_PROG_INBAND_YES (2 << 24) /* Open Settlement Protocol authentication */ -#define SIP_OSPAUTH (3 << 26) /* three settings, uses two bits */ -#define SIP_OSPAUTH_NO (0 << 26) -#define SIP_OSPAUTH_YES (1 << 26) -#define SIP_OSPAUTH_EXCLUSIVE (2 << 26) +#define SIP_OSPAUTH (3 << 26) /* three settings, uses two bits */ +#define SIP_OSPAUTH_NO (0 << 26) +#define SIP_OSPAUTH_YES (1 << 26) +#define SIP_OSPAUTH_EXCLUSIVE (2 << 26) /* Call states */ -#define SIP_CALL_ONHOLD (1 << 28) -#define SIP_CALL_LIMIT (1 << 29) +#define SIP_CALL_ONHOLD (1 << 28) +#define SIP_CALL_LIMIT (1 << 29) /* a new page of flags for peer */ -#define SIP_PAGE2_RTCACHEFRIENDS (1 << 0) -#define SIP_PAGE2_RTNOUPDATE (1 << 1) -#define SIP_PAGE2_RTAUTOCLEAR (1 << 2) -#define SIP_PAGE2_RTIGNOREREGEXPIRE (1 << 3) +#define SIP_PAGE2_RTCACHEFRIENDS (1 << 0) +#define SIP_PAGE2_RTNOUPDATE (1 << 1) +#define SIP_PAGE2_RTAUTOCLEAR (1 << 2) +#define SIP_PAGE2_RTIGNOREREGEXPIRE (1 << 3) static int global_rtautoclear = 120; /* sip_pvt: PVT structures are used for each SIP conversation, ie. a call */ static struct sip_pvt { - ast_mutex_t lock; /* Channel private lock */ - int method; /* SIP method of this packet */ - char callid[80]; /* Global CallID */ - char randdata[80]; /* Random data */ - struct ast_codec_pref prefs; /* codec prefs */ - unsigned int ocseq; /* Current outgoing seqno */ - unsigned int icseq; /* Current incoming seqno */ - ast_group_t callgroup; /* Call group */ - ast_group_t pickupgroup; /* Pickup group */ - int lastinvite; /* Last Cseq of invite */ - unsigned int flags; /* SIP_ flags */ - unsigned int sipoptions; /* Supported SIP sipoptions on the other end */ - int capability; /* Special capability (codec) */ - int jointcapability; /* Supported capability at both ends (codecs ) */ - int peercapability; /* Supported peer capability */ - int prefcodec; /* Preferred codec (outbound only) */ + ast_mutex_t lock; /* Channel private lock */ + int method; /* SIP method of this packet */ + char callid[80]; /* Global CallID */ + char randdata[80]; /* Random data */ + struct ast_codec_pref prefs; /* codec prefs */ + unsigned int ocseq; /* Current outgoing seqno */ + unsigned int icseq; /* Current incoming seqno */ + ast_group_t callgroup; /* Call group */ + ast_group_t pickupgroup; /* Pickup group */ + int lastinvite; /* Last Cseq of invite */ + unsigned int flags; /* SIP_ flags */ + unsigned int sipoptions; /* Supported SIP sipoptions on the other end */ + int capability; /* Special capability (codec) */ + int jointcapability; /* Supported capability at both ends (codecs ) */ + int peercapability; /* Supported peer capability */ + int prefcodec; /* Preferred codec (outbound only) */ int noncodeccapability; - int callingpres; /* Calling presentation */ - int authtries; /* Times we've tried to authenticate */ - int expiry; /* How long we take to expire */ - int branch; /* One random number */ - int tag; /* Another random number */ - int sessionid; /* SDP Session ID */ - int sessionversion; /* SDP Session Version */ - struct sockaddr_in sa; /* Our peer */ - struct sockaddr_in redirip; /* Where our RTP should be going if not to us */ - struct sockaddr_in vredirip; /* Where our Video RTP should be going if not to us */ - int redircodecs; /* Redirect codecs */ - struct sockaddr_in recv; /* Received as */ - struct in_addr ourip; /* Our IP */ - struct ast_channel *owner; /* Who owns us */ - char exten[AST_MAX_EXTENSION]; /* Extension where to start */ - char refer_to[AST_MAX_EXTENSION]; /* Place to store REFER-TO extension */ - char referred_by[AST_MAX_EXTENSION]; /* Place to store REFERRED-BY extension */ - char refer_contact[AST_MAX_EXTENSION]; /* Place to store Contact info from a REFER extension */ - struct sip_pvt *refer_call; /* Call we are referring */ - struct sip_route *route; /* Head of linked list of routing steps (fm Record-Route) */ - int route_persistant; /* Is this the "real" route? */ - char from[256]; /* The From: header */ - char useragent[256]; /* User agent in SIP request */ - char context[AST_MAX_CONTEXT]; /* Context for this call */ - char fromdomain[MAXHOSTNAMELEN]; /* Domain to show in the from field */ - char fromuser[AST_MAX_EXTENSION]; /* User to show in the user field */ - char fromname[AST_MAX_EXTENSION]; /* Name to show in the user field */ - char tohost[MAXHOSTNAMELEN]; /* Host we should put in the "to" field */ - char language[MAX_LANGUAGE]; /* Default language for this call */ - char musicclass[MAX_MUSICCLASS]; /* Music on Hold class */ - char rdnis[256]; /* Referring DNIS */ - char theirtag[256]; /* Their tag */ - char username[256]; /* [user] name */ - char peername[256]; /* [peer] name, not set if [user] */ - char authname[256]; /* Who we use for authentication */ - char uri[256]; /* Original requested URI */ - char okcontacturi[256]; /* URI from the 200 OK on INVITE */ - char peersecret[256]; /* Password */ + int callingpres; /* Calling presentation */ + int authtries; /* Times we've tried to authenticate */ + int expiry; /* How long we take to expire */ + int branch; /* One random number */ + int tag; /* Another random number */ + int sessionid; /* SDP Session ID */ + int sessionversion; /* SDP Session Version */ + struct sockaddr_in sa; /* Our peer */ + struct sockaddr_in redirip; /* Where our RTP should be going if not to us */ + struct sockaddr_in vredirip; /* Where our Video RTP should be going if not to us */ + int redircodecs; /* Redirect codecs */ + struct sockaddr_in recv; /* Received as */ + struct in_addr ourip; /* Our IP */ + struct ast_channel *owner; /* Who owns us */ + char exten[AST_MAX_EXTENSION]; /* Extension where to start */ + char refer_to[AST_MAX_EXTENSION]; /* Place to store REFER-TO extension */ + char referred_by[AST_MAX_EXTENSION]; /* Place to store REFERRED-BY extension */ + char refer_contact[AST_MAX_EXTENSION]; /* Place to store Contact info from a REFER extension */ + struct sip_pvt *refer_call; /* Call we are referring */ + struct sip_route *route; /* Head of linked list of routing steps (fm Record-Route) */ + int route_persistant; /* Is this the "real" route? */ + char from[256]; /* The From: header */ + char useragent[256]; /* User agent in SIP request */ + char context[AST_MAX_CONTEXT]; /* Context for this call */ + char subscribecontext[AST_MAX_CONTEXT]; /* Subscribecontext */ + char fromdomain[MAXHOSTNAMELEN]; /* Domain to show in the from field */ + char fromuser[AST_MAX_EXTENSION]; /* User to show in the user field */ + char fromname[AST_MAX_EXTENSION]; /* Name to show in the user field */ + char tohost[MAXHOSTNAMELEN]; /* Host we should put in the "to" field */ + char language[MAX_LANGUAGE]; /* Default language for this call */ + char musicclass[MAX_MUSICCLASS]; /* Music on Hold class */ + char rdnis[256]; /* Referring DNIS */ + char theirtag[256]; /* Their tag */ + char username[256]; /* [user] name */ + char peername[256]; /* [peer] name, not set if [user] */ + char authname[256]; /* Who we use for authentication */ + char uri[256]; /* Original requested URI */ + char okcontacturi[256]; /* URI from the 200 OK on INVITE */ + char peersecret[256]; /* Password */ char peermd5secret[256]; - struct sip_auth *peerauth; /* Realm authentication */ - char cid_num[256]; /* Caller*ID */ - char cid_name[256]; /* Caller*ID */ - char via[256]; /* Via: header */ - char fullcontact[128]; /* The Contact: that the UA registers with us */ - char accountcode[AST_MAX_ACCOUNT_CODE]; /* Account code */ - char our_contact[256]; /* Our contact header */ - char realm[MAXHOSTNAMELEN]; /* Authorization realm */ - char nonce[256]; /* Authorization nonce */ - char opaque[256]; /* Opaque nonsense */ - char qop[80]; /* Quality of Protection, since SIP wasn't complicated enough yet. */ - char domain[MAXHOSTNAMELEN]; /* Authorization domain */ - char lastmsg[256]; /* Last Message sent/received */ - int amaflags; /* AMA Flags */ - int pendinginvite; /* Any pending invite */ + struct sip_auth *peerauth; /* Realm authentication */ + char cid_num[256]; /* Caller*ID */ + char cid_name[256]; /* Caller*ID */ + char via[256]; /* Via: header */ + char fullcontact[128]; /* The Contact: that the UA registers with us */ + char accountcode[AST_MAX_ACCOUNT_CODE]; /* Account code */ + char our_contact[256]; /* Our contact header */ + char realm[MAXHOSTNAMELEN]; /* Authorization realm */ + char nonce[256]; /* Authorization nonce */ + char opaque[256]; /* Opaque nonsense */ + char qop[80]; /* Quality of Protection, since SIP wasn't complicated enough yet. */ + char domain[MAXHOSTNAMELEN]; /* Authorization domain */ + char lastmsg[256]; /* Last Message sent/received */ + int amaflags; /* AMA Flags */ + int pendinginvite; /* Any pending invite */ #ifdef OSP_SUPPORT - int osphandle; /* OSP Handle for call */ - time_t ospstart; /* OSP Start time */ + int osphandle; /* OSP Handle for call */ + time_t ospstart; /* OSP Start time */ #endif - struct sip_request initreq; /* Initial request */ + struct sip_request initreq; /* Initial request */ - int maxtime; /* Max time for first response */ - int maxforwards; /* keep the max-forwards info */ - int initid; /* Auto-congest ID if appropriate */ - int autokillid; /* Auto-kill ID */ - time_t lastrtprx; /* Last RTP received */ - time_t lastrtptx; /* Last RTP sent */ - int rtptimeout; /* RTP timeout time */ - int rtpholdtimeout; /* RTP timeout when on hold */ - int rtpkeepalive; /* Send RTP packets for keepalive */ - - int subscribed; /* Is this call a subscription? */ - int stateid; + int maxtime; /* Max time for first response */ + int maxforwards; /* keep the max-forwards info */ + int initid; /* Auto-congest ID if appropriate */ + int autokillid; /* Auto-kill ID */ + time_t lastrtprx; /* Last RTP received */ + time_t lastrtptx; /* Last RTP sent */ + int rtptimeout; /* RTP timeout time */ + int rtpholdtimeout; /* RTP timeout when on hold */ + int rtpkeepalive; /* Send RTP packets for keepalive */ + + int subscribed; /* Is this call a subscription? */ + int stateid; + int laststate; /* Last known state */ int dialogver; - struct ast_dsp *vad; /* Voice Activation Detection dsp */ + struct ast_dsp *vad; /* Voice Activation Detection dsp */ - struct sip_peer *peerpoke; /* If this calls is to poke a peer, which one */ - struct sip_registry *registry; /* If this is a REGISTER call, to which registry */ - struct ast_rtp *rtp; /* RTP Session */ - struct ast_rtp *vrtp; /* Video RTP session */ - struct sip_pkt *packets; /* Packets scheduled for re-transmission */ - struct sip_history *history; /* History of this SIP dialog */ - struct ast_variable *chanvars; /* Channel variables to set for call */ - struct sip_pvt *next; /* Next call in chain */ + struct sip_peer *peerpoke; /* If this calls is to poke a peer, which one */ + struct sip_registry *registry; /* If this is a REGISTER call, to which registry */ + struct ast_rtp *rtp; /* RTP Session */ + struct ast_rtp *vrtp; /* Video RTP session */ + struct sip_pkt *packets; /* Packets scheduled for re-transmission */ + struct sip_history *history; /* History of this SIP dialog */ + struct ast_variable *chanvars; /* Channel variables to set for call */ + struct sip_pvt *next; /* Next call in chain */ } *iflist = NULL; -#define FLAG_RESPONSE (1 << 0) -#define FLAG_FATAL (1 << 1) +#define FLAG_RESPONSE (1 << 0) +#define FLAG_FATAL (1 << 1) /* sip packet - read in sipsock_read, transmitted in send_request */ struct sip_pkt { - struct sip_pkt *next; /* Next packet */ - int retrans; /* Retransmission number */ - int seqno; /* Sequence number */ - unsigned int flags; /* non-zero if this is a response packet (e.g. 200 OK) */ - struct sip_pvt *owner; /* Owner call */ - int retransid; /* Retransmission ID */ - int packetlen; /* Length of packet */ + struct sip_pkt *next; /* Next packet */ + int retrans; /* Retransmission number */ + int seqno; /* Sequence number */ + unsigned int flags; /* non-zero if this is a response packet (e.g. 200 OK) */ + struct sip_pvt *owner; /* Owner call */ + int retransid; /* Retransmission ID */ + int packetlen; /* Length of packet */ char data[0]; }; @@ -598,87 +589,90 @@ struct sip_user { /* Users who can access various contexts */ ASTOBJ_COMPONENTS(struct sip_user); - char secret[80]; /* Password */ - char md5secret[80]; /* Password in md5 */ - char context[AST_MAX_CONTEXT]; /* Default context for incoming calls */ - char cid_num[80]; /* Caller ID num */ - char cid_name[80]; /* Caller ID name */ - char accountcode[AST_MAX_ACCOUNT_CODE]; /* Account code */ - char language[MAX_LANGUAGE]; /* Default language for this user */ - char musicclass[MAX_MUSICCLASS];/* Music on Hold class */ - char useragent[256]; /* User agent in SIP request */ - struct ast_codec_pref prefs; /* codec prefs */ - ast_group_t callgroup; /* Call group */ - ast_group_t pickupgroup; /* Pickup Group */ - unsigned int flags; /* SIP flags */ - unsigned int sipoptions; /* Supported SIP options */ - struct ast_flags flags_page2; /* SIP_PAGE2 flags */ - int amaflags; /* AMA flags for billing */ - int callingpres; /* Calling id presentation */ - int capability; /* Codec capability */ - int inUse; /* Number of calls in use */ - int incominglimit; /* Limit of incoming calls */ - int outUse; /* disabled */ - int outgoinglimit; /* disabled */ - struct ast_ha *ha; /* ACL setting */ - struct ast_variable *chanvars; /* Variables to set for channel created by user */ + char secret[80]; /* Password */ + char md5secret[80]; /* Password in md5 */ + char context[AST_MAX_CONTEXT]; /* Default context for incoming calls */ + char subscribecontext[AST_MAX_CONTEXT]; /* Default context for subscriptions */ + char cid_num[80]; /* Caller ID num */ + char cid_name[80]; /* Caller ID name */ + char accountcode[AST_MAX_ACCOUNT_CODE]; /* Account code */ + char language[MAX_LANGUAGE]; /* Default language for this user */ + char musicclass[MAX_MUSICCLASS]; /* Music on Hold class */ + char useragent[256]; /* User agent in SIP request */ + struct ast_codec_pref prefs; /* codec prefs */ + ast_group_t callgroup; /* Call group */ + ast_group_t pickupgroup; /* Pickup Group */ + unsigned int flags; /* SIP flags */ + unsigned int sipoptions; /* Supported SIP options */ + struct ast_flags flags_page2; /* SIP_PAGE2 flags */ + int amaflags; /* AMA flags for billing */ + int callingpres; /* Calling id presentation */ + int capability; /* Codec capability */ + int inUse; /* Number of calls in use */ + int incominglimit; /* Limit of incoming calls */ + int outUse; /* disabled */ + int outgoinglimit; /* disabled */ + struct ast_ha *ha; /* ACL setting */ + struct ast_variable *chanvars; /* Variables to set for channel created by user */ }; /* Structure for SIP peer data, we place calls to peers if registred or fixed IP address (host) */ struct sip_peer { - ASTOBJ_COMPONENTS(struct sip_peer); /* name, refcount, objflags, object pointers */ - /* peer->name is the unique name of this object */ - char secret[80]; /* Password */ - char md5secret[80]; /* Password in MD5 */ - struct sip_auth *auth; /* Realm authentication list */ - char context[AST_MAX_CONTEXT]; /* Default context for incoming calls */ - char username[80]; /* Temporary username until registration */ - char accountcode[AST_MAX_ACCOUNT_CODE]; /* Account code */ - int amaflags; /* AMA Flags (for billing) */ - char tohost[MAXHOSTNAMELEN]; /* If not dynamic, IP address */ - char regexten[AST_MAX_EXTENSION]; /* Extension to register (if regcontext is used) */ - char fromuser[80]; /* From: user when calling this peer */ - char fromdomain[MAXHOSTNAMELEN]; /* From: domain when calling this peer */ - char fullcontact[256]; /* Contact registred with us (not in sip.conf) */ - char cid_num[80]; /* Caller ID num */ - char cid_name[80]; /* Caller ID name */ - int callingpres; /* Calling id presentation */ - int inUse; /* Number of calls in use */ - int incominglimit; /* Limit of incoming calls */ - int outUse; /* disabled */ - int outgoinglimit; /* disabled */ - char mailbox[AST_MAX_EXTENSION]; /* Mailbox setting for MWI checks */ - char language[MAX_LANGUAGE]; /* Default language for prompts */ - char musicclass[MAX_MUSICCLASS];/* Music on Hold class */ - char useragent[256]; /* User agent in SIP request (saved from registration) */ - struct ast_codec_pref prefs; /* codec prefs */ + ASTOBJ_COMPONENTS(struct sip_peer); /* name, refcount, objflags, object pointers */ + /* peer->name is the unique name of this object */ + char secret[80]; /* Password */ + char md5secret[80]; /* Password in MD5 */ + struct sip_auth *auth; /* Realm authentication list */ + char context[AST_MAX_CONTEXT]; /* Default context for incoming calls */ + char subscribecontext[AST_MAX_CONTEXT]; /* Default context for subscriptions */ + char username[80]; /* Temporary username until registration */ + char accountcode[AST_MAX_ACCOUNT_CODE]; /* Account code */ + int amaflags; /* AMA Flags (for billing) */ + char tohost[MAXHOSTNAMELEN]; /* If not dynamic, IP address */ + char regexten[AST_MAX_EXTENSION]; /* Extension to register (if regcontext is used) */ + char fromuser[80]; /* From: user when calling this peer */ + char fromdomain[MAXHOSTNAMELEN]; /* From: domain when calling this peer */ + char fullcontact[256]; /* Contact registred with us (not in sip.conf) */ + char cid_num[80]; /* Caller ID num */ + char cid_name[80]; /* Caller ID name */ + int callingpres; /* Calling id presentation */ + int inUse; /* Number of calls in use */ + int incominglimit; /* Limit of incoming calls */ + int outUse; /* disabled */ + int outgoinglimit; /* disabled */ + char vmexten[AST_MAX_EXTENSION]; /* Dialplan extension for MWI notify message*/ + char mailbox[AST_MAX_EXTENSION]; /* Mailbox setting for MWI checks */ + char language[MAX_LANGUAGE]; /* Default language for prompts */ + char musicclass[MAX_MUSICCLASS]; /* Music on Hold class */ + char useragent[256]; /* User agent in SIP request (saved from registration) */ + struct ast_codec_pref prefs; /* codec prefs */ int lastmsgssent; - time_t lastmsgcheck; /* Last time we checked for MWI */ - unsigned int flags; /* SIP flags */ - unsigned int sipoptions; /* Supported SIP options */ - struct ast_flags flags_page2; /* SIP_PAGE2 flags */ - int expire; /* When to expire this peer registration */ - int expiry; /* Duration of registration */ - int capability; /* Codec capability */ - int rtptimeout; /* RTP timeout */ - int rtpholdtimeout; /* RTP Hold Timeout */ - int rtpkeepalive; /* Send RTP packets for keepalive */ - ast_group_t callgroup; /* Call group */ - ast_group_t pickupgroup; /* Pickup group */ - struct ast_dnsmgr_entry *dnsmgr;/* DNS refresh manager for peer */ - struct sockaddr_in addr; /* IP address of peer */ + time_t lastmsgcheck; /* Last time we checked for MWI */ + unsigned int flags; /* SIP flags */ + unsigned int sipoptions; /* Supported SIP options */ + struct ast_flags flags_page2; /* SIP_PAGE2 flags */ + int expire; /* When to expire this peer registration */ + int expiry; /* Duration of registration */ + int capability; /* Codec capability */ + int rtptimeout; /* RTP timeout */ + int rtpholdtimeout; /* RTP Hold Timeout */ + int rtpkeepalive; /* Send RTP packets for keepalive */ + ast_group_t callgroup; /* Call group */ + ast_group_t pickupgroup; /* Pickup group */ + struct ast_dnsmgr_entry *dnsmgr; /* DNS refresh manager for peer */ + struct sockaddr_in addr; /* IP address of peer */ struct in_addr mask; /* Qualification */ - struct sip_pvt *call; /* Call pointer */ - int pokeexpire; /* When to expire poke (qualify= checking) */ - int lastms; /* How long last response took (in ms), or -1 for no response */ - int maxms; /* Max ms we will accept for the host to be up, 0 to not monitor */ - struct timeval ps; /* Ping send time */ - - struct sockaddr_in defaddr; /* Default IP address, used until registration */ - struct ast_ha *ha; /* Access control list */ - struct ast_variable *chanvars; /* Variables to set for channel created by user */ + struct sip_pvt *call; /* Call pointer */ + int pokeexpire; /* When to expire poke (qualify= checking) */ + int lastms; /* How long last response took (in ms), or -1 for no response */ + int maxms; /* Max ms we will accept for the host to be up, 0 to not monitor */ + struct timeval ps; /* Ping send time */ + + struct sockaddr_in defaddr; /* Default IP address, used until registration */ + struct ast_ha *ha; /* Access control list */ + struct ast_variable *chanvars; /* Variables to set for channel created by user */ int lastmsg; }; @@ -686,46 +680,46 @@ static int sip_reloading = 0; /* States for outbound registrations (with register= lines in sip.conf */ -#define REG_STATE_UNREGISTERED 0 -#define REG_STATE_REGSENT 1 -#define REG_STATE_AUTHSENT 2 -#define REG_STATE_REGISTERED 3 -#define REG_STATE_REJECTED 4 -#define REG_STATE_TIMEOUT 5 -#define REG_STATE_NOAUTH 6 -#define REG_STATE_FAILED 7 +#define REG_STATE_UNREGISTERED 0 +#define REG_STATE_REGSENT 1 +#define REG_STATE_AUTHSENT 2 +#define REG_STATE_REGISTERED 3 +#define REG_STATE_REJECTED 4 +#define REG_STATE_TIMEOUT 5 +#define REG_STATE_NOAUTH 6 +#define REG_STATE_FAILED 7 /* sip_registry: Registrations with other SIP proxies */ struct sip_registry { ASTOBJ_COMPONENTS_FULL(struct sip_registry,1,1); - int portno; /* Optional port override */ - char username[80]; /* Who we are registering as */ - char authuser[80]; /* Who we *authenticate* as */ - char hostname[MAXHOSTNAMELEN]; /* Domain or host we register to */ - char secret[80]; /* Password or key name in []'s */ + int portno; /* Optional port override */ + char username[80]; /* Who we are registering as */ + char authuser[80]; /* Who we *authenticate* as */ + char hostname[MAXHOSTNAMELEN]; /* Domain or host we register to */ + char secret[80]; /* Password or key name in []'s */ char md5secret[80]; - char contact[256]; /* Contact extension */ + char contact[256]; /* Contact extension */ char random[80]; - int expire; /* Sched ID of expiration */ - int regattempts; /* Number of attempts (since the last success) */ - int timeout; /* sched id of sip_reg_timeout */ - int refresh; /* How often to refresh */ - struct sip_pvt *call; /* create a sip_pvt structure for each outbound "registration call" in progress */ - int regstate; /* Registration state (see above) */ - int callid_valid; /* 0 means we haven't chosen callid for this registry yet. */ - char callid[80]; /* Global CallID for this registry */ - unsigned int ocseq; /* Sequence number we got to for REGISTERs for this registry */ - struct sockaddr_in us; /* Who the server thinks we are */ + int expire; /* Sched ID of expiration */ + int regattempts; /* Number of attempts (since the last success) */ + int timeout; /* sched id of sip_reg_timeout */ + int refresh; /* How often to refresh */ + struct sip_pvt *call; /* create a sip_pvt structure for each outbound "registration call" in progress */ + int regstate; /* Registration state (see above) */ + int callid_valid; /* 0 means we haven't chosen callid for this registry yet. */ + char callid[80]; /* Global CallID for this registry */ + unsigned int ocseq; /* Sequence number we got to for REGISTERs for this registry */ + struct sockaddr_in us; /* Who the server thinks we are */ - /* Saved headers */ - char realm[MAXHOSTNAMELEN]; /* Authorization realm */ - char nonce[256]; /* Authorization nonce */ - char domain[MAXHOSTNAMELEN]; /* Authorization domain */ - char opaque[256]; /* Opaque nonsense */ - char qop[80]; /* Quality of Protection. */ + /* Saved headers */ + char realm[MAXHOSTNAMELEN]; /* Authorization realm */ + char nonce[256]; /* Authorization nonce */ + char domain[MAXHOSTNAMELEN]; /* Authorization domain */ + char opaque[256]; /* Opaque nonsense */ + char qop[80]; /* Quality of Protection. */ - char lastmsg[256]; /* Last Message sent/received */ + char lastmsg[256]; /* Last Message sent/received */ }; /*--- The user list: Users and friends ---*/ @@ -749,7 +743,6 @@ static int sipsock = -1; - static struct sockaddr_in bindaddr; static struct sockaddr_in externip; static char externhost[MAXHOSTNAMELEN] = ""; @@ -785,6 +778,7 @@ static struct sip_user *build_user(const char *name, struct ast_variable *v, int realtime); static int sip_do_reload(void); static int expire_register(void *data); +static int sip_addheader(struct ast_channel *chan, void *data); static int callevents = 0; static struct ast_channel *sip_request(const char *type, int format, void *data, int *cause); @@ -803,29 +797,49 @@ static struct sip_auth *add_realm_authentication(struct sip_auth *authlist, char *configuration, int lineno); /* Add realm authentication in list */ static struct sip_auth *find_realm_authentication(struct sip_auth *authlist, char *realm); /* Find authentication for a specific realm */ static void append_date(struct sip_request *req); /* Append date to SIP packet */ +static void sip_destroy(struct sip_pvt *p); +static void parse(struct sip_request *req); +static char *get_header(struct sip_request *req, char *name); +static void copy_request(struct sip_request *dst,struct sip_request *src); +static int transmit_response_reliable(struct sip_pvt *p, char *msg, struct sip_request *req, int fatal); +static int transmit_register(struct sip_registry *r, int sipmethod, char *auth, char *authheader); +static int sip_poke_peer(struct sip_peer *peer); + /* Definition of this channel for channel registration */ static const struct ast_channel_tech sip_tech = { - .type = channeltype, - .description = "Session Initiation Protocol (SIP)", + .type = channeltype, + .description = "Session Initiation Protocol (SIP)", .capabilities = ((AST_FORMAT_MAX_AUDIO << 1) - 1), - .properties = AST_CHAN_TP_WANTSJITTER, - .requester = sip_request, - .devicestate = sip_devicestate, - .call = sip_call, - .hangup = sip_hangup, - .answer = sip_answer, - .read = sip_read, - .write = sip_write, - .write_video = sip_write, - .indicate = sip_indicate, - .transfer = sip_transfer, - .fixup = sip_fixup, - .send_digit = sip_senddigit, - .bridge = ast_rtp_bridge, - .send_text = sip_sendtext, + .properties = AST_CHAN_TP_WANTSJITTER, + .requester = sip_request, + .devicestate = sip_devicestate, + .call = sip_call, + .hangup = sip_hangup, + .answer = sip_answer, + .read = sip_read, + .write = sip_write, + .write_video = sip_write, + .indicate = sip_indicate, + .transfer = sip_transfer, + .fixup = sip_fixup, + .send_digit = sip_senddigit, + .bridge = ast_rtp_bridge, + .send_text = sip_sendtext, }; +/*--- hex2int: Convert hex code to integer ---*/ +static int hex2int(char a) +{ + if ((a >= '0') && (a <= '9')) + return a - '0'; + else if ((a >= 'a') && (a <= 'f')) + return a - 'a' + 10; + else if ((a >= 'A') && (a <= 'F')) + return a - 'A' + 10; + return 0; +} + /*--- find_sip_method: Find SIP method from header */ int find_sip_method(char *msg) { @@ -838,24 +852,64 @@ return res; } -/* - * If there is a string in , strip everything around and return - * the content. Otherwise return the original argument. - */ -static char *get_in_brackets(char *c) +/* --- sip_extract_tag: extract from and to tags from a callid ---*/ +static int sip_extract_tag(char **in) { - char *n = strchr(c, '<'); + char *tag; - if (n) { + if ((tag = ast_strcasestr(*in, "tag="))) { + char *ptr; + tag += 4; + if ((ptr = strchr(tag, ';'))) + *ptr = '\0'; + return 0; + } + return -1; +} + +/*--- ditch_braces: Pick out text in braces from character string ---*/ +static char *ditch_braces(char *tmp, int mode) +{ + char *c = tmp, *n, *q; + + if (!mode && (q = strchr(tmp, '"')) ) { + c = q + 1; + if ((q = strchr(c, '"')) ) + c = q + 1; + else { + ast_log(LOG_WARNING, "No closing quote in '%s'\n", tmp); + c = tmp; + } + } + if ((n = strchr(c, '<')) ) { c = n + 1; - n = strchr(c, '>'); - /* Lose the part after the > */ - if (n) - *n = '\0'; + while (*c && *c != '>') c++; + if (*c != '>') { + ast_log(LOG_WARNING, "No closing brace in '%s'\n", tmp); + } else + *c = '\0'; + return n+1; } return c; } +/*--- url_decode: Decode SIP URL (overwrite the string) ---*/ +static void url_decode(char *s) +{ + char *o; + unsigned int tmp; + + for (o = s; *s; s++, o++) { + if (*s == '%' && strlen(s) > 2 && sscanf(s + 1, "%2x", &tmp) == 1) { + /* have '%', two chars and correct parsing */ + *o = tmp; + s += 2; /* Will be incremented once more when we break out */ + } else /* all other cases, just copy */ + *o = *s; + } + *o = '\0'; +} + /*--- parse_sip_options: Parse supported header in incoming packet */ unsigned int parse_sip_options(struct sip_pvt *pvt, char *supported) { @@ -865,11 +919,11 @@ int i; unsigned int profile = 0; - if (!supported || ast_strlen_zero(supported) ) + if (!supported || ast_strlen_zero(supported)) return 0; if (option_debug > 2 && sipdebug) - ast_log(LOG_DEBUG, "Begin: parsing SIP \"Supported: %s\"\n", supported); + ast_log(LOG_DEBUG, "Begin: parsing SIP \"Supported: %s for Call: %s\"\n", supported, pvt->callid); next = temp; while (next) { @@ -891,14 +945,14 @@ } } if (!res) - if (option_debug > 2 && sipdebug) - ast_log(LOG_DEBUG, "Found no match for SIP option: %s (Please file bug report!)\n", next); + ast_log(LOG_DEBUG, "Found no match for SIP option: %s (Please consider filing a bug report!)\n", next); next = sep; } - if (pvt) + if (pvt) { pvt->sipoptions = profile; - - ast_log(LOG_DEBUG, "* SIP extension value: %d for call %s\n", profile, pvt->callid); + if (option_debug) + ast_log(LOG_DEBUG, "* SIP extension value: %d for call %s\n", profile, pvt->callid); + } return(profile); } @@ -924,7 +978,6 @@ return sip_debug_test_addr(((ast_test_flag(p, SIP_NAT) & SIP_NAT_ROUTE) ? &p->recv : &p->sa)); } - /*--- __sip_xmit: Transmit SIP message ---*/ static int __sip_xmit(struct sip_pvt *p, char *data, int len) { @@ -932,17 +985,15 @@ char iabuf[INET_ADDRSTRLEN]; if (ast_test_flag(p, SIP_NAT) & SIP_NAT_ROUTE) - res=sendto(sipsock, data, len, 0, (struct sockaddr *)&p->recv, sizeof(struct sockaddr_in)); + res=sendto(sipsock, data, len, 0, (struct sockaddr *)&p->recv, sizeof(struct sockaddr_in)); else - res=sendto(sipsock, data, len, 0, (struct sockaddr *)&p->sa, sizeof(struct sockaddr_in)); + res=sendto(sipsock, data, len, 0, (struct sockaddr *)&p->sa, sizeof(struct sockaddr_in)); if (res != len) { ast_log(LOG_WARNING, "sip_xmit of %p (len %d) to %s returned %d: %s\n", data, len, ast_inet_ntoa(iabuf, sizeof(iabuf), p->sa.sin_addr), res, strerror(errno)); } return res; } -static void sip_destroy(struct sip_pvt *p); - /*--- build_via: Build a Via header for a request ---*/ static void build_via(struct sip_pvt *p, char *buf, int len) { @@ -955,7 +1006,7 @@ snprintf(buf, len, "SIP/2.0/UDP %s:%d;branch=z9hG4bK%08x", ast_inet_ntoa(iabuf, sizeof(iabuf), p->ourip), ourport, p->branch); } -/*--- ast_sip_ouraddrfor: NAT fix - decide which IP address to use for ASterisk server? ---*/ +/*--- ast_sip_ouraddrfor: NAT fix - decide which IP address to use for Asterisk server? ---*/ /* Only used for outbound registrations */ static int ast_sip_ouraddrfor(struct in_addr *them, struct in_addr *us) { @@ -991,14 +1042,13 @@ } /*--- append_history: Append to SIP dialog history */ -/* Always returns 0 */ static int append_history(struct sip_pvt *p, char *event, char *data) { struct sip_history *hist, *prev; char *c; if (!recordhistory) return 0; - if(!(hist = malloc(sizeof(struct sip_history)))) { + if (!(hist = malloc(sizeof(struct sip_history)))) { ast_log(LOG_WARNING, "Can't allocate memory for history"); return 0; } @@ -1006,7 +1056,7 @@ snprintf(hist->event, sizeof(hist->event), "%-15s %s", event, data); /* Trim up nicely */ c = hist->event; - while(*c) { + while (*c) { if ((*c == '\r') || (*c == '\n')) { *c = '\0'; break; @@ -1016,12 +1066,12 @@ /* Enqueue into history */ prev = p->history; if (prev) { - while(prev->next) + while (prev->next) prev = prev->next; prev->next = hist; - } else { + } else p->history = hist; - } + return 0; } @@ -1048,7 +1098,7 @@ append_history(pkt->owner, "MaxRetries", (ast_test_flag(pkt, FLAG_FATAL)) ? "(Critical)" : "(Non-critical)"); pkt->retransid = -1; if (ast_test_flag(pkt, FLAG_FATAL)) { - while(pkt->owner->owner && ast_mutex_trylock(&pkt->owner->owner->lock)) { + while (pkt->owner->owner && ast_mutex_trylock(&pkt->owner->owner->lock)) { ast_mutex_unlock(&pkt->owner->lock); usleep(1); ast_mutex_lock(&pkt->owner->lock); @@ -1065,7 +1115,7 @@ /* In any case, go ahead and remove the packet */ prev = NULL; cur = pkt->owner->packets; - while(cur) { + while (cur) { if (cur == pkt) break; prev = cur; @@ -1122,7 +1172,8 @@ struct sip_pvt *p = data; p->autokillid = -1; - ast_log(LOG_DEBUG, "Auto destroying call '%s'\n", p->callid); + if (option_debug > 1) + ast_log(LOG_DEBUG, "Auto destroying call '%s'\n", p->callid); append_history(p, "AutoDestroy", ""); if (p->owner) { ast_log(LOG_WARNING, "Autodestruct on call '%s' with owner in place\n", p->callid); @@ -1171,12 +1222,13 @@ msg = sip_methods[sipmethod].text; cur = p->packets; - while(cur) { + while (cur) { if ((cur->seqno == seqno) && ((ast_test_flag(cur, FLAG_RESPONSE)) == resp) && ((ast_test_flag(cur, FLAG_RESPONSE)) || (!strncasecmp(msg, cur->data, strlen(msg)) && (cur->data[strlen(msg)] < 33)))) { if (!resp && (seqno == p->pendinginvite)) { - ast_log(LOG_DEBUG, "Acked pending invite %d\n", p->pendinginvite); + if (option_debug) + ast_log(LOG_DEBUG, "Acked pending invite %d\n", p->pendinginvite); p->pendinginvite = 0; resetinvite = 1; } @@ -1194,17 +1246,19 @@ prev = cur; cur = cur->next; } - ast_log(LOG_DEBUG, "Stopping retransmission on '%s' of %s %d: %s\n", p->callid, resp ? "Response" : "Request", seqno, res ? "Not Found" : "Found"); + if (option_debug > 1) + ast_log(LOG_DEBUG, "Stopping retransmission on '%s' of %s %d: %s\n", p->callid, resp ? "Response" : "Request", seqno, res ? "Not Found" : "Found"); return res; } + /* Pretend to ack all packets */ static int __sip_pretend_ack(struct sip_pvt *p) { char method[128]=""; struct sip_pkt *cur=NULL; char *c; - while(p->packets) { + while (p->packets) { if (cur == p->packets) { ast_log(LOG_WARNING, "Have a packet that doesn't want to give up!\n"); return -1; @@ -1226,7 +1280,7 @@ char *msg = sip_methods[sipmethod].text; cur = p->packets; - while(cur) { + while (cur) { if ((cur->seqno == seqno) && ((ast_test_flag(cur, FLAG_RESPONSE)) == resp) && ((ast_test_flag(cur, FLAG_RESPONSE)) || (!strncasecmp(msg, cur->data, strlen(msg)) && (cur->data[strlen(msg)] < 33)))) { @@ -1239,14 +1293,11 @@ } cur = cur->next; } - ast_log(LOG_DEBUG, "(Provisional) Stopping retransmission (but retaining packet) on '%s' %s %d: %s\n", p->callid, resp ? "Response" : "Request", seqno, res ? "Not Found" : "Found"); + if (option_debug > 1) + ast_log(LOG_DEBUG, "(Provisional) Stopping retransmission (but retaining packet) on '%s' %s %d: %s\n", p->callid, resp ? "Response" : "Request", seqno, res ? "Not Found" : "Found"); return res; } -static void parse(struct sip_request *req); -static char *get_header(struct sip_request *req, char *name); -static void copy_request(struct sip_request *dst,struct sip_request *src); - /*--- parse_copy: Copy SIP request, parse it */ static void parse_copy(struct sip_request *dst, struct sip_request *src) { @@ -1321,51 +1372,6 @@ return res; } -/*--- url_decode: Decode SIP URL (overwrite the string) ---*/ -static void url_decode(char *s) -{ - char *o; - unsigned int tmp; - - for (o = s; *s; s++, o++) { - if (*s == '%' && strlen(s) > 2 && sscanf(s + 1, "%2x", &tmp) == 1) { - /* have '%', two chars and correct parsing */ - *o = tmp; - s += 2; /* Will be incremented once more when we break out */ - } else /* all other cases, just copy */ - *o = *s; - } - *o = '\0'; -} - -/*--- ditch_braces: Pick out text in braces from character string ---*/ -static char *ditch_braces(char *tmp) -{ - char *c = tmp; - char *n; - char *q; - if ((q = strchr(tmp, '"')) ) { - c = q + 1; - if ((q = strchr(c, '"')) ) - c = q + 1; - else { - ast_log(LOG_WARNING, "No closing quote in '%s'\n", tmp); - c = tmp; - } - } - if ((n = strchr(c, '<')) ) { - c = n + 1; - while(*c && *c != '>') c++; - if (*c != '>') { - ast_log(LOG_WARNING, "No closing brace in '%s'\n", tmp); - } else { - *c = '\0'; - } - return n+1; - } - return c; -} - /*--- sip_sendtext: Send SIP MESSAGE text within a call ---*/ /* Called from PBX core text message functions */ static int sip_sendtext(struct ast_channel *ast, const char *text) @@ -1386,16 +1392,16 @@ } /*--- realtime_update_peer: Update peer object in realtime storage ---*/ -static void realtime_update_peer(const char *peername, struct sockaddr_in *sin, const char *username, int expirey) +static void realtime_update_peer(const char *peername, struct sockaddr_in *sin, const char *username, int expiry) { char port[10] = ""; char ipaddr[20] = ""; char regseconds[20] = "0"; - if (expirey) { /* Registration */ + if (expiry) { /* Registration */ time_t nowtime; time(&nowtime); - nowtime += expirey; + nowtime += expiry; snprintf(regseconds, sizeof(regseconds), "%ld", nowtime); /* Expiration time */ ast_inet_ntoa(ipaddr, sizeof(ipaddr), sin->sin_addr); snprintf(port, sizeof(port), "%d", ntohs(sin->sin_port)); @@ -1411,7 +1417,7 @@ if (!ast_strlen_zero(regcontext)) { ast_copy_string(multi, ast_strlen_zero(peer->regexten) ? peer->name : peer->regexten, sizeof(multi)); stringp = multi; - while((ext = strsep(&stringp, "&"))) { + while ((ext = strsep(&stringp, "&"))) { if (onoff) ast_add_extension(regcontext, 1, ext, 1, NULL, NULL, "Noop", strdup(peer->name), free, channeltype); else @@ -1459,7 +1465,6 @@ } } - /*--- realtime_peer: Get peer from realtime storage ---*/ /* Checks the "sippeers" realtime family from extconfig.conf */ static struct sip_peer *realtime_peer(const char *peername, struct sockaddr_in *sin) @@ -1484,14 +1489,13 @@ tmp = var; /* If this is type=user, then skip this object. */ - while(tmp) { + while (tmp) { if (!strcasecmp(tmp->name, "type") && - !strcasecmp(tmp->value, "user")) { + !strcasecmp(tmp->value, "user")) { ast_variables_destroy(var); return NULL; - } else if (!newpeername && !strcasecmp(tmp->name, "name")) { + } else if (!newpeername && !strcasecmp(tmp->name, "name")) newpeername = tmp->value; - } tmp = tmp->next; } @@ -1592,8 +1596,6 @@ } tmp = tmp->next; } - - user = build_user(username, var, !ast_test_flag((&global_flags_page2), SIP_PAGE2_RTCACHEFRIENDS)); @@ -1605,8 +1607,8 @@ if (ast_test_flag((&global_flags_page2), SIP_PAGE2_RTCACHEFRIENDS)) { ast_set_flag((&user->flags_page2), SIP_PAGE2_RTCACHEFRIENDS); suserobjs++; - ASTOBJ_CONTAINER_LINK(&userl,user); - } else { + ASTOBJ_CONTAINER_LINK(&userl,user); + } else { /* Move counter from s to r... */ suserobjs--; ruserobjs++; @@ -1636,7 +1638,7 @@ char *callhost; if ((peer->addr.sin_addr.s_addr || peer->defaddr.sin_addr.s_addr) && - (!peer->maxms || ((peer->lastms >= 0) && (peer->lastms <= peer->maxms)))) { + (!peer->maxms || ((peer->lastms >= 0) && (peer->lastms <= peer->maxms)))) { if (peer->addr.sin_addr.s_addr) { r->sa.sin_addr = peer->addr.sin_addr; r->sa.sin_port = peer->addr.sin_port; @@ -1650,15 +1652,17 @@ } ast_copy_flags(r, peer, - SIP_PROMISCREDIR | SIP_USEREQPHONE | SIP_DTMF | SIP_NAT | SIP_REINVITE | - SIP_INSECURE_PORT | SIP_INSECURE_INVITE); + SIP_PROMISCREDIR | SIP_USEREQPHONE | SIP_DTMF | SIP_NAT | SIP_REINVITE | + SIP_INSECURE_PORT | SIP_INSECURE_INVITE); r->capability = peer->capability; if (r->rtp) { - ast_log(LOG_DEBUG, "Setting NAT on RTP to %d\n", (ast_test_flag(r, SIP_NAT) & SIP_NAT_ROUTE)); + if (option_debug > 1) + ast_log(LOG_DEBUG, "Setting NAT on RTP to %d\n", (ast_test_flag(r, SIP_NAT) & SIP_NAT_ROUTE)); ast_rtp_setnat(r->rtp, (ast_test_flag(r, SIP_NAT) & SIP_NAT_ROUTE)); } if (r->vrtp) { - ast_log(LOG_DEBUG, "Setting NAT on VRTP to %d\n", (ast_test_flag(r, SIP_NAT) & SIP_NAT_ROUTE)); + if (option_debug > 1) + ast_log(LOG_DEBUG, "Setting NAT on VRTP to %d\n", (ast_test_flag(r, SIP_NAT) & SIP_NAT_ROUTE)); ast_rtp_setnat(r->vrtp, (ast_test_flag(r, SIP_NAT) & SIP_NAT_ROUTE)); } ast_copy_string(r->peername, peer->username, sizeof(r->peername)); @@ -1707,9 +1711,9 @@ struct ast_hostent ahp; struct sip_peer *p; int found=0; - char *port; + char *port, *ptr, *hostp, *hostn; int portno; - char host[MAXHOSTNAMELEN], *hostn; + char host[MAXHOSTNAMELEN]; char peer[256]=""; ast_copy_string(peer, opeer, sizeof(peer)); @@ -1746,7 +1750,13 @@ portno = tportno; } } - hp = ast_gethostbyname(hostn, &ahp); + if ((hostp = ast_strdupa(hostn))) { + if ((ptr = strchr(hostp, '?'))) + *ptr = '\0'; + } else + hostp = peer; + + hp = ast_gethostbyname(hostp, &ahp); if (hp) { ast_copy_string(r->tohost, peer, sizeof(r->tohost)); memcpy(&r->sa.sin_addr, hp->h_addr, sizeof(r->sa.sin_addr)); @@ -1780,9 +1790,6 @@ return 0; } - - - /*--- sip_call: Initiate SIP call from PBX ---*/ /* used from the dial() application */ static int sip_call(struct ast_channel *ast, char *dest, int timeout) @@ -1914,13 +1921,13 @@ ast_mutex_unlock(&p->owner->lock); } /* Clear history */ - while(p->history) { + while (p->history) { hist = p->history; p->history = p->history->next; free(hist); } cur = iflist; - while(cur) { + while (cur) { if (cur == p) { if (prev) prev->next = cur->next; @@ -1937,7 +1944,7 @@ } if (p->initid > -1) ast_sched_del(sched, p->initid); - while((cp = p->packets)) { + while ((cp = p->packets)) { p->packets = p->packets->next; if (cp->retransid > -1) ast_sched_del(sched, cp->retransid); @@ -1987,60 +1994,56 @@ return 0; } } - switch(event) { + switch (event) { /* incoming and outgoing affects the inUse counter */ - case DEC_OUT_USE: - case DEC_IN_USE: - if ( *inuse > 0 ) { - (*inuse)--; - } else { - *inuse = 0; - } - break; - case INC_IN_USE: - case INC_OUT_USE: - if (*incominglimit > 0 ) { - if (*inuse >= *incominglimit) { - ast_log(LOG_ERROR, "Call from %s '%s' rejected due to usage limit of %d\n", u?"user":"peer", name, *incominglimit); - /* inc inUse as well */ - if ( event == INC_OUT_USE ) { + case DEC_OUT_USE: + case DEC_IN_USE: + if ( *inuse > 0 ) + (*inuse)--; + else + *inuse = 0; + break; + case INC_IN_USE: + case INC_OUT_USE: + if (*incominglimit > 0 ) { + if (*inuse >= *incominglimit) { + ast_log(LOG_ERROR, "Call from %s '%s' rejected due to usage limit of %d\n", u?"user":"peer", name, *incominglimit); + /* inc inUse as well */ + if ( event == INC_OUT_USE ) (*inuse)++; - } - if (u) - ASTOBJ_UNREF(u,sip_destroy_user); - else - ASTOBJ_UNREF(p,sip_destroy_peer); - return -1; - } + if (u) + ASTOBJ_UNREF(u,sip_destroy_user); + else + ASTOBJ_UNREF(p,sip_destroy_peer); + return -1; } - (*inuse)++; - ast_log(LOG_DEBUG, "Call from %s '%s' is %d out of %d\n", u?"user":"peer", name, *inuse, *incominglimit); - break; + } + (*inuse)++; + ast_log(LOG_DEBUG, "Call from %s '%s' is %d out of %d\n", u?"user":"peer", name, *inuse, *incominglimit); + break; #ifdef DISABLED_CODE - /* we don't use these anymore */ - case DEC_OUT_USE: - if ( u->outUse > 0 ) { - u->outUse--; - } else { - u->outUse = 0; - } - break; - case INC_OUT_USE: - if ( u->outgoinglimit > 0 ) { - if ( u->outUse >= u->outgoinglimit ) { - ast_log(LOG_ERROR, "Outgoing call from user '%s' rejected due to usage limit of %d\n", u->name, u->outgoinglimit); - ast_mutex_unlock(&userl.lock); - if (u->temponly) { - destroy_user(u); - } - return -1; - } + /* we don't use these anymore */ + case DEC_OUT_USE: + if ( u->outUse > 0 ) + u->outUse--; + else + u->outUse = 0; + break; + case INC_OUT_USE: + if ( u->outgoinglimit > 0 ) { + if ( u->outUse >= u->outgoinglimit ) { + ast_log(LOG_ERROR, "Outgoing call from user '%s' rejected due to usage limit of %d\n", u->name, u->outgoinglimit); + ast_mutex_unlock(&userl.lock); + if (u->temponly) + destroy_user(u); + return -1; } - u->outUse++; - break; + } + u->outUse++; + break; #endif - default: - ast_log(LOG_ERROR, "update_user_counter(%s,%d) called with no event!\n",name,event); + default: + ast_log(LOG_ERROR, "update_user_counter(%s,%d) called with no event!\n",name,event); } if (u) ASTOBJ_UNREF(u,sip_destroy_user); @@ -2057,45 +2060,41 @@ ast_mutex_unlock(&iflock); } - -static int transmit_response_reliable(struct sip_pvt *p, char *msg, struct sip_request *req, int fatal); - /*--- hangup_sip2cause: Convert SIP hangup causes to Asterisk hangup causes ---*/ static int hangup_sip2cause(int cause) { /* Possible values taken from causes.h */ - switch(cause) { - case 403: /* Not found */ - return AST_CAUSE_CALL_REJECTED; - case 404: /* Not found */ - return AST_CAUSE_UNALLOCATED; - case 408: /* No reaction */ - return AST_CAUSE_NO_USER_RESPONSE; - case 480: /* No answer */ - return AST_CAUSE_FAILURE; - case 483: /* Too many hops */ - return AST_CAUSE_NO_ANSWER; - case 486: /* Busy everywhere */ - return AST_CAUSE_BUSY; - case 488: /* No codecs approved */ - return AST_CAUSE_BEARERCAPABILITY_NOTAVAIL; - case 500: /* Server internal failure */ - return AST_CAUSE_FAILURE; - case 501: /* Call rejected */ - return AST_CAUSE_FACILITY_REJECTED; - case 502: - return AST_CAUSE_DESTINATION_OUT_OF_ORDER; - case 503: /* Service unavailable */ - return AST_CAUSE_CONGESTION; - default: - return AST_CAUSE_NORMAL; + switch (cause) { + case 403: /* Not found */ + return AST_CAUSE_CALL_REJECTED; + case 404: /* Not found */ + return AST_CAUSE_UNALLOCATED; + case 408: /* No reaction */ + return AST_CAUSE_NO_USER_RESPONSE; + case 480: /* No answer */ + return AST_CAUSE_FAILURE; + case 483: /* Too many hops */ + return AST_CAUSE_NO_ANSWER; + case 486: /* Busy everywhere */ + return AST_CAUSE_BUSY; + case 488: /* No codecs approved */ + return AST_CAUSE_BEARERCAPABILITY_NOTAVAIL; + case 500: /* Server internal failure */ + return AST_CAUSE_FAILURE; + case 501: /* Call rejected */ + return AST_CAUSE_FACILITY_REJECTED; + case 502: + return AST_CAUSE_DESTINATION_OUT_OF_ORDER; + case 503: /* Service unavailable */ + return AST_CAUSE_CONGESTION; + default: + return AST_CAUSE_NORMAL; } /* Never reached */ return 0; } - /*--- hangup_cause2sip: Convert Asterisk hangup causes to SIP codes ---*/ /* Possible values from causes.h AST_CAUSE_NOTDEFINED AST_CAUSE_NORMAL AST_CAUSE_BUSY @@ -2128,52 +2127,51 @@ */ static char *hangup_cause2sip(int cause) { - switch(cause) - { - case AST_CAUSE_UNALLOCATED: /* 1 */ - case AST_CAUSE_NO_ROUTE_DESTINATION: /* 3 IAX2: Can't find extension in context */ - case AST_CAUSE_NO_ROUTE_TRANSIT_NET: /* 2 */ - return "404 Not Found"; - case AST_CAUSE_CONGESTION: /* 34 */ - case AST_CAUSE_SWITCH_CONGESTION: /* 42 */ - return "503 Service Unavailable"; - case AST_CAUSE_NO_USER_RESPONSE: /* 18 */ - return "408 Request Timeout"; - case AST_CAUSE_NO_ANSWER: /* 19 */ - return "480 Temporarily unavailable"; - case AST_CAUSE_CALL_REJECTED: /* 21 */ - return "403 Forbidden"; - case AST_CAUSE_NUMBER_CHANGED: /* 22 */ - return "410 Gone"; - case AST_CAUSE_NORMAL_UNSPECIFIED: /* 31 */ - return "480 Temporarily unavailable"; - case AST_CAUSE_INVALID_NUMBER_FORMAT: - return "484 Address incomplete"; - case AST_CAUSE_USER_BUSY: - return "486 Busy here"; - case AST_CAUSE_FAILURE: - return "500 Server internal failure"; - case AST_CAUSE_FACILITY_REJECTED: /* 29 */ - return "501 Not Implemented"; - case AST_CAUSE_CHAN_NOT_IMPLEMENTED: - return "503 Service Unavailable"; - /* Used in chan_iax2 */ - case AST_CAUSE_DESTINATION_OUT_OF_ORDER: - return "502 Bad Gateway"; - case AST_CAUSE_BEARERCAPABILITY_NOTAVAIL: /* Can't find codec to connect to host */ - return "488 Not Acceptable Here"; - - case AST_CAUSE_NOTDEFINED: - default: + switch (cause) { + case AST_CAUSE_UNALLOCATED: /* 1 */ + case AST_CAUSE_NO_ROUTE_DESTINATION: /* 3 IAX2: Can't find extension in context */ + case AST_CAUSE_NO_ROUTE_TRANSIT_NET: /* 2 */ + return "404 Not Found"; + case AST_CAUSE_CONGESTION: /* 34 */ + case AST_CAUSE_SWITCH_CONGESTION: /* 42 */ + return "503 Service Unavailable"; + case AST_CAUSE_NO_USER_RESPONSE: /* 18 */ + return "408 Request Timeout"; + case AST_CAUSE_NO_ANSWER: /* 19 */ + return "480 Temporarily unavailable"; + case AST_CAUSE_CALL_REJECTED: /* 21 */ + return "403 Forbidden"; + case AST_CAUSE_NUMBER_CHANGED: /* 22 */ + return "410 Gone"; + case AST_CAUSE_NORMAL_UNSPECIFIED: /* 31 */ + return "480 Temporarily unavailable"; + case AST_CAUSE_INVALID_NUMBER_FORMAT: + return "484 Address incomplete"; + case AST_CAUSE_USER_BUSY: + return "486 Busy here"; + case AST_CAUSE_FAILURE: + return "500 Server internal failure"; + case AST_CAUSE_FACILITY_REJECTED: /* 29 */ + return "501 Not Implemented"; + case AST_CAUSE_CHAN_NOT_IMPLEMENTED: + return "503 Service Unavailable"; + /* Used in chan_iax2 */ + case AST_CAUSE_DESTINATION_OUT_OF_ORDER: + return "502 Bad Gateway"; + case AST_CAUSE_BEARERCAPABILITY_NOTAVAIL: /* Can't find codec to connect to host */ + return "488 Not Acceptable Here"; + + case AST_CAUSE_NOTDEFINED: + default: + if (option_debug) ast_log(LOG_DEBUG, "AST hangup cause %d (no match found in SIP)\n", cause); - return NULL; + return NULL; } /* Never reached */ return 0; } - /*--- sip_hangup: Hangup SIP call ---*/ /* Part of PBX interface */ static int sip_hangup(struct ast_channel *ast) @@ -2195,10 +2193,12 @@ } #endif if (ast_test_flag(p, SIP_OUTGOING)) { - ast_log(LOG_DEBUG, "update_user_counter(%s) - decrement outUse counter\n", p->username); + if (option_debug > 3) + ast_log(LOG_DEBUG, "update_user_counter(%s) - decrement outUse counter\n", p->username); update_user_counter(p, DEC_OUT_USE); } else { - ast_log(LOG_DEBUG, "update_user_counter(%s) - decrement inUse counter\n", p->username); + if (option_debug > 3) + ast_log(LOG_DEBUG, "update_user_counter(%s) - decrement inUse counter\n", p->username); update_user_counter(p, DEC_IN_USE); } /* Determine how to disconnect */ @@ -2393,9 +2393,6 @@ return res; } -#define DEFAULT_MAX_FORWARDS 70 - - /*--- sip_transfer: Transfer SIP call */ static int sip_transfer(struct ast_channel *ast, const char *dest) { @@ -2420,18 +2417,16 @@ int res = 0; ast_mutex_lock(&p->lock); - switch(condition) { + switch (condition) { case AST_CONTROL_RINGING: if (ast->_state == AST_STATE_RING) { if (!ast_test_flag(p, SIP_PROGRESS_SENT) || - (ast_test_flag(p, SIP_PROG_INBAND) == SIP_PROG_INBAND_NEVER)) { + (ast_test_flag(p, SIP_PROG_INBAND) == SIP_PROG_INBAND_NEVER)) { /* Send 180 ringing if out-of-band seems reasonable */ transmit_response(p, "180 Ringing", &p->initreq); ast_set_flag(p, SIP_RINGING); if (ast_test_flag(p, SIP_PROG_INBAND) != SIP_PROG_INBAND_YES) break; - } else { - /* Well, if it's not reasonable, just send in-band */ } } res = -1; @@ -2494,8 +2489,6 @@ return res; } - - /*--- sip_new: Initiate a call in the SIP channel */ /* called from sip_request (calls from the pbx ) */ static struct ast_channel *sip_new(struct sip_pvt *i, int state, char *title) @@ -2594,7 +2587,7 @@ } ast_setstate(tmp, state); if (state != AST_STATE_DOWN) { - if (ast_pbx_start(tmp)) { + if (ast_pbx_start(tmp)) { ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmp->name); ast_hangup(tmp); tmp = NULL; @@ -2638,8 +2631,8 @@ *iterator = 0; } -static char* get_sdp_iterate(int* iterator, - struct sip_request *req, char *name) + +static char* get_sdp_iterate(int* iterator, struct sip_request *req, char *name) { int len = strlen(name); char *r; @@ -2652,6 +2645,7 @@ return ""; } + static char *find_alias(const char *name, char *_default) { int x; @@ -2661,6 +2655,7 @@ return _default; } + static char *__get_header(struct sip_request *req, char *name, int *start) { int pass; @@ -2709,7 +2704,7 @@ /* Retrieve audio/etc from channel. Assumes p->lock is already held. */ struct ast_frame *f; static struct ast_frame null_frame = { AST_FRAME_NULL, }; - switch(ast->fdno) { + switch (ast->fdno) { case 0: f = ast_rtp_read(p->rtp); /* RTP Audio */ break; @@ -2789,7 +2784,7 @@ return NULL; /* Keep track of stuff */ memset(p, 0, sizeof(struct sip_pvt)); - ast_mutex_init(&p->lock); + ast_mutex_init(&p->lock); p->method = intended_method; p->initid = -1; @@ -2916,7 +2911,7 @@ } ast_mutex_lock(&iflock); p = iflist; - while(p) { + while (p) { if (!strcmp(p->callid, callid) && (!pedanticsipchecking || !tag || ast_strlen_zero(p->theirtag) || !strcmp(p->theirtag, tag))) { /* Found the call */ @@ -3062,14 +3057,10 @@ /* First header starts immediately */ req->header[f] = c; - while(*c) { + while (*c) { if (*c == '\n') { /* We've got a new header */ *c = 0; - -#if 0 - printf("Header: %s (%d)\n", req->header[f], strlen(req->header[f])); -#endif if (ast_strlen_zero(req->header[f])) { /* Line by itself means we're now in content */ c++; @@ -3093,13 +3084,10 @@ /* Now we process any mime content */ f = 0; req->line[f] = c; - while(*c) { + while (*c) { if (*c == '\n') { /* We've got a new line */ *c = 0; -#if 0 - printf("Line: %s (%d)\n", req->line[f], strlen(req->line[f])); -#endif if (f >= SIP_MAX_LINES - 1) { ast_log(LOG_WARNING, "Too many SDP lines...\n"); } else @@ -3175,13 +3163,13 @@ while ((m = get_sdp_iterate(&iterator, req, "m"))[0] != '\0') { int found = 0; if ((sscanf(m, "audio %d RTP/AVP %n", &x, &len) == 1) || - (sscanf(m, "audio %d/%d RTP/AVP %n", &x, &y, &len) == 2)) { + (sscanf(m, "audio %d/%d RTP/AVP %n", &x, &y, &len) == 2)) { found = 1; portno = x; /* Scan through the RTP payload types specified in a "m=" line: */ ast_rtp_pt_clear(p->rtp); codecs = m + len; - while(!ast_strlen_zero(codecs)) { + while (!ast_strlen_zero(codecs)) { if (sscanf(codecs, "%d%n", &codec, &len) != 1) { ast_log(LOG_WARNING, "Error in codec string '%s'\n", codecs); return -1; @@ -3201,7 +3189,7 @@ vportno = x; /* Scan through the RTP payload types specified in a "m=" line: */ codecs = m + len; - while(!ast_strlen_zero(codecs)) { + while (!ast_strlen_zero(codecs)) { if (sscanf(codecs, "%d%n", &codec, &len) != 1) { ast_log(LOG_WARNING, "Error in codec string '%s'\n", codecs); return -1; @@ -3371,11 +3359,11 @@ /* No address for RTP, we're on hold */ append_history(p, "Hold", req->data); if (callevents && !ast_test_flag(p, SIP_CALL_ONHOLD)) { - manager_event(EVENT_FLAG_CALL, "Hold", - "Channel: %s\r\n" - "Uniqueid: %s\r\n", - p->owner->name, - p->owner->uniqueid); + manager_event(EVENT_FLAG_CALL, "Hold", + "Channel: %s\r\n" + "Uniqueid: %s\r\n", + p->owner->name, + p->owner->uniqueid); } ast_set_flag(p, SIP_CALL_ONHOLD); /* Indicate HOLD status to the other channel */ @@ -3658,7 +3646,6 @@ return 0; } - /*--- respprep: Prepare SIP response packet ---*/ static int respprep(struct sip_request *resp, struct sip_pvt *p, char *msg, struct sip_request *req) { @@ -3710,7 +3697,7 @@ return 0; } -/*--- reqprep: Initialize a SIP request packet ---*/ +/*--- reqprep: Initialize a SIP request response packet ---*/ static int reqprep(struct sip_request *req, struct sip_pvt *p, int sipmethod, int seqno, int newbranch) { struct sip_request *orig = &p->initreq; @@ -3737,7 +3724,7 @@ c = p->initreq.rlPart2; /* Use original URI */ } else if (sipmethod == SIP_ACK) { /* Use URI from Contact: in 200 OK (if INVITE) - (we only have the contacturi on INVITEs) */ + (we only have the contacturi on INVITEs) */ if (!ast_strlen_zero(p->okcontacturi)) c = p->okcontacturi; else @@ -3750,7 +3737,7 @@ /* We have no URI, use To: or From: header as URI (depending on direction) */ c = get_header(orig, (ast_test_flag(p, SIP_OUTGOING)) ? "To" : "From"); ast_copy_string(stripped, c, sizeof(stripped)); - c = get_in_brackets(stripped); + c = ditch_braces(stripped, 1); n = strchr(c, ';'); if (n) *n = '\0'; @@ -3789,7 +3776,12 @@ add_header(req, "From", ot); add_header(req, "To", of); } - add_header(req, "Contact", p->our_contact); + if (sipmethod == SIP_MESSAGE) { + /* Add date header to MESSAGE */ + append_date(req); + } else { + add_header(req, "Contact", p->our_contact); + } copy_header(req, orig, "Call-ID"); add_header(req, "CSeq", tmp); @@ -3869,6 +3861,7 @@ return send_response(p, &resp, reliable, 0); } + /* transmit_response_with_auth: Respond with authorization request */ static int transmit_response_with_auth(struct sip_pvt *p, char *msg, struct sip_request *req, char *randdata, int reliable, char *header, int stale) { @@ -4156,7 +4149,7 @@ e = ast_skip_blanks(e); if ( !*e ) return -1; - + if ( !strcasecmp(cmd, "SIP/2.0") ) { /* We have a response */ req->rlPart2 = e; @@ -4178,7 +4171,7 @@ return -1; } /* XXX maybe trim_blanks() ? */ - while( isspace( *(--e) ) ) {} + while (isspace(*(--e))) {} if ( *e == '>' ) { *e = '\0'; } else { @@ -4222,7 +4215,7 @@ char stripped[256]=""; char *c, *n; ast_copy_string(stripped, get_header(req, "Contact"), sizeof(stripped)); - c = get_in_brackets(stripped); + c = ditch_braces(stripped, 1); n = strchr(c, ';'); if (n) *n = '\0'; @@ -4255,31 +4248,25 @@ char urioptions[256]=""; if (ast_test_flag(p, SIP_USEREQPHONE)) { - char onlydigits = 1; - x=0; - - /* Test p->username against allowed characters in AST_DIGIT_ANY - If it matches the allowed characters list, then sipuser = ";user=phone" - - If not, then sipuser = "" - */ - /* + is allowed in first position in a tel: uri */ - if (p->username && p->username[0] == '+') - x=1; - - for (; xusername); x++) { - if (!strchr(AST_DIGIT_ANYNUM, p->username[x])) { - onlydigits = 0; - break; - } - } - - /* If we have only digits, add ;user=phone to the uri */ - if (onlydigits) - strcpy(urioptions, ";user=phone"); + char onlydigits = 1; + x=0; + /* Test p->username against allowed characters in AST_DIGIT_ANY + If it matches the allowed characters list, then sipuser = ";user=phone" + If not, then sipuser = "" + + is allowed in first position in a tel: uri */ + if (p->username && p->username[0] == '+') + x=1; + for (; xusername); x++) { + if (!strchr(AST_DIGIT_ANYNUM, p->username[x])) { + onlydigits = 0; + break; + } + } + /* If we have only digits, add ;user=phone to the uri */ + if (onlydigits) + strcpy(urioptions, ";user=phone"); } - snprintf(p->lastmsg, sizeof(p->lastmsg), "Init: %s", sip_methods[sipmethod].text); if (p->owner) { @@ -4287,7 +4274,7 @@ n = p->owner->cid.cid_name; } if (!l || (!ast_isphonenumber(l) && default_callerid[0])) - l = default_callerid; + l = default_callerid; /* if user want's his callerid restricted */ if ((p->callingpres & AST_PRES_RESTRICTION) != AST_PRES_ALLOWED) { l = CALLERID_UNKNOWN; @@ -4318,24 +4305,20 @@ ast_copy_string(invite, p->fullcontact, sizeof(invite)); /* Otherwise, use the username while waiting for registration */ } else if (!ast_strlen_zero(p->username)) { - if (ntohs(p->sa.sin_port) != DEFAULT_SIP_PORT) { + if (ntohs(p->sa.sin_port) != DEFAULT_SIP_PORT) snprintf(invite, sizeof(invite), "sip:%s@%s:%d%s",p->username, p->tohost, ntohs(p->sa.sin_port), urioptions); - } else { + else snprintf(invite, sizeof(invite), "sip:%s@%s%s",p->username, p->tohost, urioptions); - } - } else if (ntohs(p->sa.sin_port) != DEFAULT_SIP_PORT) { + } else if (ntohs(p->sa.sin_port) != DEFAULT_SIP_PORT) snprintf(invite, sizeof(invite), "sip:%s:%d%s", p->tohost, ntohs(p->sa.sin_port), urioptions); - } else { + else snprintf(invite, sizeof(invite), "sip:%s%s", p->tohost, urioptions); - } ast_copy_string(p->uri, invite, sizeof(p->uri)); /* If there is a VXML URL append it to the SIP URL */ if (vxml_url) - { snprintf(to, sizeof(to), "<%s>;%s", invite, vxml_url); - } else { + else snprintf(to, sizeof(to), "<%s>", invite); - } memset(req, 0, sizeof(struct sip_request)); init_req(req, sipmethod, invite); snprintf(tmp, sizeof(tmp), "%d %s", ++p->ocseq, sip_methods[sipmethod].text); @@ -4353,7 +4336,6 @@ add_header(req, "User-Agent", default_useragent); } - /*--- transmit_invite: Build REFER/INVITE/OPTIONS message and transmit it ---*/ static int transmit_invite(struct sip_pvt *p, int sipmethod, int sdp, struct sip_invite_param *options, int init) { @@ -4380,14 +4362,11 @@ if (options && options->osptoken && !ast_strlen_zero(options->osptoken)) { ast_log(LOG_DEBUG,"Adding OSP Token: %s\n", options->osptoken); add_header(&req, "P-OSP-Auth-Token", options->osptoken); - } else { + } else ast_log(LOG_DEBUG,"NOT Adding OSP Token\n"); - } #endif if (options && options->distinctive_ring && !ast_strlen_zero(options->distinctive_ring)) - { add_header(&req, "Alert-Info", options->distinctive_ring); - } add_header(&req, "Allow", ALLOWED_METHODS); if (options && options->addsipheaders && init) { struct ast_channel *ast; @@ -4410,7 +4389,7 @@ /* Strip of the starting " (if it's there) */ if (*header == '"') header++; - if ((content = strchr(header, ':'))) { + if ((content = strchr(header, ':'))) { *content = '\0'; content++; /* Move pointer ahead */ /* Skip white space */ @@ -4420,8 +4399,7 @@ end = content + strlen(content) -1; if (*end == '"') *end = '\0'; - - add_header(&req, header, content); + add_header(&req, header, content); if (sipdebug) ast_log(LOG_DEBUG, "Adding SIP Header \"%s\" with content :%s: \n", header, content); } @@ -4454,101 +4432,176 @@ static int transmit_state_notify(struct sip_pvt *p, int state, int full) { char tmp[4000]; - int maxbytes = 0; - int bytes = 0; + char *t = tmp; + int maxbytes = sizeof(tmp); char from[256], to[256]; - char *t, *c, *a; - char *mfrom, *mto; + char *mfrom, *mto, *c, *a; struct sip_request req; char clen[20]; + char hint[AST_MAX_EXTENSION]; + char *statestring = "terminated"; + enum state { + NOTIFY_OPEN = 0, + NOTIFY_INUSE = 1, + NOTIFY_CLOSED = 2, + } local_state = NOTIFY_OPEN; + char *pidfstate = "--"; + char *pidfnote= "Ready"; + struct ast_channel *chan = NULL; + struct sip_pvt *np; + char notify_cid[AST_MAX_EXTENSION] = ""; + char notify_callid[80] = ""; + int notify_ourtag = 0; + char notify_theirtag[256] = ""; + int hintlen; + + switch (state) { + case AST_EXTENSION_RINGING_AND_INUSE: + if (global_notifyringing) + statestring = "early"; + else + statestring = "confirmed"; + local_state = NOTIFY_INUSE; + pidfstate = "busy"; + pidfnote = "Ringing"; + break; + case AST_EXTENSION_RINGING: + statestring = "early"; + local_state = NOTIFY_INUSE; + pidfstate = "busy"; + pidfnote = "Ringing"; + break; + case AST_EXTENSION_INUSE: + statestring = "confirmed"; + local_state = NOTIFY_INUSE; + pidfstate = "busy"; + pidfnote = "On the phone"; + break; + case AST_EXTENSION_BUSY: + statestring = "confirmed"; + local_state = NOTIFY_CLOSED; + pidfstate = "busy"; + pidfnote = "On the phone"; + break; + case AST_EXTENSION_UNAVAILABLE: + statestring = "confirmed"; + local_state = NOTIFY_CLOSED; + pidfstate = "away"; + pidfnote = "Unavailable"; + break; + case AST_EXTENSION_NOT_INUSE: + default: + /* Default setting */ + break; + } + + /* Check which device/devices we are watching and if they are registered */ + if (ast_get_hint(hint, sizeof(hint), NULL, 0, NULL, p->context, p->exten)) { + /* If they are not registered, we will override notification and show no availability */ + if (ast_device_state(hint) == AST_DEVICE_UNAVAILABLE) { + local_state = NOTIFY_CLOSED; + pidfstate = "away"; + pidfnote = "Not online"; + } + + /* check if the device is ringing and if so get the callid to enable pickup functionality (e.g. for snom phones) */ + if (state == AST_EXTENSION_RINGING_AND_INUSE || state == AST_EXTENSION_RINGING) { + hintlen = strlen(hint); + while ((chan = ast_channel_walk_locked(chan)) != NULL) { + if (chan->_state == AST_STATE_RINGING && chan->tech_pvt && !strncasecmp(chan->name, hint, hintlen)) { + np = chan->tech_pvt; + ast_copy_string(notify_callid, np->callid, sizeof(notify_callid)); + ast_copy_string(notify_theirtag, np->theirtag, sizeof(notify_theirtag)); + ast_copy_string(notify_cid, np->fromname, sizeof(notify_cid)); + notify_ourtag = np->tag; + ast_mutex_unlock(&chan->lock); + break; + } + ast_mutex_unlock(&chan->lock); + } + if (ast_strlen_zero(notify_callid)) + ast_log(LOG_NOTICE, "CallID for hint %s not found\n", hint); + } + } memset(from, 0, sizeof(from)); - memset(to, 0, sizeof(to)); ast_copy_string(from, get_header(&p->initreq, "From"), sizeof(from)); - - c = ditch_braces(from); + c = ditch_braces(from, 0); if (strncmp(c, "sip:", 4)) { ast_log(LOG_WARNING, "Huh? Not a SIP header (%s)?\n", c); return -1; } - if ((a = strchr(c, ';'))) { + if ((a = strchr(c, ';'))) *a = '\0'; - } mfrom = c; - reqprep(&req, p, SIP_NOTIFY, 0, 1); - - if (p->subscribed == 1) { - ast_copy_string(to, get_header(&p->initreq, "To"), sizeof(to)); + memset(to, 0, sizeof(to)); + ast_copy_string(to, get_header(&p->initreq, "To"), sizeof(to)); + c = ditch_braces(to, 0); + if (strncmp(c, "sip:", 4)) { + ast_log(LOG_WARNING, "Huh? Not a SIP header (%s)?\n", c); + return -1; + } + if ((a = strchr(c, ';'))) + *a = '\0'; + mto = c; - c = ditch_braces(to); - if (strncmp(c, "sip:", 4)) { - ast_log(LOG_WARNING, "Huh? Not a SIP header (%s)?\n", c); - return -1; - } - if ((a = strchr(c, ';'))) { - *a = '\0'; - } - mto = c; + reqprep(&req, p, SIP_NOTIFY, 0, 1); + switch (p->subscribed) { + case SUBSCRIBE_XPIDF_XML: + case SUBSCRIBE_CPIM_PIDF_XML: add_header(&req, "Event", "presence"); add_header(&req, "Subscription-State", "active"); add_header(&req, "Content-Type", "application/xpidf+xml"); - - if ((state==AST_EXTENSION_UNAVAILABLE) || (state==AST_EXTENSION_BUSY)) - state = 2; - else if (state==AST_EXTENSION_INUSE) - state = 1; + ast_build_string(&t, &maxbytes, "\n"); + ast_build_string(&t, &maxbytes, "\n"); + ast_build_string(&t, &maxbytes, "\n"); + ast_build_string(&t, &maxbytes, "\n", mfrom); + ast_build_string(&t, &maxbytes, "\n", p->exten); + ast_build_string(&t, &maxbytes, "
\n", mto); + ast_build_string(&t, &maxbytes, "\n", (local_state == NOTIFY_OPEN) ? "open" : (local_state == NOTIFY_INUSE) ? "inuse" : "closed"); + ast_build_string(&t, &maxbytes, "\n", (local_state == NOTIFY_OPEN) ? "online" : (local_state == NOTIFY_INUSE) ? "onthephone" : "offline"); + ast_build_string(&t, &maxbytes, "
\n
\n
\n"); + break; + case SUBSCRIBE_PIDF_XML: /* Eyebeam supports this format */ + add_header(&req, "Event", "presence"); + add_header(&req, "Subscription-State", "active"); + add_header(&req, "Content-Type", "application/pidf+xml"); + ast_build_string(&t, &maxbytes, "\n"); + ast_build_string(&t, &maxbytes, "\n", mfrom); + ast_build_string(&t, &maxbytes, "\n"); + if (pidfstate[0] != '-') + ast_build_string(&t, &maxbytes, "%s\n", pidfstate); + ast_build_string(&t, &maxbytes, "\n"); + ast_build_string(&t, &maxbytes, "%s\n", pidfnote); /* Note */ + ast_build_string(&t, &maxbytes, "\n", p->exten); /* Tuple start */ + ast_build_string(&t, &maxbytes, "%s\n", mto); + if (pidfstate[0] == 'b') /* Busy? Still open ... */ + ast_build_string(&t, &maxbytes, "open\n"); else - state = 0; - - t = tmp; - maxbytes = sizeof(tmp); - bytes = snprintf(t, maxbytes, "\n"); - t += bytes; - maxbytes -= bytes; - bytes = snprintf(t, maxbytes, "\n"); - t += bytes; - maxbytes -= bytes; - bytes = snprintf(t, maxbytes, "\n"); - t += bytes; - maxbytes -= bytes; - bytes = snprintf(t, maxbytes, "\n", mfrom); - t += bytes; - maxbytes -= bytes; - bytes = snprintf(t, maxbytes, "\n", p->exten); - t += bytes; - maxbytes -= bytes; - bytes = snprintf(t, maxbytes, "
\n", mto); - t += bytes; - maxbytes -= bytes; - bytes = snprintf(t, maxbytes, "\n", !state ? "open" : (state==1) ? "inuse" : "closed"); - t += bytes; - maxbytes -= bytes; - bytes = snprintf(t, maxbytes, "\n", !state ? "online" : (state==1) ? "onthephone" : "offline"); - t += bytes; - maxbytes -= bytes; - bytes = snprintf(t, maxbytes, "
\n
\n
\n"); - } else { + ast_build_string(&t, &maxbytes, "%s\n", (local_state != NOTIFY_CLOSED) ? "open" : "closed"); + ast_build_string(&t, &maxbytes, "
\n
\n"); + break; + case SUBSCRIBE_DIALOG_INFO_XML: /* SNOM subscribes in this format */ add_header(&req, "Event", "dialog"); add_header(&req, "Content-Type", "application/dialog-info+xml"); - - t = tmp; - maxbytes = sizeof(tmp); - bytes = snprintf(t, maxbytes, "\n"); - t += bytes; - maxbytes -= bytes; - bytes = snprintf(t, maxbytes, "\n", p->dialogver++, full ? "full":"partial", mfrom); - t += bytes; - maxbytes -= bytes; - bytes = snprintf(t, maxbytes, "\n", p->exten); - t += bytes; - maxbytes -= bytes; - bytes = snprintf(t, maxbytes, "%s\n", state ? "confirmed" : "terminated"); - t += bytes; - maxbytes -= bytes; - bytes = snprintf(t, maxbytes, "\n\n"); + ast_build_string(&t, &maxbytes, "\n"); + ast_build_string(&t, &maxbytes, "\n", p->dialogver++, full ? "full":"partial", mto); + if (!ast_strlen_zero(notify_callid)) { + ast_build_string(&t, &maxbytes, "\n", p->exten, notify_callid, notify_ourtag, notify_theirtag); + if (option_debug > 1) + ast_log(LOG_NOTICE, "Transmitting CallID in NOTIFY message - DialogID: %s CallID: %s\n", p->exten, notify_callid); + } else + ast_build_string(&t, &maxbytes, "\n", p->exten); + ast_build_string(&t, &maxbytes, "%s\n", statestring); + if (state == AST_EXTENSION_RINGING) { + ast_build_string(&t, &maxbytes, "%s\n", p->exten, mfrom, mfrom); + ast_build_string(&t, &maxbytes, "%s\n", notify_cid, mto, mto); + } + ast_build_string(&t, &maxbytes, "\n\n"); } + if (t > tmp + sizeof(tmp)) ast_log(LOG_WARNING, "Buffer overflow detected!! (Please file a bug report)\n"); @@ -4565,25 +4618,30 @@ * We use the SIP Event package message-summary * MIME type defaults to "application/simple-message-summary"; */ -static int transmit_notify_with_mwi(struct sip_pvt *p, int newmsgs, int oldmsgs) +static int transmit_notify_with_mwi(struct sip_pvt *p, int newmsgs, int oldmsgs, char *vmexten) { struct sip_request req; - char tmp[256]; - char tmp2[256]; + char tmp[1000]; + char *t = tmp; + int maxbytes = sizeof(tmp); char clen[20]; + initreqprep(&req, p, SIP_NOTIFY, NULL); add_header(&req, "Event", "message-summary"); add_header(&req, "Content-Type", default_notifymime); - snprintf(tmp, sizeof(tmp), "Messages-Waiting: %s\r\n", newmsgs ? "yes" : "no"); - snprintf(tmp2, sizeof(tmp2), "Voice-Message: %d/%d (0/0)\r\n", newmsgs, oldmsgs); - snprintf(clen, sizeof(clen), "%d", (int)(strlen(tmp) + strlen(tmp2))); + ast_build_string(&t, &maxbytes, "Message-Account: sip:%s@%s\r\n", (vmexten && !ast_strlen_zero(vmexten)) ? vmexten : global_vmexten, p->fromdomain); + ast_build_string(&t, &maxbytes, "Messages-Waiting: %s\r\n", newmsgs ? "yes" : "no"); + ast_build_string(&t, &maxbytes, "Voice-Message: %d/%d (0/0)\r\n", newmsgs, oldmsgs); + + if (t > tmp + sizeof(tmp)) + ast_log(LOG_WARNING, "Buffer overflow detected!! (Please file a bug report)\n"); + + snprintf(clen, sizeof(clen), "%d", (int)strlen(tmp)); add_header(&req, "Content-Length", clen); add_line(&req, tmp); - add_line(&req, tmp2); - if (!p->initreq.headers) { - /* Use this as the basis */ + if (!p->initreq.headers) { /* Use this as the basis */ copy_request(&p->initreq, &req); parse(&p->initreq); if (sip_debug_test_pvt(p)) @@ -4642,9 +4700,10 @@ return send_request(p, &req, 1, p->ocseq); } + static char *regstate2str(int regstate) { - switch(regstate) { + switch (regstate) { case REG_STATE_FAILED: return "Failed"; case REG_STATE_UNREGISTERED: @@ -4666,8 +4725,6 @@ } } -static int transmit_register(struct sip_registry *r, int sipmethod, char *auth, char *authheader); - /*--- sip_reregister: Update registration with SIP Proxy---*/ static int sip_reregister(void *data) { @@ -4700,7 +4757,6 @@ /*--- sip_reg_timeout: Registration timeout, register again */ static int sip_reg_timeout(void *data) { - /* if we are here, our registration timed out, so we'll just do it over */ struct sip_registry *r = ASTOBJ_REF((struct sip_registry *) data); struct sip_pvt *p; @@ -4773,7 +4829,7 @@ r->callid_valid = 1; } /* Allocate SIP packet for registration */ - p=sip_alloc( r->callid, NULL, 0, SIP_REGISTER); + p = sip_alloc(r->callid, NULL, 0, SIP_REGISTER); if (!p) { ast_log(LOG_WARNING, "Unable to allocate registration call\n"); return 0; @@ -4899,7 +4955,6 @@ memset(digest,0,sizeof(digest)); build_reply_digest(p, sipmethod, digest, sizeof(digest)); add_header(&req, "Authorization", digest); - } snprintf(tmp, sizeof(tmp), "%d", default_expiry); @@ -4910,9 +4965,8 @@ add_blank_header(&req); copy_request(&p->initreq, &req); parse(&p->initreq); - if (sip_debug_test_pvt(p)) { + if (sip_debug_test_pvt(p)) ast_verbose("REGISTER %d headers, %d lines\n", p->initreq.headers, p->initreq.lines); - } determine_firstline_parts(&p->initreq); r->regstate=auth?REG_STATE_AUTHSENT:REG_STATE_REGSENT; r->regattempts++; /* Another attempt */ @@ -4937,56 +4991,52 @@ char from[256]; char *of, *c; char referto[256]; - char tmp[80]; + char tmp[80]; if (ast_test_flag(p, SIP_OUTGOING)) of = get_header(&p->initreq, "To"); else of = get_header(&p->initreq, "From"); ast_copy_string(from, of, sizeof(from)); - of = ditch_braces(from); + of = ditch_braces(from, 0); ast_copy_string(p->from,of,sizeof(p->from)); if (strncmp(of, "sip:", 4)) { ast_log(LOG_NOTICE, "From address missing 'sip:', using it anyway\n"); } else of += 4; /* Get just the username part */ - if ((c = strchr(dest, '@'))) { - c = NULL; - } else if ((c = strchr(of, '@'))) { + if ((c = strchr(dest, '@'))) { + c = NULL; + } else if ((c = strchr(of, '@'))) { *c = '\0'; c++; } - if (c) { + if (c) snprintf(referto, sizeof(referto), "", dest, c); - } else { + else snprintf(referto, sizeof(referto), "", dest); - } - ast_copy_string(tmp, get_header(&p->initreq, "Max-Forwards"), sizeof(tmp)); - if (strlen(tmp) && atoi(tmp)) { - p->maxforwards = atoi(tmp) - 1; - } else { - p->maxforwards = DEFAULT_MAX_FORWARDS - 1; - } - if (p->maxforwards > -1) { - /* save in case we get 407 challenge */ - ast_copy_string(p->refer_to, referto, sizeof(p->refer_to)); - ast_copy_string(p->referred_by, p->our_contact, sizeof(p->referred_by)); - - reqprep(&req, p, SIP_REFER, 0, 1); - add_header(&req, "Refer-To", referto); - if (!ast_strlen_zero(p->our_contact)) - add_header(&req, "Referred-By", p->our_contact); - add_blank_header(&req); - return send_request(p, &req, 1, p->ocseq); - } else { - return -1; - } + ast_copy_string(tmp, get_header(&p->initreq, "Max-Forwards"), sizeof(tmp)); + if (strlen(tmp) && atoi(tmp)) + p->maxforwards = atoi(tmp) - 1; + else + p->maxforwards = DEFAULT_MAX_FORWARDS - 1; + if (p->maxforwards > -1) { + /* save in case we get 407 challenge */ + ast_copy_string(p->refer_to, referto, sizeof(p->refer_to)); + ast_copy_string(p->referred_by, p->our_contact, sizeof(p->referred_by)); + + reqprep(&req, p, SIP_REFER, 0, 1); + add_header(&req, "Refer-To", referto); + if (!ast_strlen_zero(p->our_contact)) + add_header(&req, "Referred-By", p->our_contact); + add_blank_header(&req); + return send_request(p, &req, 1, p->ocseq); + } else + return -1; } -/*--- transmit_info_with_digit: Send SIP INFO dtmf message, see Cisco documentation on cisco.co -m ---*/ +/*--- transmit_info_with_digit: Send SIP INFO dtmf message, see Cisco documentation on cisco.com ---*/ static int transmit_info_with_digit(struct sip_pvt *p, char digit) { struct sip_request req; @@ -5044,7 +5094,6 @@ return 0; } -static int sip_poke_peer(struct sip_peer *peer); static int sip_poke_peer_s(void *data) { @@ -5094,7 +5143,7 @@ if (option_verbose > 2) ast_verbose(VERBOSE_PREFIX_3 "SIP Seeding peer from astdb: '%s' at %s@%s:%d for %d\n", - peer->name, peer->username, ast_inet_ntoa(iabuf, sizeof(iabuf), in), port, expiry); + peer->name, peer->username, ast_inet_ntoa(iabuf, sizeof(iabuf), in), port, expiry); memset(&peer->addr, 0, sizeof(peer->addr)); peer->addr.sin_family = AF_INET; @@ -5125,7 +5174,7 @@ /* Look for brackets */ ast_copy_string(contact, get_header(req, "Contact"), sizeof(contact)); - c = get_in_brackets(contact); + c = ditch_braces(contact, 1); /* Save full contact to call pvt for later bye or re-invite */ ast_copy_string(pvt->fullcontact, c, sizeof(pvt->fullcontact)); @@ -5182,7 +5231,6 @@ return 0; } - /*--- parse_contact: Parse contact header and save registration ---*/ static int parse_contact(struct sip_pvt *pvt, struct sip_peer *p, struct sip_request *req) { @@ -5210,7 +5258,7 @@ } /* Look for brackets */ ast_copy_string(contact, get_header(req, "Contact"), sizeof(contact)); - c = get_in_brackets(contact); + c = ditch_braces(contact, 1); if (!strcasecmp(c, "*") || !expiry) { /* Unregister this peer */ /* This means remove all registrations and return OK */ @@ -5403,7 +5451,8 @@ /* Can be multiple Contact headers, comma separated values - we just take the first */ contact = get_header(req, "Contact"); if (!ast_strlen_zero(contact)) { - ast_log(LOG_DEBUG, "build_route: Contact hop: %s\n", contact); + if (option_debug > 1) + ast_log(LOG_DEBUG, "build_route: Contact hop: %s\n", contact); /* Look for <: delimited address */ c = strchr(contact, '<'); if (c) { @@ -5452,12 +5501,12 @@ /* Always OK if no secret */ if (ast_strlen_zero(secret) && ast_strlen_zero(md5secret) #ifdef OSP_SUPPORT - && !ast_test_flag(p, SIP_OSPAUTH) - && global_allowguest != 2 + && !ast_test_flag(p, SIP_OSPAUTH) + && global_allowguest != 2 #endif ) return 0; - if (sipmethod == SIP_REGISTER) { + if (sipmethod == SIP_REGISTER || sipmethod == SIP_SUBSCRIBE) { /* On a REGISTER, we have to use 401 and its family of headers instead of 407 and its family of headers -- GO SIP! Whoo hoo! Two things that do the same thing but are used in different circumstances! What a surprise. */ @@ -5479,7 +5528,6 @@ snprintf(tmp, sizeof(tmp), "%d", p->osphandle); pbx_builtin_setvar_helper(p->owner, "_OSPHANDLE", tmp); - /* If ospauth is 'exclusive' don't require further authentication */ if ((ast_test_flag(p, SIP_OSPAUTH) == SIP_OSPAUTH_EXCLUSIVE) || (ast_strlen_zero(secret) && ast_strlen_zero(md5secret))) @@ -5529,7 +5577,7 @@ ast_copy_string(tmp, authtoken, sizeof(tmp)); c = tmp; - while(c) { + while (c) { c = ast_skip_blanks(c); if (!*c) break; @@ -5562,11 +5610,11 @@ c+= strlen("username="); if ((*c == '\"')) { digestusername=++c; - if((c = strchr(c,'\"'))) + if ((c = strchr(c,'\"'))) *c = '\0'; } else { digestusername=c; - if((c = strchr(c,','))) + if ((c = strchr(c,','))) *c = '\0'; } } else if (!strncasecmp(c, "nonce=", strlen("nonce="))) { @@ -5592,7 +5640,7 @@ return -2; } - /* Verify nonce from request matches our nonce. If not, send 401 with new nonce */ + /* Verify nonce from request matches our nonce. If not, send 401 with new nonce */ if (strncasecmp(randdata, nonce, randlen)) { wrongnonce = 1; usednonce = nonce; @@ -5617,7 +5665,6 @@ if (wrongnonce) { ast_log(LOG_NOTICE, "stale nonce received from '%s'\n", get_header(req, "To")); - snprintf(randdata, randlen, "%08x", rand()); if (ua_hash && !strncasecmp(ua_hash, resp_hash, strlen(resp_hash))) { /* We got working auth token, based on stale nonce . */ @@ -5641,10 +5688,13 @@ return res; } -/*--- cb_extensionstate: Part of thte SUBSCRIBE support subsystem ---*/ +/*--- cb_extensionstate: Callback for the devicestate notification (SUBSCRIBE) support subsystem ---*/ +/* If you add an "hint" priority to the extension in the dial plan, + you will get notifications on device state changes */ static int cb_extensionstate(char *context, char* exten, int state, void *data) { - struct sip_pvt *p = data; + struct sip_pvt *p = data; /* The actual subscription data */ + if (state == -1) { sip_scheddestroy(p, 15000); p->stateid = -1; @@ -5652,7 +5702,8 @@ } transmit_state_notify(p, state, 1); - + p->laststate = state; + if (option_debug > 1) ast_verbose(VERBOSE_PREFIX_1 "Extension Changed %s new state %d for Notify User %s\n", exten, state, p->username); return 0; @@ -5669,12 +5720,12 @@ char *t; /* Terminate URI */ t = uri; - while(*t && (*t > 32) && (*t != ';')) + while (*t && (*t > 32) && (*t != ';')) t++; *t = '\0'; ast_copy_string(tmp, get_header(req, "To"), sizeof(tmp)); - c = ditch_braces(tmp); + c = ditch_braces(tmp, 0); /* Ditch ;user=phone */ name = strchr(c, ';'); if (name) @@ -5735,9 +5786,8 @@ } } } - if (!res) { - ast_device_state_changed("SIP/%s", peer->name); - } + if (!res) + ast_device_state_changed("SIP/%s", peer->name); if (res < 0) { switch (res) { case -1: @@ -5770,7 +5820,7 @@ ast_copy_string(tmp, get_header(req, "Diversion"), sizeof(tmp)); if (ast_strlen_zero(tmp)) return 0; - c = ditch_braces(tmp); + c = ditch_braces(tmp, 0); if (strncmp(c, "sip:", 4)) { ast_log(LOG_WARNING, "Huh? Not an RDNIS SIP header (%s)?\n", c); return -1; @@ -5798,10 +5848,10 @@ req = &p->initreq; if (req->rlPart2) ast_copy_string(tmp, req->rlPart2, sizeof(tmp)); - c = ditch_braces(tmp); + c = ditch_braces(tmp, 0); ast_copy_string(tmpf, get_header(req, "From"), sizeof(tmpf)); - fr = ditch_braces(tmpf); + fr = ditch_braces(tmpf, 0); if (strncmp(c, "sip:", 4)) { ast_log(LOG_WARNING, "Huh? Not a SIP header (%s)?\n", c); @@ -5845,7 +5895,7 @@ } if (ast_canmatch_extension(NULL, p->context, c, 1, fr) || - !strncmp(c, ast_pickup_ext(),strlen(c))) { + !strncmp(c, ast_pickup_ext(),strlen(c))) { return 1; } @@ -5853,19 +5903,44 @@ } /*--- get_sip_pvt_byid_locked: Lock interface lock and find matching pvt lock ---*/ -static struct sip_pvt *get_sip_pvt_byid_locked(char *callid) +static struct sip_pvt *get_sip_pvt_byid_locked(char *callid, struct sip_request *req, char *totag, char *fromtag) { struct sip_pvt *sip_pvt_ptr = NULL; - + char *real_totag = NULL, *real_fromtag = NULL; + int match = 1; + /* Search interfaces and find the match */ ast_mutex_lock(&iflock); sip_pvt_ptr = iflist; - while(sip_pvt_ptr) { + while (sip_pvt_ptr) { if (!strcmp(sip_pvt_ptr->callid, callid)) { /* Go ahead and lock it (and its owner) before returning */ ast_mutex_lock(&sip_pvt_ptr->lock); + + if (req && pedanticsipchecking) { + if (totag) { + real_totag = ast_strdupa(get_header(req, "To")); + if (sip_extract_tag(&real_totag)) + real_totag = NULL; + if (strcmp(real_totag, totag)) + match = 0; + } + if (match && fromtag) { + real_fromtag = ast_strdupa(get_header(req, "From")); + if (sip_extract_tag(&real_fromtag)) + real_fromtag = NULL; + if (strcmp(real_fromtag, fromtag)) + match = 0; + } + } + + if (!match) { + ast_mutex_unlock(&sip_pvt_ptr->lock); + break; + } + if (sip_pvt_ptr->owner) { - while(ast_mutex_trylock(&sip_pvt_ptr->owner->lock)) { + while (ast_mutex_trylock(&sip_pvt_ptr->owner->lock)) { ast_mutex_unlock(&sip_pvt_ptr->lock); usleep(1); ast_mutex_lock(&sip_pvt_ptr->lock); @@ -5881,12 +5956,31 @@ return sip_pvt_ptr; } +/*--- sip_unescape_uri: Turn %XX into and ascii char ---*/ +static int sip_unescape_uri(char *uri) +{ + char *ptr = uri; + int replaced = 0; + + while ((ptr = strchr(ptr, '%'))) { + /* un-escape urlencoded text */ + if (strlen(ptr) < 3) + break; + *ptr = hex2int(ptr[1]) * 16 + hex2int(ptr[2]); + memmove(ptr+1, ptr+3, strlen(ptr+3) + 1); + ptr++; + replaced++; + } + + return replaced; +} + /*--- get_refer_info: Call transfer support (the REFER method) ---*/ static int get_refer_info(struct sip_pvt *sip_pvt, struct sip_request *outgoing_req) { char *p_refer_to = NULL, *p_referred_by = NULL, *h_refer_to = NULL, *h_referred_by = NULL, *h_contact = NULL; - char *replace_callid = "", *refer_to = NULL, *referred_by = NULL, *ptr = NULL; + char *replace_callid = "", *refer_to = NULL, *referred_by = NULL, *ptr = NULL, *replaces_header=NULL, *refer_uri; struct sip_request *req = NULL; struct sip_pvt *sip_pvt_ptr = NULL; struct ast_channel *chan = NULL, *peer = NULL; @@ -5902,14 +5996,13 @@ return -1; } - refer_to = ditch_braces(h_refer_to); + refer_to = ditch_braces(h_refer_to, 0); if (!( (p_referred_by = get_header(req, "Referred-By")) && (h_referred_by = ast_strdupa(p_referred_by)) )) { ast_log(LOG_WARNING, "No Referrred-By Header That's not illegal\n"); return -1; - } else { - referred_by = ditch_braces(h_referred_by); - } + } else + referred_by = ditch_braces(h_referred_by, 0); h_contact = get_header(req, "Contact"); if (strncmp(refer_to, "sip:", 4)) { @@ -5928,6 +6021,8 @@ if (referred_by) referred_by += 4; + refer_uri = ast_strdupa(refer_to); + if ((ptr = strchr(refer_to, '?'))) { /* Search for arguments */ *ptr = '\0'; @@ -5935,10 +6030,7 @@ if (!strncasecmp(ptr, "REPLACES=", 9)) { char *p; replace_callid = ast_strdupa(ptr + 9); - /* someday soon to support invite/replaces properly! - replaces_header = ast_strdupa(replace_callid); - -anthm - */ + replaces_header = ast_strdupa(replace_callid); url_decode(replace_callid); if ((ptr = strchr(replace_callid, '%'))) *ptr = '\0'; @@ -5976,18 +6068,46 @@ ast_copy_string(sip_pvt->referred_by, "", sizeof(sip_pvt->referred_by)); ast_copy_string(sip_pvt->refer_contact, "", sizeof(sip_pvt->refer_contact)); sip_pvt->refer_call = NULL; - if ((sip_pvt_ptr = get_sip_pvt_byid_locked(replace_callid))) { + if ((sip_pvt_ptr = get_sip_pvt_byid_locked(replace_callid, req, NULL, NULL))) { sip_pvt->refer_call = sip_pvt_ptr; if (sip_pvt->refer_call == sip_pvt) { ast_log(LOG_NOTICE, "Supervised transfer attempted to transfer into same call id (%s == %s)!\n", replace_callid, sip_pvt->callid); sip_pvt->refer_call = NULL; - } else - return 0; + } + return 0; } else { - ast_log(LOG_NOTICE, "Supervised transfer requested, but unable to find callid '%s'. Both legs must reside on Asterisk box to transfer at this time.\n", replace_callid); - /* XXX The refer_to could contain a call on an entirely different machine, requiring an - INVITE with a replaces header -anthm XXX */ - /* The only way to find out is to use the dialplan - oej */ + /* Don't ask me =0 ?, SIP made do it! */ + int cause = 0, res = -1; + struct ast_channel *ichan = NULL; + transmit_notify_with_sipfrag(sip_pvt, sip_pvt->ocseq); + if ((ptr = strchr(refer_uri, ';'))) + *ptr = '\0'; + + if ((ichan = sip_request("SIP", sip_pvt->owner ? sip_pvt->owner->readformat : AST_FORMAT_ULAW, refer_uri, &cause))) { + struct ast_frame *f; + char *rbuf; + ast_log(LOG_DEBUG, "Going hunting for a remote INVITE/Replaces at [%s] Wish me luck!\n", refer_uri); + if ((rbuf = alloca(strlen(replaces_header) + 10))) { + sprintf(rbuf, "Replaces: %s", replaces_header); + sip_addheader(ichan, rbuf); + sip_call(ichan, refer_uri, 20000); + ast_channel_masquerade(sip_pvt->owner, ichan); + if ((f = ast_read(ichan))) { + ast_log(LOG_DEBUG, "WooHoo! The INVITE/Replaces Worked!\n"); + ast_frfree(f); + transmit_response(sip_pvt, "202 Accepted", req); + res = SIP_RETVAL_IGNORE; /* means do nothing more */ + } else + res = -1; + } else { + ast_log(LOG_ERROR,"Memory Error!\n"); + res = -1; + } + + ast_hangup(ichan); + } else + res = -1; + return res; } } else if (ast_exists_extension(NULL, sip_pvt->context, refer_to, 1, NULL) || !strcmp(refer_to, ast_parking_ext())) { /* This is an unsupervised transfer (blind transfer) */ @@ -6008,9 +6128,8 @@ pbx_builtin_setvar_helper(peer, "BLINDTRANSFER", chan->name); } return 0; - } else if (ast_canmatch_extension(NULL, sip_pvt->context, refer_to, 1, NULL)) { + } else if (ast_canmatch_extension(NULL, sip_pvt->context, refer_to, 1, NULL)) return 1; - } return -1; } @@ -6026,7 +6145,7 @@ req = &p->initreq; ast_copy_string(tmp, get_header(req, "Also"), sizeof(tmp)); - c = ditch_braces(tmp); + c = ditch_braces(tmp, 0); if (strncmp(c, "sip:", 4)) { @@ -6127,7 +6246,7 @@ /* clear the empty characters in the begining*/ input = ast_skip_blanks(input); /* clear the empty characters in the end */ - while(*end && (*end < 33) && end > input) + while (*end && (*end < 33) && end > input) end--; if (end >= input) { bytes = (int) (end - input) + 2; @@ -6174,7 +6293,6 @@ return 0; } - /*--- check_user: Check if matching user or peer is defined ---*/ static int check_user_full(struct sip_pvt *p, struct sip_request *req, int sipmethod, char *uri, int reliable, struct sockaddr_in *sin, int ignore, char *mailbox, int mailboxlen) { @@ -6191,7 +6309,7 @@ /* Terminate URI */ t = uri; - while(*t && (*t > 32) && (*t != ';')) + while (*t && (*t > 32) && (*t != ';')) t++; *t = '\0'; of = get_header(req, "From"); @@ -6204,7 +6322,7 @@ if (!ast_strlen_zero(rpid)) p->callingpres = get_rpid_num(rpid,rpid_num, sizeof(rpid_num)); - of = ditch_braces(from); + of = ditch_braces(from, 0); if (ast_strlen_zero(p->exten)) { t = uri; if (!strncmp(t, "sip:", 4)) @@ -6252,11 +6370,13 @@ } if (p->rtp) { - ast_log(LOG_DEBUG, "Setting NAT on RTP to %d\n", (ast_test_flag(p, SIP_NAT) & SIP_NAT_ROUTE)); + if (option_debug > 1) + ast_log(LOG_DEBUG, "Setting NAT on RTP to %d\n", (ast_test_flag(p, SIP_NAT) & SIP_NAT_ROUTE)); ast_rtp_setnat(p->rtp, (ast_test_flag(p, SIP_NAT) & SIP_NAT_ROUTE)); } if (p->vrtp) { - ast_log(LOG_DEBUG, "Setting NAT on VRTP to %d\n", (ast_test_flag(p, SIP_NAT) & SIP_NAT_ROUTE)); + if (option_debug > 1) + ast_log(LOG_DEBUG, "Setting NAT on VRTP to %d\n", (ast_test_flag(p, SIP_NAT) & SIP_NAT_ROUTE)); ast_rtp_setnat(p->vrtp, (ast_test_flag(p, SIP_NAT) & SIP_NAT_ROUTE)); } if (!(res = check_auth(p, req, p->randdata, sizeof(p->randdata), user->name, user->secret, user->md5secret, sipmethod, uri, reliable, ignore))) { @@ -6279,6 +6399,7 @@ ast_copy_string(p->cid_name, user->cid_name, sizeof(p->cid_name)); ast_copy_string(p->username, user->name, sizeof(p->username)); ast_copy_string(p->peersecret, user->secret, sizeof(p->peersecret)); + ast_copy_string(p->subscribecontext, user->subscribecontext, sizeof(p->subscribecontext)); ast_copy_string(p->peermd5secret, user->md5secret, sizeof(p->peermd5secret)); ast_copy_string(p->accountcode, user->accountcode, sizeof(p->accountcode)); ast_copy_string(p->language, user->language, sizeof(p->language)); @@ -6341,6 +6462,7 @@ } ast_copy_string(p->peersecret, peer->secret, sizeof(p->peersecret)); p->peersecret[sizeof(p->peersecret)-1] = '\0'; + ast_copy_string(p->subscribecontext, peer->subscribecontext, sizeof(p->subscribecontext)); ast_copy_string(p->peermd5secret, peer->md5secret, sizeof(p->peermd5secret)); p->peermd5secret[sizeof(p->peermd5secret)-1] = '\0'; p->callingpres = peer->callingpres; @@ -6445,18 +6567,31 @@ return 0; } - /*--- receive_message: Receive SIP MESSAGE method messages ---*/ -/* we handle messages within current calls currently */ +/* We only handle messages within current calls currently */ +/* Reference: RFC 3428 */ static void receive_message(struct sip_pvt *p, struct sip_request *req) { char buf[1024]; struct ast_frame f; + char *content_type; + + content_type = get_header(req, "Content-Type"); + + if (strcmp(content_type, "text/plain")) { + /* No text/plain attachment */ + transmit_response(p, "415 unsupported media type", req); /* Good enough or? */ + ast_set_flag(p, SIP_NEEDDESTROY); + return; + } if (get_msg_text(buf, sizeof(buf), req)) { ast_log(LOG_WARNING, "Unable to retrieve text from %s\n", p->callid); + transmit_response(p, "202 Accepted", req); + ast_set_flag(p, SIP_NEEDDESTROY); return; } + if (p->owner) { if (sip_debug_test_pvt(p)) ast_verbose("Message received: '%s'\n", buf); @@ -6467,7 +6602,15 @@ f.data = buf; f.datalen = strlen(buf); ast_queue_frame(p->owner, &f); + transmit_response(p, "202 Accepted", req); + /* We respond 202 accepted, since we relay the message */ + } else { + /* Message outside of a call, we do not support that */ + ast_log(LOG_WARNING,"Received message to %s from %s, dropped it...\n Content-Type:%s\n Message: %s\n", get_header(req,"To"), get_header(req,"From"), content_type, buf); + transmit_response(p, "405 Method not allowed", req); /* Good enough or? */ } + ast_set_flag(p, SIP_NEEDDESTROY); + return; } /*--- sip_show_inuse: CLI Command to show calls within limits set by @@ -6534,7 +6677,7 @@ /*--- nat2str: Convert NAT setting to text string */ static char *nat2str(int nat) { - switch(nat) { + switch (nat) { case SIP_NAT_NEVER: return "No"; case SIP_NAT_ROUTE: @@ -6547,7 +6690,7 @@ return "Unknown"; } } - + /*--- sip_show_users: CLI Command 'SIP Show Users' ---*/ static int sip_show_users(int fd, int argc, char *argv[]) { @@ -6608,12 +6751,12 @@ static int manager_sip_show_peers( struct mansession *s, struct message *m ) { char *id = astman_get_header(m,"ActionID"); - char *a[] = { "sip", "show", "peers" }; + char *a[] = { "sip", "show", "peers" }; char idtext[256] = ""; int total = 0; if (id && !ast_strlen_zero(id)) - snprintf(idtext,256,"ActionID: %s\r\n",id); + snprintf(idtext,256,"ActionID: %s\r\n",id); astman_send_ack(s, m, "Peer status list will follow"); /* List the peers in separate manager events */ @@ -6655,7 +6798,7 @@ if (s) { /* Manager - get ActionID */ id = astman_get_header(m,"ActionID"); if (id && !ast_strlen_zero(id)) - snprintf(idtext,256,"ActionID: %s\r\n",id); + snprintf(idtext,256,"ActionID: %s\r\n",id); } switch (argc) { @@ -6766,11 +6909,10 @@ ASTOBJ_UNLOCK(iterator); total_peers++; - } while(0) ); + } while (0) ); - if (!s) { - ast_cli(fd,"%d sip peers [%d online , %d offline]\n",total_peers,peers_online,peers_offline); - } + if (!s) + ast_cli(fd,"%d sip peer%s [%d online , %d offline]\n", total_peers, (total_peers != 1) ? "s" : "", peers_online, peers_offline); if (havepattern) regfree(®exbuf); @@ -6992,9 +7134,9 @@ static int manager_sip_show_peer( struct mansession *s, struct message *m ) { char *id = astman_get_header(m,"ActionID"); - char *a[4]; + char *a[4]; char *peer; - int ret; + int ret; peer = astman_get_header(m,"Peer"); if (!peer || ast_strlen_zero(peer)) { @@ -7009,14 +7151,12 @@ if (id && !ast_strlen_zero(id)) ast_cli(s->fd, "ActionID: %s\r\n",id); - ret = _sip_show_peer(1, s->fd, s, m, 4, a ); - ast_cli( s->fd, "\r\n\r\n" ); + ret = _sip_show_peer(1, s->fd, s, m, 4, a ); + ast_cli( s->fd, "\r\n\r\n" ); ast_mutex_unlock(&s->lock); - return ret; + return ret; } - - /*--- sip_show_peer: Show one peer in detail ---*/ static int sip_show_peer(int fd, int argc, char *argv[]) { @@ -7055,7 +7195,7 @@ ast_cli(fd, " Secret : %s\n", ast_strlen_zero(peer->secret)?"":""); ast_cli(fd, " MD5Secret : %s\n", ast_strlen_zero(peer->md5secret)?"":""); auth = peer->auth; - while(auth) { + while (auth) { ast_cli(fd, " Realm-auth : Realm %-15.15s User %-10.20s ", auth->realm, auth->username); ast_cli(fd, "%s\n", !ast_strlen_zero(auth->secret)?"":(!ast_strlen_zero(auth->md5secret)?"" : "")); auth = auth->next; @@ -7111,7 +7251,7 @@ ast_cli(fd, "%s\n", codec_buf); ast_cli(fd, " Codec Order : ("); pref = &peer->prefs; - for(x = 0; x < 32 ; x++) { + for (x = 0; x < 32 ; x++) { codec = ast_codec_pref_index(pref,x); if (!codec) break; @@ -7194,7 +7334,7 @@ ast_cli(fd, "%s\r\n", codec_buf); ast_cli(fd, "CodecOrder: "); pref = &peer->prefs; - for(x = 0; x < 32 ; x++) { + for (x = 0; x < 32 ; x++) { codec = ast_codec_pref_index(pref,x); if (!codec) break; @@ -7270,7 +7410,7 @@ ast_cli(fd, " ACL : %s\n", (user->ha?"Yes":"No")); ast_cli(fd, " Codec Order : ("); pref = &user->prefs; - for(x = 0; x < 32 ; x++) { + for (x = 0; x < 32 ; x++) { codec = ast_codec_pref_index(pref,x); if (!codec) break; @@ -7313,7 +7453,7 @@ snprintf(host, sizeof(host), "%s:%d", iterator->hostname, iterator->portno ? iterator->portno : DEFAULT_SIP_PORT); ast_cli(fd, FORMAT, host, iterator->username, iterator->refresh, regstate2str(iterator->regstate)); ASTOBJ_UNLOCK(iterator); - } while(0)); + } while (0)); return RESULT_SUCCESS; #undef FORMAT #undef FORMAT2 @@ -7325,17 +7465,18 @@ /*--- sip_show_channels: Show active SIP channels ---*/ static int sip_show_channels(int fd, int argc, char *argv[]) { - return __sip_show_channels(fd, argc, argv, 0); + return __sip_show_channels(fd, argc, argv, 0); } /*--- sip_show_subscriptions: Show active SIP subscriptions ---*/ static int sip_show_subscriptions(int fd, int argc, char *argv[]) { - return __sip_show_channels(fd, argc, argv, 1); + return __sip_show_channels(fd, argc, argv, 1); } static int __sip_show_channels(int fd, int argc, char *argv[], int subscriptions) { +#define FORMAT4 "%-15.15s %-10.10s %-21.21s %-15.15s %10s\n" #define FORMAT3 "%-15.15s %-10.10s %-21.21s %-15.15s\n" #define FORMAT2 "%-15.15s %-10.10s %-11.11s %-11.11s %s %s\n" #define FORMAT "%-15.15s %-10.10s %-11.11s %5.5d/%5.5d %-6.6s%s %s\n" @@ -7349,7 +7490,7 @@ if (!subscriptions) ast_cli(fd, FORMAT2, "Peer", "User/ANR", "Call ID", "Seq (Tx/Rx)", "Format", "Last Msg"); else - ast_cli(fd, FORMAT3, "Peer", "User", "Call ID", "URI"); + ast_cli(fd, FORMAT4, "Peer", "User", "Call ID", "Extension", "Last state"); while (cur) { if (!cur->subscribed && !subscriptions) { ast_cli(fd, FORMAT, ast_inet_ntoa(iabuf, sizeof(iabuf), cur->sa.sin_addr), @@ -7362,22 +7503,23 @@ numchans++; } if (cur->subscribed && subscriptions) { - ast_cli(fd, FORMAT3, ast_inet_ntoa(iabuf, sizeof(iabuf), cur->sa.sin_addr), - ast_strlen_zero(cur->username) ? ( ast_strlen_zero(cur->cid_num) ? "(None)" : cur->cid_num ) : cur->username, - cur->callid, cur->uri); - - } + ast_cli(fd, FORMAT4, ast_inet_ntoa(iabuf, sizeof(iabuf), cur->sa.sin_addr), + ast_strlen_zero(cur->username) ? ( ast_strlen_zero(cur->cid_num) ? "(None)" : cur->cid_num ) : cur->username, + cur->callid, cur->exten, ast_state2str(cur->laststate)); + numchans++; + } cur = cur->next; } ast_mutex_unlock(&iflock); if (!subscriptions) - ast_cli(fd, "%d active SIP channel(s)\n", numchans); + ast_cli(fd, "%d active SIP channel%s\n", numchans, (numchans != 1) ? "s" : ""); else - ast_cli(fd, "%d active SIP subscriptions(s)\n", numchans); + ast_cli(fd, "%d active SIP subscriptions%s\n", numchans, (numchans != 1) ? "s" : ""); return RESULT_SUCCESS; #undef FORMAT #undef FORMAT2 #undef FORMAT3 +#undef FORMAT4 } /*--- complete_sipch: Support routine for 'sip show channel' CLI ---*/ @@ -7389,7 +7531,7 @@ ast_mutex_lock(&iflock); cur = iflist; - while(cur) { + while (cur) { if (!strncasecmp(word, cur->callid, strlen(word))) { if (++which > state) { c = strdup(cur->callid); @@ -7418,7 +7560,7 @@ result = strdup(iterator->name); } } - } while(0) ); + } while (0) ); return result; } @@ -7456,7 +7598,7 @@ result = strdup(iterator->name); } } - } while(0) ); + } while (0) ); return result; } @@ -7484,7 +7626,7 @@ return NULL; cat = ast_category_browse(notify_types, NULL); - while(cat) { + while (cat) { if (!strncasecmp(word, cat, strlen(word))) { if (++which > state) { c = strdup(cat); @@ -7532,7 +7674,7 @@ len = strlen(argv[3]); ast_mutex_lock(&iflock); cur = iflist; - while(cur) { + while (cur) { if (!strncasecmp(cur->callid, argv[3],len)) { ast_cli(fd,"\n"); if (cur->subscribed) @@ -7543,8 +7685,8 @@ ast_cli(fd, " Call-ID: %s\n", cur->callid); ast_cli(fd, " Our Codec Capability: %d\n", cur->capability); ast_cli(fd, " Non-Codec Capability: %d\n", cur->noncodeccapability); - ast_cli(fd, " Their Codec Capability: %d\n", cur->peercapability); - ast_cli(fd, " Joint Codec Capability: %d\n", cur->jointcapability); + ast_cli(fd, " Their Codec Capability: %d\n", cur->peercapability); + ast_cli(fd, " Joint Codec Capability: %d\n", cur->jointcapability); ast_cli(fd, " Format %s\n", ast_getformatname(cur->owner ? cur->owner->nativeformats : 0) ); ast_cli(fd, " Theoretical Address: %s:%d\n", ast_inet_ntoa(iabuf, sizeof(iabuf), cur->sa.sin_addr), ntohs(cur->sa.sin_port)); ast_cli(fd, " Received Address: %s:%d\n", ast_inet_ntoa(iabuf, sizeof(iabuf), cur->recv.sin_addr), ntohs(cur->recv.sin_port)); @@ -7565,7 +7707,7 @@ ast_cli(fd, " Promiscuous Redir: %s\n", ast_test_flag(cur, SIP_PROMISCREDIR) ? "Yes" : "No"); ast_cli(fd, " Route: %s\n", cur->route ? cur->route->hop : "N/A"); ast_cli(fd, " DTMF Mode: %s\n", dtmfmode2str(ast_test_flag(cur, SIP_DTMF))); - ast_cli(fd, " SIP Options : "); + ast_cli(fd, " SIP Options: "); if (cur->sipoptions) { int x; for (x=0 ; (x < (sizeof(sip_options) / sizeof(sip_options[0]))); x++) { @@ -7601,7 +7743,7 @@ len = strlen(argv[3]); ast_mutex_lock(&iflock); cur = iflist; - while(cur) { + while (cur) { if (!strncasecmp(cur->callid, argv[3],len)) { ast_cli(fd,"\n"); if (cur->subscribed) @@ -7610,7 +7752,7 @@ ast_cli(fd, " * SIP Call\n"); x = 0; hist = cur->history; - while(hist) { + while (hist) { x++; ast_cli(fd, "%d. %s\n", x, hist->event); hist = hist->next; @@ -7627,7 +7769,6 @@ return RESULT_SUCCESS; } - /*--- receive_info: Receive SIP INFO Message ---*/ /* Doesn't read the duration of the DTMF signal */ static void receive_info(struct sip_pvt *p, struct sip_request *req) @@ -7640,7 +7781,7 @@ /* Need to check the media/type */ if (!strcasecmp(get_header(req, "Content-Type"), "application/dtmf-relay") || - !strcasecmp(get_header(req, "Content-Type"), "application/vnd.nortelnetworks.digits")) { + !strcasecmp(get_header(req, "Content-Type"), "application/vnd.nortelnetworks.digits")) { /* Try getting the "signal=" part */ if (ast_strlen_zero(c = get_sdp(req, "Signal")) && ast_strlen_zero(c = get_sdp(req, "d"))) { @@ -7990,7 +8131,7 @@ and users (for calls). Also used for authentication of CANCEL and BYE */ static int build_reply_digest(struct sip_pvt *p, int method, char* digest, int digest_len) { - char a1[256]; + char a1[256]; char a2[256]; char a1_hash[256]; char a2_hash[256]; @@ -8031,9 +8172,9 @@ snprintf(a1,sizeof(a1),"%s:%s:%s",username,p->realm,secret); snprintf(a2,sizeof(a2),"%s:%s", sip_methods[method].text, uri); if (!ast_strlen_zero(md5secret)) - ast_copy_string(a1_hash, md5secret, sizeof(a1_hash)); + ast_copy_string(a1_hash, md5secret, sizeof(a1_hash)); else - ast_md5_hash(a1_hash,a1); + ast_md5_hash(a1_hash,a1); ast_md5_hash(a2_hash,a2); /* XXX We hard code the nonce-number to 1... What are the odds? Are we seriously going to keep track of every nonce we've seen? Also we hard code to "auth"... XXX */ @@ -8184,7 +8325,7 @@ char tmp[256] = ""; char *s, *e; ast_copy_string(tmp, get_header(req, "Contact"), sizeof(tmp)); - s = ditch_braces(tmp); + s = ditch_braces(tmp, 0); e = strchr(s, ';'); if (e) *e = '\0'; @@ -8301,11 +8442,11 @@ char *contact = NULL; char *tmptmp = NULL; int start = 0; - for(;;) { + for (;;) { contact = __get_header(req, "Contact", &start); /* this loop ensures we get a contact header about our register request */ - if(!ast_strlen_zero(contact)) { - if( (tmptmp=strstr(contact, p->our_contact))) { + if (!ast_strlen_zero(contact)) { + if ((tmptmp=strstr(contact, p->our_contact))) { contact=tmptmp; break; } @@ -8369,7 +8510,7 @@ } } if (!peer->lastms) - statechanged = 1; + statechanged = 1; peer->lastms = pingtime; peer->call = NULL; if (statechanged) { @@ -8450,21 +8591,18 @@ ast_sched_del(sched, p->initid); p->initid = -1; } - switch(resp) { + switch (resp) { case 100: /* 100 Trying */ - if (sipmethod == SIP_INVITE) { + if (sipmethod == SIP_INVITE) sip_cancel_destroy(p); - } break; case 183: /* 183 Session Progress */ if (sipmethod == SIP_INVITE) { sip_cancel_destroy(p); if (!ast_strlen_zero(get_header(req, "Content-Type"))) process_sdp(p, req); - if (p->owner) { - /* Queue a progress frame */ + if (p->owner) /* Queue a progress frame */ ast_queue_control(p->owner, AST_CONTROL_PROGRESS); - } } break; case 180: /* 180 Ringing */ @@ -8484,9 +8622,8 @@ ast_log(LOG_WARNING, "Notify answer on an owned channel?\n"); ast_queue_hangup(p->owner); } else { - if (!p->subscribed) { - ast_set_flag(p, SIP_NEEDDESTROY); - } + if (!p->subscribed) + ast_set_flag(p, SIP_NEEDDESTROY); } } else if (sipmethod == SIP_INVITE) { /* 200 OK on invite - someone's answering our call */ @@ -8607,7 +8744,7 @@ ast_rtp_stop(p->vrtp); } /* XXX Locking issues?? XXX */ - switch(resp) { + switch (resp) { case 300: /* Multiple Choices */ case 301: /* Moved permenantly */ case 302: /* Moved temporarily */ @@ -8682,7 +8819,7 @@ } if (sip_debug_test_pvt(p)) ast_verbose("Response message is %s\n", msg); - switch(resp) { + switch (resp) { case 200: /* Change branch since this is a 200 response */ if (sipmethod == SIP_INVITE) @@ -8854,6 +8991,7 @@ } peerc->cdr = NULL; + ast_log(LOG_DEBUG, "XXXX Trying to masquerade %s and %s\n", peerb->name, peerc->name); if (ast_channel_masquerade(peerb, peerc)) { ast_log(LOG_WARNING, "Failed to masquerade %s into %s\n", peerb->name, peerc->name); res = -1; @@ -8897,14 +9035,14 @@ /*--- handle_request_invite: Handle incoming INVITE request */ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int debug, int ignore, int seqno, struct sockaddr_in *sin, int *recount, char *e) { - int res = 1; - struct ast_channel *c=NULL; - int gotdest; - struct ast_frame af = { AST_FRAME_NULL, }; - char *supported; - char *required; + int res = 1, gotdest = 0; + struct ast_channel *c = NULL; + struct ast_frame af = { AST_FRAME_NULL, }, *f = NULL; + char *supported = NULL, *required = NULL; unsigned int required_profile = 0; - + char *ptr, *p_replaces = NULL, *replace_id = NULL; + struct sip_pvt *refer_pvt = NULL; + /* Find out what they support */ if (!p->sipoptions) { supported = get_header(req, "Supported"); @@ -8919,10 +9057,23 @@ transmit_response_with_unsupported(p, "420 Bad extension", req, required); ast_set_flag(p, SIP_NEEDDESTROY); return -1; - } } + if ((p_replaces = get_header(req, "Replaces"))) { + if (ast_strlen_zero(p_replaces)) { + p_replaces = NULL; + } else { + if (debug) + ast_log(LOG_DEBUG, "Found a Replaces header %s\n", get_header(req, "Replaces")); + replace_id = ast_strdupa(p_replaces); + if (strchr(replace_id, '%')) + sip_unescape_uri(replace_id); + if ((ptr = strchr(replace_id, ';'))) + *ptr = '\0'; + } + } + /* Check if this is a loop */ /* This happens since we do not properly support SIP domain handling yet... -oej */ @@ -8974,6 +9125,7 @@ } return 0; } + /* Process the SDP portion */ if (!ast_strlen_zero(get_header(req, "Content-Type"))) { if (process_sdp(p, req)) { @@ -8992,7 +9144,8 @@ if (ast_strlen_zero(p->context)) strcpy(p->context, default_context); /* Check number of concurrent calls -vs- incoming limit HERE */ - ast_log(LOG_DEBUG, "Checking SIP call limits for device %s\n", p->username); + if (option_debug > 1) + ast_log(LOG_DEBUG, "Checking SIP call limits for device %s\n", p->username); res = update_user_counter(p, INC_IN_USE); if (res) { if (res < 0) { @@ -9011,7 +9164,7 @@ extract_uri(p, req); build_contact(p); - if (gotdest) { + if (!replace_id && gotdest) { if (gotdest < 0) { if (ignore) transmit_response(p, "404 Not Found", req); @@ -9038,20 +9191,40 @@ /* Save Record-Route for any later requests we make on this dialogue */ build_route(p, req, 0); if (c) { + if (replace_id) { + if ((refer_pvt = get_sip_pvt_byid_locked(replace_id, req, NULL, p->theirtag))) { + transmit_response(p, "100 Trying", req); + ast_mutex_unlock(&refer_pvt->owner->lock); + ast_mutex_unlock(&refer_pvt->lock); + ast_channel_masquerade(refer_pvt->owner, c ); + ast_hangup(c); + c = refer_pvt->owner; + if ((f = ast_read(c))) { + if (option_debug > 1) + ast_log(LOG_DEBUG, "SIP Call Replacement (pickup) successful for CallID: %s\n", p_replaces); + ast_frfree(f); + ast_setstate(c, AST_STATE_UP); + } else + ast_log(LOG_WARNING, "SIP Call Replacement (pickup) not successful for CallID: %s\n", p_replaces); + } else { + transmit_response_with_allow(p, "481 Call/Transaction Does Not Exist", req, 0); + return 0; + } + } /* Pre-lock the call */ ast_mutex_lock(&c->lock); } } - } else { if (option_debug > 1 && sipdebug) ast_log(LOG_DEBUG, "Got a SIP re-invite for call %s\n", p->callid); c = p->owner; } + if (!ignore && p) p->lastinvite = seqno; if (c) { - switch(c->_state) { + switch (c->_state) { case AST_STATE_DOWN: transmit_response(p, "100 Trying", req); ast_setstate(c, AST_STATE_RING); @@ -9274,16 +9447,12 @@ /*--- handle_request_message: Handle incoming MESSAGE request ---*/ static int handle_request_message(struct sip_pvt *p, struct sip_request *req, int debug, int ignore) { - if (p->lastinvite) { - if (!ignore) { - if (debug) - ast_verbose("Receiving message!\n"); - receive_message(p, req); - } - transmit_response(p, "200 OK", req); + if (!ignore) { + if (debug) + ast_verbose("Receiving message!\n"); + receive_message(p, req); } else { - transmit_response(p, "405 Method Not Allowed", req); - ast_set_flag(p, SIP_NEEDDESTROY); + transmit_response(p, "202 Accepted", req); } return 1; } @@ -9319,7 +9488,9 @@ return 0; } /* Initialize the context if it hasn't been already */ - if (ast_strlen_zero(p->context)) + if (p->subscribecontext && !ast_strlen_zero(p->subscribecontext)) + ast_copy_string(p->context, p->subscribecontext, sizeof(p->context)); + else if (ast_strlen_zero(p->context)) strcpy(p->context, default_context); /* Get destination right away */ gotdest = get_destination(p, NULL); @@ -9328,15 +9499,34 @@ if (gotdest < 0) transmit_response(p, "404 Not Found", req); else - transmit_response(p, "484 Address Incomplete", req); + transmit_response(p, "484 Address Incomplete", req); /* Overlap dialing on SUBSCRIBE?? */ ast_set_flag(p, SIP_NEEDDESTROY); } else { + char *event = get_header(req, "Event"); /* Get Event package name */ + char *accept = get_header(req, "Accept"); + /* Initialize tag */ p->tag = rand(); - if (!strcmp(get_header(req, "Accept"), "application/dialog-info+xml")) - p->subscribed = 2; - else if (!strcmp(get_header(req, "Accept"), "application/simple-message-summary")) { - /* Looks like they actually want a mailbox */ + if (!strcmp(event, "presence") || !strcmp(event, "dialog")) { /* Presence, RFC 3842 */ + /* Header from Xten Eye-beam Accept: multipart/related, application/rlmi+xml, application/pidf+xml, application/xpidf+xml */ + if (strstr(accept, "application/dialog-info+xml")) + p->subscribed = SUBSCRIBE_DIALOG_INFO_XML; + /* IETF draft: draft-ietf-sipping-dialog-package-05.txt */ + /* Should not be used for SUBSCRIBE, but anyway */ + else if (!p->subscribed && strstr(accept, "application/cpim-pidf+xml")) + p->subscribed = SUBSCRIBE_CPIM_PIDF_XML; /* RFC 3863 format */ + else if (!p->subscribed && strstr(accept, "application/pidf+xml")) + p->subscribed = SUBSCRIBE_PIDF_XML; /* RFC 3863 format */ + else if (!p->subscribed && strstr(accept, "application/xpidf+xml")) + p->subscribed = SUBSCRIBE_XPIDF_XML; /* Early pre-RFC 3863 format with MSN additions (Microsoft Messenger) */ + else { + /* Can't find a format for events that we know about */ + transmit_response(p, "489 Bad Event", req); + ast_set_flag(p, SIP_NEEDDESTROY); + return 0; + } + } else if (!strcmp(event, "message-summary") && !strcmp(accept, "application/simple-message-summary")) { + /* Looks like they actually want a mailbox status */ /* At this point, we should check if they subscribe to a mailbox that has the same extension as the peer or the mailbox id. If we configure @@ -9347,12 +9537,10 @@ Since we do not act on this subscribe anyway, we might as well accept any authenticated peer with a mailbox definition in their - config section. - - */ - if (!ast_strlen_zero(mailbox)) { + config section. */ + + if (!ast_strlen_zero(mailbox)) found++; - } if (found){ transmit_response(p, "200 OK", req); @@ -9362,8 +9550,14 @@ ast_set_flag(p, SIP_NEEDDESTROY); } return 0; - } else - p->subscribed = 1; + } else { + /* At this point, Asterisk does not understand the specified event */ + transmit_response(p, "489 Bad Event", req); + if (option_debug > 1) + ast_log(LOG_DEBUG, "Received SIP subscribe for unknown event package: %s\n", event); + ast_set_flag(p, SIP_NEEDDESTROY); + return 0; + } if (p->subscribed) p->stateid = ast_extension_state_add(p->context, p->exten, cb_extensionstate, p); } @@ -9379,10 +9573,10 @@ return 0; } /* The next line can be removed if the SNOM200 Expires bug is fixed */ - if (p->subscribed == 1) { + /* if (p->subscribed != 0) { if (p->expiry>max_expiry) p->expiry = max_expiry; - } + } */ /* Go ahead and free RTP port */ if (p->rtp) { if (p->owner) { @@ -9400,8 +9594,12 @@ ast_rtp_destroy(p->vrtp); p->vrtp = NULL; } + if (sipdebug || option_debug > 1) + ast_log(LOG_DEBUG, "Adding subscription for extension %s context %s for peer %s\n", p->exten, p->context, p->username); transmit_response(p, "200 OK", req); + /* Set timer for destruction of call at expiration */ sip_scheddestroy(p, (p->expiry+10)*1000); + /* Send first notification */ transmit_state_notify(p, ast_extension_state(NULL, p->context, p->exten),1); } return 1; @@ -9739,7 +9937,7 @@ build_callid(p->callid, sizeof(p->callid), p->ourip, p->fromdomain); /* Send MWI */ ast_set_flag(p, SIP_OUTGOING); - transmit_notify_with_mwi(p, newmsgs, oldmsgs); + transmit_notify_with_mwi(p, newmsgs, oldmsgs, peer->vmexten); sip_scheddestroy(p, 15000); return 0; } @@ -9763,7 +9961,7 @@ /* This thread monitors all the frame relay interfaces which are not yet in use (and thus do not have a separate thread) indefinitely */ /* From here on out, we die whenever asked */ - for(;;) { + for (;;) { /* Check for a reload request */ ast_mutex_lock(&sip_reload_lock); reloading = sip_reloading; @@ -9779,7 +9977,7 @@ restartsearch: time(&t); sip = iflist; - while(sip) { + while (sip) { ast_mutex_lock(&sip->lock); if (sip->rtp && sip->owner && (sip->owner->_state == AST_STATE_UP) && !sip->redirip.sin_addr.s_addr) { if (sip->lastrtptx && sip->rtpkeepalive && t > sip->lastrtptx + sip->rtpkeepalive) { @@ -9796,7 +9994,7 @@ (t > sip->lastrtprx + sip->rtpholdtimeout))) { /* Needs a hangup */ if (sip->rtptimeout) { - while(sip->owner && ast_mutex_trylock(&sip->owner->lock)) { + while (sip->owner && ast_mutex_trylock(&sip->owner->lock)) { ast_mutex_unlock(&sip->lock); usleep(1); ast_mutex_lock(&sip->lock); @@ -10014,13 +10212,35 @@ if (p) { found++; res = AST_DEVICE_UNAVAILABLE; + if (option_debug > 2) + ast_log(LOG_DEBUG, "Checking device state for peer %s\n", dest); if ((p->addr.sin_addr.s_addr || p->defaddr.sin_addr.s_addr) && (!p->maxms || ((p->lastms > -1) && (p->lastms <= p->maxms)))) { - /* peer found and valid */ - res = AST_DEVICE_UNKNOWN; + /* Peer is registred, or have default IP address + and a valid registration */ + + + /* Now check if we know anything about the state. The only way is by implementing + call control with incominglimit=X in sip.conf where X > 0 + Check if the device has incominglimit, and if qualify=on, if the device + is reachable + */ + if (p->incominglimit && (p->lastms == 0 || p->lastms <= p->maxms)) { + /* Free for a call */ + res = AST_DEVICE_NOT_INUSE; + + if (p->inUse) { /* On a call */ + res = AST_DEVICE_BUSY; + } + } else { + /* peer found and valid, state unknown */ + res = AST_DEVICE_UNKNOWN; + } } } if (!p && !found) { + if (option_debug > 2) + ast_log(LOG_DEBUG, "Checking device state for DNS host %s\n", dest); hp = ast_gethostbyname(host, &ahp); if (hp) res = AST_DEVICE_UNKNOWN; @@ -10096,9 +10316,6 @@ ast_copy_string(p->username, ext, sizeof(p->username)); p->fullcontact[0] = 0; } -#if 0 - printf("Setting up to call extension '%s' at '%s'\n", ext ? ext : "", host); -#endif p->prefcodec = format; ast_mutex_lock(&p->lock); tmpc = sip_new(p, AST_STATE_DOWN, host); /* Place the call */ @@ -10187,10 +10404,10 @@ #ifdef OSP_SUPPORT if (!strcasecmp(v->value, "osp")) global_allowguest = 2; - else + else #endif - if (ast_true(v->value)) - global_allowguest = 1; + if (ast_true(v->value)) + global_allowguest = 1; else global_allowguest = 0; #ifdef OSP_SUPPORT @@ -10214,58 +10431,58 @@ /*--- add_realm_authentication: Add realm authentication in list ---*/ static struct sip_auth *add_realm_authentication(struct sip_auth *authlist, char *configuration, int lineno) { - char authcopy[256] = ""; - char *username=NULL, *realm=NULL, *secret=NULL, *md5secret=NULL; + char authcopy[256] = ""; + char *username=NULL, *realm=NULL, *secret=NULL, *md5secret=NULL; char *stringp; struct sip_auth *auth; struct sip_auth *b = NULL, *a = authlist; - - if (!configuration || ast_strlen_zero(configuration)) - return (authlist); + + if (!configuration || ast_strlen_zero(configuration)) + return (authlist); ast_log(LOG_DEBUG, "Auth config :: %s\n", configuration); - ast_copy_string(authcopy, configuration, sizeof(authcopy)); - stringp = authcopy; + ast_copy_string(authcopy, configuration, sizeof(authcopy)); + stringp = authcopy; - username = stringp; - realm = strrchr(stringp, '@'); - if (realm) { - *realm = '\0'; - realm++; - } - if (!username || ast_strlen_zero(username) || !realm || ast_strlen_zero(realm)) { - ast_log(LOG_WARNING, "Format for authentication entry is user[:secret]@realm at line %d\n", lineno); - return (authlist); - } - stringp = username; - username = strsep(&stringp, ":"); - if (username) { - secret = strsep(&stringp, ":"); + username = stringp; + realm = strrchr(stringp, '@'); + if (realm) { + *realm = '\0'; + realm++; + } + if (!username || ast_strlen_zero(username) || !realm || ast_strlen_zero(realm)) { + ast_log(LOG_WARNING, "Format for authentication entry is user[:secret]@realm at line %d\n", lineno); + return (authlist); + } + stringp = username; + username = strsep(&stringp, ":"); + if (username) { + secret = strsep(&stringp, ":"); if (!secret) { - stringp = username; + stringp = username; md5secret = strsep(&stringp,"#"); } - } + } auth = malloc(sizeof(struct sip_auth)); - if (auth) { - memset(auth, 0, sizeof(struct sip_auth)); + if (auth) { + memset(auth, 0, sizeof(struct sip_auth)); ast_copy_string(auth->realm, realm, sizeof(auth->realm)); ast_copy_string(auth->username, username, sizeof(auth->username)); if (secret) ast_copy_string(auth->secret, secret, sizeof(auth->secret)); if (md5secret) ast_copy_string(auth->md5secret, md5secret, sizeof(auth->md5secret)); - } else { - ast_log(LOG_ERROR, "Allocation of auth structure failed, Out of memory\n"); - return (authlist); - } + } else { + ast_log(LOG_ERROR, "Allocation of auth structure failed, Out of memory\n"); + return (authlist); + } /* Add authentication to authl */ if (!authlist) { /* No existing list */ return(auth); } - while(a) { + while (a) { b = a; a = a->next; } @@ -10274,8 +10491,7 @@ if (option_verbose > 2) ast_verbose("Added authentication for realm %s\n", realm); - return(authlist); - + return(authlist); } /*--- clear_realm_authentication: Clear realm authentication list (at reload) ---*/ @@ -10284,11 +10500,11 @@ struct sip_auth *a = authlist; struct sip_auth *b; - while (a) { - b = a; - a = a->next; - free(b); - } + while (a) { + b = a; + a = a->next; + free(b); + } return(1); } @@ -10299,12 +10515,11 @@ struct sip_auth *a = authlist; /* First entry in auth list */ while (a) { - if (!strcasecmp(a->realm, realm)){ + if (!strcasecmp(a->realm, realm)) break; - } a = a->next; } - + return(a); } @@ -10321,9 +10536,9 @@ user = (struct sip_user *)malloc(sizeof(struct sip_user)); - if (!user) { + if (!user) return NULL; - } + memset(user, 0, sizeof(struct sip_user)); suserobjs++; ASTOBJ_INIT(user); @@ -10334,15 +10549,15 @@ user->inUse = 0; user->outUse = 0; ast_copy_flags(user, &global_flags, - SIP_PROMISCREDIR | SIP_TRUSTRPID | SIP_USECLIENTCODE | SIP_DTMF | SIP_NAT | - SIP_REINVITE | SIP_INSECURE_PORT | SIP_INSECURE_INVITE | SIP_PROG_INBAND | SIP_OSPAUTH); + SIP_PROMISCREDIR | SIP_TRUSTRPID | SIP_USECLIENTCODE | SIP_DTMF | SIP_NAT | + SIP_REINVITE | SIP_INSECURE_PORT | SIP_INSECURE_INVITE | SIP_PROG_INBAND | SIP_OSPAUTH); user->capability = global_capability; user->prefs = prefs; /* set default context */ strcpy(user->context, default_context); strcpy(user->language, default_language); strcpy(user->musicclass, global_musicclass); - while(v) { + while (v) { if (handle_common_options(&userflags, &mask, v)) { v = v->next; continue; @@ -10350,6 +10565,8 @@ if (!strcasecmp(v->name, "context")) { ast_copy_string(user->context, v->value, sizeof(user->context)); + } else if (!strcasecmp(v->name, "subscribecontext")) { + ast_copy_string(user->subscribecontext, v->value, sizeof(user->subscribecontext)); } else if (!strcasecmp(v->name, "setvar")) { varname = ast_strdupa(v->value); if (varname && (varval = strchr(varname,'='))) { @@ -10430,10 +10647,11 @@ peer->pokeexpire = -1; ast_copy_string(peer->name, name, sizeof(peer->name)); ast_copy_flags(peer, &global_flags, - SIP_PROMISCREDIR | SIP_USEREQPHONE | SIP_TRUSTRPID | SIP_USECLIENTCODE | - SIP_DTMF | SIP_NAT | SIP_REINVITE | SIP_INSECURE_PORT | SIP_INSECURE_INVITE | - SIP_PROG_INBAND | SIP_OSPAUTH); + SIP_PROMISCREDIR | SIP_USEREQPHONE | SIP_TRUSTRPID | SIP_USECLIENTCODE | + SIP_DTMF | SIP_NAT | SIP_REINVITE | SIP_INSECURE_PORT | SIP_INSECURE_INVITE | + SIP_PROG_INBAND | SIP_OSPAUTH); strcpy(peer->context, default_context); + strcpy(peer->subscribecontext, default_subscribecontext); strcpy(peer->language, default_language); strcpy(peer->musicclass, global_musicclass); peer->addr.sin_port = htons(DEFAULT_SIP_PORT); @@ -10475,9 +10693,9 @@ /* Already in the list, remove it and it will be added back (or FREE'd) */ found++; } else { - peer = malloc(sizeof(struct sip_peer)); + peer = malloc(sizeof(*peer)); if (peer) { - memset(peer, 0, sizeof(struct sip_peer)); + memset(peer, 0, sizeof(*peer)); if (realtime) rpeerobjs++; else @@ -10508,6 +10726,8 @@ peer->chanvars = NULL; } strcpy(peer->context, default_context); + strcpy(peer->subscribecontext, default_subscribecontext); + strcpy(peer->vmexten, global_vmexten); strcpy(peer->language, default_language); strcpy(peer->musicclass, global_musicclass); ast_copy_flags(peer, &global_flags, SIP_USEREQPHONE); @@ -10528,13 +10748,13 @@ peer->ha = NULL; peer->addr.sin_family = AF_INET; ast_copy_flags(peer, &global_flags, - SIP_PROMISCREDIR | SIP_TRUSTRPID | SIP_USECLIENTCODE | - SIP_DTMF | SIP_REINVITE | SIP_INSECURE_PORT | SIP_INSECURE_INVITE | - SIP_PROG_INBAND | SIP_OSPAUTH); + SIP_PROMISCREDIR | SIP_TRUSTRPID | SIP_USECLIENTCODE | + SIP_DTMF | SIP_REINVITE | SIP_INSECURE_PORT | SIP_INSECURE_INVITE | + SIP_PROG_INBAND | SIP_OSPAUTH); peer->capability = global_capability; peer->rtptimeout = global_rtptimeout; peer->rtpholdtimeout = global_rtpholdtimeout; - while(v) { + while (v) { if (handle_common_options(&peerflags, &mask, v)) { v = v->next; continue; @@ -10543,9 +10763,9 @@ if (realtime && !strcasecmp(v->name, "regseconds")) { if (sscanf(v->value, "%li", ®seconds) != 1) regseconds = 0; - } else if (realtime && !strcasecmp(v->name, "ipaddr") && !ast_strlen_zero(v->value) ) { + } else if (realtime && !strcasecmp(v->name, "ipaddr") && !ast_strlen_zero(v->value) ) inet_aton(v->value, &(peer->addr.sin_addr)); - } else if (realtime && !strcasecmp(v->name, "name")) + else if (realtime && !strcasecmp(v->name, "name")) ast_copy_string(peer->name, v->value, sizeof(peer->name)); else if (!strcasecmp(v->name, "secret")) ast_copy_string(peer->secret, v->value, sizeof(peer->secret)); @@ -10553,11 +10773,13 @@ ast_copy_string(peer->md5secret, v->value, sizeof(peer->md5secret)); else if (!strcasecmp(v->name, "auth")) peer->auth = add_realm_authentication(peer->auth, v->value, v->lineno); - else if (!strcasecmp(v->name, "callerid")) { + else if (!strcasecmp(v->name, "callerid")) ast_callerid_split(v->value, peer->cid_name, sizeof(peer->cid_name), peer->cid_num, sizeof(peer->cid_num)); - } else if (!strcasecmp(v->name, "context")) { + else if (!strcasecmp(v->name, "context")) ast_copy_string(peer->context, v->value, sizeof(peer->context)); - } else if (!strcasecmp(v->name, "fromdomain")) + else if (!strcasecmp(v->name, "subscribecontext")) + ast_copy_string(peer->subscribecontext, v->value, sizeof(peer->subscribecontext)); + else if (!strcasecmp(v->name, "fromdomain")) ast_copy_string(peer->fromdomain, v->value, sizeof(peer->fromdomain)); else if (!strcasecmp(v->name, "usereqphone")) ast_set2_flag(peer, ast_true(v->value), SIP_USEREQPHONE); @@ -10646,6 +10868,8 @@ ast_copy_string(peer->musicclass, v->value, sizeof(peer->musicclass)); } else if (!strcasecmp(v->name, "mailbox")) { ast_copy_string(peer->mailbox, v->value, sizeof(peer->mailbox)); + } else if (!strcasecmp(v->name, "vmexten")) { + ast_copy_string(peer->vmexten, v->value, sizeof(peer->vmexten)); } else if (!strcasecmp(v->name, "callgroup")) { peer->callgroup = ast_get_group(v->value); } else if (!strcasecmp(v->name, "pickupgroup")) { @@ -10750,6 +10974,7 @@ /* Initialize some reasonable defaults at SIP reload */ ast_copy_string(default_context, DEFAULT_CONTEXT, sizeof(default_context)); + default_subscribecontext[0] = '\0'; default_language[0] = '\0'; default_fromdomain[0] = '\0'; default_qualify = 0; @@ -10759,6 +10984,7 @@ sipdebug = 0; ast_copy_string(default_useragent, DEFAULT_USERAGENT, sizeof(default_useragent)); ast_copy_string(default_notifymime, DEFAULT_NOTIFYMIME, sizeof(default_notifymime)); + global_notifyringing = 1; ast_copy_string(global_realm, DEFAULT_REALM, sizeof(global_realm)); ast_copy_string(global_musicclass, "default", sizeof(global_musicclass)); ast_copy_string(default_callerid, DEFAULT_CALLERID, sizeof(default_callerid)); @@ -10781,6 +11007,7 @@ ast_set_flag(&global_flags, SIP_NAT_RFC3581); ast_set_flag(&global_flags, SIP_CAN_REINVITE); global_mwitime = DEFAULT_MWITIME; + ast_copy_string(global_vmexten, DEFAULT_VMEXTEN, sizeof(global_vmexten)); srvlookup = 0; autocreatepeer = 0; regcontext[0] = '\0'; @@ -10790,7 +11017,7 @@ /* Read the [general] config section of sip.conf (or from realtime config) */ v = ast_variable_browse(cfg, "general"); - while(v) { + while (v) { if (handle_common_options(&global_flags, &dummy, v)) { v = v->next; continue; @@ -10827,6 +11054,8 @@ ast_log(LOG_WARNING, "'%s' is not a valid MWI time setting at line %d. Using default (10).\n", v->value, v->lineno); global_mwitime = DEFAULT_MWITIME; } + } else if (!strcasecmp(v->name, "vmexten")) { + ast_copy_string(global_vmexten, v->value, sizeof(global_vmexten)); } else if (!strcasecmp(v->name, "rtptimeout")) { if ((sscanf(v->value, "%d", &global_rtptimeout) != 1) || (global_rtptimeout < 0)) { ast_log(LOG_WARNING, "'%s' is not a valid RTP hold time at line %d. Using default.\n", v->value, v->lineno); @@ -10848,6 +11077,8 @@ compactheaders = ast_true(v->value); } else if (!strcasecmp(v->name, "notifymimetype")) { ast_copy_string(default_notifymime, v->value, sizeof(default_notifymime)); + } else if (!strcasecmp(v->name, "notifyringing")) { + global_notifyringing = ast_true(v->value); } else if (!strcasecmp(v->name, "musicclass") || !strcasecmp(v->name, "musiconhold")) { ast_copy_string(global_musicclass, v->value, sizeof(global_musicclass)); } else if (!strcasecmp(v->name, "language")) { @@ -10971,7 +11202,7 @@ /* Build list of authentication to various SIP realms, i.e. service providers */ v = ast_variable_browse(cfg, "authentication"); - while(v) { + while (v) { /* Format for authentication is auth = username:password@realm */ if (!strcasecmp(v->name, "auth")) { authl = add_realm_authentication(authl, v->value, v->lineno); @@ -10981,7 +11212,7 @@ /* Load peers, users and friends */ cat = ast_category_browse(cfg, NULL); - while(cat) { + while (cat) { if (strcasecmp(cat, "general") && strcasecmp(cat, "authentication")) { utype = ast_variable_retrieve(cfg, cat, "type"); if (utype) { @@ -11213,12 +11444,12 @@ ast_log(LOG_WARNING, "This application requires the argument: Header\n"); return 0; } - ast_mutex_lock(&chan->lock); - if (chan->type != channeltype) { - ast_log(LOG_WARNING, "Call this application only on incoming SIP calls\n"); - ast_mutex_unlock(&chan->lock); - return 0; - } + ast_mutex_lock(&chan->lock); + if (chan->type != channeltype) { + ast_log(LOG_WARNING, "Call this application only on incoming SIP calls\n"); + ast_mutex_unlock(&chan->lock); + return 0; + } /* Check for headers */ while (!ok && no <= 50) { @@ -11233,10 +11464,10 @@ pbx_builtin_setvar_helper (chan, varbuf, data); if (sipdebug) ast_log(LOG_DEBUG,"SIP Header added \"%s\" as %s\n", (char *) data, varbuf); - } else { - ast_log(LOG_WARNING, "Too many SIP headers added, max 50\n"); - } - ast_mutex_unlock(&chan->lock); + } else + ast_log(LOG_WARNING, "Too many SIP headers added, max 50\n"); + + ast_mutex_unlock(&chan->lock); return 0; } @@ -11450,7 +11681,6 @@ return sip_reload(0, 0, NULL); } -// static struct ast_cli_entry cli_sip_reload = static struct ast_cli_entry my_clis[] = { { { "sip", "notify", NULL }, sip_notify, "Send a notify packet to a SIP peer", notify_usage, complete_sipnotify }, { { "sip", "show", "objects", NULL }, sip_show_objects, "Show all SIP object allocations", show_objects_usage }, @@ -11511,9 +11741,9 @@ ast_register_application(app_sipgetheader, sip_getheader, synopsis_sipgetheader, descrip_sipgetheader); ast_manager_register2("SIPpeers", EVENT_FLAG_SYSTEM, manager_sip_show_peers, - "List SIP peers (text format)", mandescr_show_peers); + "List SIP peers (text format)", mandescr_show_peers); ast_manager_register2("SIPshowpeer", EVENT_FLAG_SYSTEM, manager_sip_show_peer, - "Show SIP peer (text format)", mandescr_show_peer); + "Show SIP peer (text format)", mandescr_show_peer); ast_custom_function_register(&sip_header_function); Index: configs/sip.conf.sample =================================================================== RCS file: /usr/cvsroot/asterisk/configs/sip.conf.sample,v retrieving revision 1.64 diff -u -r1.64 sip.conf.sample --- configs/sip.conf.sample 9 Jun 2005 21:11:30 -0000 1.64 +++ configs/sip.conf.sample 15 Jul 2005 15:35:00 -0000 @@ -48,7 +48,13 @@ ;maxexpirey=3600 ; Max length of incoming registration we allow ;defaultexpirey=120 ; Default length of incoming/outoing registration ;notifymimetype=text/plain ; Allow overriding of mime type in MWI NOTIFY +;notifyringing=no ; Sent ringing (yes) or inuse (no) as state in + ; NOTIFY messages when observed extension is + ; in state RINGING_AND_INUSE (defaults to "yes") ;checkmwi=10 ; Default time between mailbox checks for peers +;vmexten=voicemail ; dialplan extension to reach mailbox sets the + ; Message-Account in the MWI notify message + ; defaults to "asterisk" ;videosupport=yes ; Turn on support for SIP video ;recordhistory=yes ; Record SIP history by default ; (see sip history / sip no history) @@ -318,6 +324,9 @@ ;defaultip=192.168.0.59 ; IP used until peer registers ;username=snom ; Username to use in INVITE until peer registers ;mailbox=1234@context,2345 ; Mailbox(-es) for message waiting indicator +;vmexten=voicemail ; dialplan extension to reach mailbox + ; sets the Message-Account in the MWI notify message + ; defaults to global vmexten which defaults to "asterisk" ;restrictcid=yes ; To have the callerid restriced -> sent as ANI ;disallow=all ;allow=ulaw ; dtmfmode=inband only works with ulaw or alaw! Index: include/asterisk/pbx.h =================================================================== RCS file: /usr/cvsroot/asterisk/include/asterisk/pbx.h,v retrieving revision 1.48 diff -u -r1.48 pbx.h --- include/asterisk/pbx.h 8 Jul 2005 21:14:34 -0000 1.48 +++ include/asterisk/pbx.h 15 Jul 2005 15:35:07 -0000 @@ -42,6 +42,10 @@ #define AST_EXTENSION_BUSY 2 /*! All devices UNAVAILABLE/UNREGISTERED */ #define AST_EXTENSION_UNAVAILABLE 3 +/*! One or more devices are RINGING and none are INUSE */ +#define AST_EXTENSION_RINGING 4 +/*! One or more devices are RINGING and one or more are INUSE */ +#define AST_EXTENSION_RINGING_AND_INUSE 5 struct ast_context; struct ast_exten;