/*
    Copyright (C) 2005-2007  Michel de Boer <michel@twinklephone.com>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

#ifndef _PROTOCOL_H
#define _PROTOCOL_H

#include "twinkle_config.h"
#include "parser/hdr_supported.h"

#define CRLF		"\r\n"

// Name and version of the softphone
#define PRODUCT_NAME	"Twinkle"
#define PRODUCT_VERSION	VERSION

// Anonymous calling
#define ANONYMOUS_DISPLAY	"Anonymous"
#define ANONYMOUS_URI		"sip:anonymous@anonymous.invalid"

// Call transfer types
enum t_transfer_type {
	TRANSFER_BASIC,		// Basic transfer (blind)
	TRANSFER_CONSULT,	// Transfer with consultation (possibly attended)
	TRANSFER_OTHER_LINE	// Transfer call to other line
};

// State of a call transfer at the referrer.
enum t_refer_state {
	REFST_NULL,		// No REFER in progress
	REFST_W4RESP,		// REFER sent, waiting for response
	REFST_W4NOTIFY,		// Response received, waiting for 1st NOTIFY
	REFST_PENDING,		// REFER received, but not granted yet
	REFST_ACTIVE,		// Referee granted refer
};

// Types of registration requests
enum t_register_type {
	REG_REGISTER,
	REG_QUERY,
	REG_DEREGISTER,
	REG_DEREGISTER_ALL
};

// RFC 3261 Annex A
// SIP timers
enum t_sip_timer {
	TIMER_T1,
	TIMER_T2,
	TIMER_T4,
	TIMER_A,
	TIMER_B,
	TIMER_C,
	TIMER_D,
	TIMER_E,
	TIMER_F,
	TIMER_G,
	TIMER_H,
	TIMER_I,
	TIMER_J,
	TIMER_K
};

// All durations are in msec
#define DURATION_T1	500
#define DURATION_T2	4000
#define DURATION_T4	5000
#define DURATION_A	DURATION_T1
#define DURATION_B	(64 * DURATION_T1)
#define DURATION_C	180000
#define DURATION_D	32000
#define DURATION_E	DURATION_T1
#define DURATION_F	(64 * DURATION_T1)
#define DURATION_G	DURATION_T1
#define DURATION_H	(64 * DURATION_T1)
#define DURATION_I	DURATION_T4
#define DURATION_J	(64 * DURATION_T1)
#define DURATION_K	DURATION_T4

/** UA (phone) timers */
enum t_phone_timer {
	PTMR_REGISTRATION,	/**< Registration (failure) timeout */
	PTMR_NAT_KEEPALIVE,	/**< NAT binding refresh timeout for STUN */
};

/** UA (line) timers */
enum t_line_timer {
	LTMR_ACK_TIMEOUT,	/**< Waiting for ACK */
	LTMR_ACK_GUARD,		/**< After this timer ACK is lost for good */
	LTMR_INVITE_COMP,	/**< After this timer INVITE transiction is considered complete. */
	LTMR_NO_ANSWER,		/**< This timer expires if the callee does not answer. The call will be torn down. */
	LTMR_RE_INVITE_GUARD,	/**< re-INVITE timeout */
	LTMR_100REL_TIMEOUT,	/**< Waiting for PRACK */
	LTMR_100REL_GUARD,	/**< After this timer PRACK is lost for good */
	LTMR_GLARE_RETRY,	/**< Waiting before retry re-INVITE after glare */
	LTMR_CANCEL_GUARD,	/**< Guard for situation where CANCEL has been responded to, but 487 on INVITE is never received. */
};

/** Subscription timers. */
enum t_subscribe_timer {
	STMR_SUBSCRIPTION,	/**< Subscription timeout */
};

/** Publication timers. */
enum t_publish_timer {
	PUBLISH_TMR_PUBLICATION,	/**< Publication timeout */
};

/** STUN timers. */
enum t_stun_timer {
	STUN_TMR_REQ_TIMEOUT,	/**< Waiting for response */
};


// No answer timer (ms)
#define DUR_NO_ANSWER(u)	((u)->get_timer_noanswer() * 1000)

// Registration timers (s)
// Registration duration (seconds)
#define DUR_REGISTRATION(u)	((u)->get_registration_time())
#define RE_REGISTER_DELTA	5   // Re-register 5 seconds before expiry
#define DUR_REG_FAILURE         30  // Re-registration interval after reg. failure

// NAT keepalive timer (s) default value
#define DUR_NAT_KEEPALIVE	30

// re-INVITE guard timer (ms). This timer guards against the situation
// where a UAC has sent a re-INVITE, received a 1XX but never receives
// a final response. No timer for this is defined in RFC 3261
#define DUR_RE_INVITE_GUARD	10000

// Guard for situation where CANCEL has been 
// responded to, but 487 on INVITE is never eceived.
// This situation is not defined by RFC 3261
#define DUR_CANCEL_GUARD	(64 * DURATION_T1)

// MWI timers (s)
#define DUR_MWI(u)		((u)->get_mwi_subscription_time())
#define DUR_MWI_FAILURE		30

// Presence timers (s)
#define DUR_PRESENCE(u)		((u)->get_pres_subscription_time())
#define DUR_PRESENCE_FAILURE	30

// RFC 3261 14.1
// Maximum values (10th of sec) for timers for retrying a re-INVITE after
// a glare (491 response).
#define MAX_GLARE_RETRY_NOT_OWN	20
#define MAX_GLARE_RETRY_OWN	40

// Calculate the glare retry duration (ms)
#define DUR_GLARE_RETRY_NOT_OWN	((rand() % (MAX_GLARE_RETRY_NOT_OWN + 1)) * 100)
#define DUR_GLARE_RETRY_OWN	((rand() % (MAX_GLARE_RETRY_OWN - \
				MAX_GLARE_RETRY_NOT_OWN) + 1 + MAX_GLARE_RETRY_NOT_OWN)\
				* 100)

// RFC 3262
// PRACK timers
#define DUR_100REL_TIMEOUT	DURATION_T1
#define DUR_100REL_GUARD	(64 * DURATION_T1)

// refer subscription timer (s)
// RFC 3515 does not define the length of the timer.
// It should be long enough to notify the result of an INVITE.
#define DUR_REFER_SUBSCRIPTION	60 // Used when refer is always permitted
#define DUR_REFER_SUB_INTERACT	90 // Used when user has to grant permission

// Minimum duration of a subscription
#define MIN_DUR_SUBSCRIPTION	60

// Duration to wait before re-subscribing after termination of
// a subscription
#define DUR_RESUBSCRIBE		30

// After an unsubscribe has been sent, a NOTIFY will should come in.
// In case the NOTIFY does not come, this guard timer (ms) will assure
// that the subscription will be cleaned up.
#define DUR_UNSUBSCRIBE_GUARD	4000

// RFC 3489
// STUN retransmission timer intervals (ms)
// The RFC states that the interval should start at 100ms. But that
// seems to short. We start at 200 and do 8 instead of 9 transmissions.
#define DUR_STUN_START_INTVAL	200
#define DUR_STUN_MAX_INTVAL	1600

// Maximum number of transmissions
#define STUN_MAX_TRANSMISSIONS	8

// RFC 3261
#ifndef RFC3261_COOKIE
#define RFC3261_COOKIE	"z9hG4bK"
#endif

// Max forwards RFC 3261 8.1.1.6
#define MAX_FORWARDS	70

// Length of tags in from and to headers
#define TAG_LEN		5

// Create a new tag
#define NEW_TAG		random_token(TAG_LEN)

// Length of call-id (before domain)
#define CALL_ID_LEN	15

// Create a new call-id
#define NEW_CALL_ID(u)	(random_token(CALL_ID_LEN) + '@' + USER_HOST(u))

// Create a new sequence number fo CSeq header
#define NEW_SEQNR	rand() % 1000 + 1

// Length of cnonce
#define CNONCE_LEN	10

// Create a cnonce
#define NEW_CNONCE	random_hexstr(CNONCE_LEN)

/** Length of tuple id in PIDF documents. */
#define PIDF_TUPLE_ID_LEN	6

/** Create a new PIDF tuple id. */
#define NEW_PIDF_TUPLE_ID	random_token(PIDF_TUPLE_ID_LEN)

// Character set encoding for outgoing text messages
#define MSG_TEXT_CHARSET	"utf-8"

// Set Allow header with methods that can be handled by the phone
#define SET_HDR_ALLOW(h, u)	{ (h).add_method(INVITE); \
				  (h).add_method(ACK); \
				  (h).add_method(BYE); \
				  (h).add_method(CANCEL); \
				  (h).add_method(OPTIONS); \
				  if ((u)->get_ext_100rel() != EXT_DISABLED) {\
				  	(h).add_method(PRACK);\
				  }\
				  (h).add_method(REFER); \
				  (h).add_method(NOTIFY); \
				  (h).add_method(SUBSCRIBE); \
				  (h).add_method(INFO); \
				  (h).add_method(MESSAGE); \
				}

// Set Supported header with supported extensions
#define SET_HDR_SUPPORTED(h, u)	{ if ((u)->get_ext_replaces()) {\
					(h).add_feature(EXT_REPLACES);\
				  }\
				  (h).add_feature(EXT_NOREFERSUB);\
				}

// Set Accept header with accepted body types
#define SET_HDR_ACCEPT(h)	{ (h).add_media(t_media("application",\
				  "sdp")); }
				 
/** Set Accept header with accepted body types for messaging. */
#define SET_MESSAGE_HDR_ACCEPT(h)	{ (h).add_media(t_media("text", "plain"));\
					  (h).add_media(t_media("text", "html")); }

/** Set Accept header with accepted body types for presence. */
#define SET_PRESENCE_HDR_ACCEPT(h)	{ (h).add_media(t_media("application",\
				  "pidf+xml")); }
				  
/** Set Accept header with accepted body types for MWI. */
#define SET_MWI_HDR_ACCEPT(h)	{ (h).add_media(t_media("application",\
				  "simple-message-summary")); }

/** Set Accept-Encoding header with accepted encodings. */
#define SET_HDR_ACCEPT_ENCODING(h)\
				{ (h).add_coding(t_coding("identity")); }
				
/** Check if content encoding is supported */
#define CONTENT_ENCODING_SUPPORTED(ce)\
				(cmp_nocase(ce, "identity") == 0)

// Set Accept-Language header with accepted languages
#define SET_HDR_ACCEPT_LANGUAGE(h)\
				{ (h).add_language(t_language("en")); }

// Set User-Agent header
#define SET_HDR_USER_AGENT(h)	{ (h).add_server(t_server(PRODUCT_NAME,\
					PRODUCT_VERSION)); }

// Set Server header
#define SET_HDR_SERVER(h)	{ (h).add_server(t_server(PRODUCT_NAME,\
					PRODUCT_VERSION)); }

// Set Organization header
#define SET_HDR_ORGANIZATION(h, u)	{ if ((u)->get_organization() != "") {\
					(h).set_name((u)->get_organization()); }}

// Check if an event is supported by Twinkle				
#define SIP_EVENT_SUPPORTED(e)	((e) == SIP_EVENT_REFER ||\
				 (e) == SIP_EVENT_MSG_SUMMARY ||\
				 (e) == SIP_EVENT_PRESENCE)

// Add the supported events to the Allow-Events header
#define ADD_SUPPORTED_SIP_EVENTS(h)	{ (h).add_event_type(SIP_EVENT_REFER);\
					  (h).add_event_type(SIP_EVENT_MSG_SUMMARY);\
					  (h).add_event_type(SIP_EVENT_PRESENCE); }

#endif


syntax highlighted by Code2HTML, v. 0.9.1