diff options
Diffstat (limited to 'src/line.h')
-rw-r--r-- | src/line.h | 567 |
1 files changed, 567 insertions, 0 deletions
diff --git a/src/line.h b/src/line.h new file mode 100644 index 0000000..a1e1cb3 --- /dev/null +++ b/src/line.h @@ -0,0 +1,567 @@ +/* + Copyright (C) 2005-2009 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 _LINE_H +#define _LINE_H + +#include <list> +#include <string> +#include "call_history.h" +#include "dialog.h" +#include "id_object.h" +#include "phone.h" +#include "protocol.h" +#include "user.h" +#include "audio/audio_codecs.h" +#include "sockets/url.h" +#include "parser/request.h" +#include "parser/response.h" +#include "stun/stun.h" + +using namespace std; + +// Forward declarations +class t_dialog; +class t_phone; + +// Info about the current call. +// This info can be used by the user interface to render the +// call state to the user. +class t_call_info { +public: + t_url from_uri; + string from_display; + + // Override of display for presentation to user, e.g. name from + // address book lookup. + string from_display_override; + + string from_organization; + t_url to_uri; + string to_display; + string to_organization; + string subject; + bool dtmf_supported; + bool dtmf_inband; // DTMF must be sent inband + bool dtmf_info; // DTMF must be sent via SIP INFO + t_hdr_referred_by hdr_referred_by; + + // The reason phrase of the last received provisional response + // on an outgoing INVITE. + string last_provisional_reason; + + t_audio_codec send_codec; + t_audio_codec recv_codec; + bool refer_supported; + + t_call_info(); + void clear(void); + + // Get the from display name to show to the user. + string get_from_display_presentation(void) const; +}; + +class t_line : public t_id_object { + friend class t_phone; + +private: + t_line_state state; + t_line_substate substate; + bool is_on_hold; + bool is_muted; + bool hide_user; // Anonymous call + + // Indicates if a call is a consultation for a transfer + bool is_transfer_consult; + + // The line about which this consultation handles. + unsigned short consult_transfer_from_line; + + // Indicates if this call is to be transferred after consultation. + bool to_be_transferred; + + // After consultation this line should be transferred to the + // transfer_to_line. + unsigned short consult_transfer_to_line; + + // Indicates if media encryption should be negotiated. + bool try_to_encrypt; + + // Indicates if call must be auto answered + bool auto_answer; + + // Line number (starting from 0) + // The number of a line may change when it moves from the user lines + // to the pool of dying lines. So a line number cannot be used as + // unique line identification over longer times. + unsigned short line_number; + + // The phone that owns this line + t_phone *phone; + + // Dialog for which no response with a to-tag has been received. + // Formally this is not a dialog yet. + t_dialog *open_dialog; + + // Dialogs for which a response (1XX/2XX) with a to-tag has + // been received. + list<t_dialog *> pending_dialogs; + + // Outgoing call: The first dialog for which a 2XX has been received. + // Incoming call: Dialog created by an incoming INVITE + t_dialog *active_dialog; + + // Currently not used. + list<t_dialog *> dying_dialogs; + + // Timers + t_object_id id_invite_comp; + t_object_id id_no_answer; + + // Call info + t_call_info call_info; + + /** RTP port to be used for this line. */ + unsigned short rtp_port; + + /** + * Phone user using the line. + * This member is only set when the line is not idle. + * An idle line is not associated with a user. + * @note The line object does not own the phone user. + * Therefor the line object must never delete the phone user. + */ + t_phone_user *phone_user; + + // The incoming call script can return a specific ring tone + // to be played for an incoming call. This ring tone is + // stored here. If there is no specific ring tone to be played + // then this attribute is empty + string user_defined_ringtone; + + // Indicates if the line must go to seized state when it + // becomes idle. + bool keep_seized; + + // Find a dialog from the list that matches the response. + t_dialog *match_response(t_response *r, + const list<t_dialog *> &l) const; + t_dialog *match_response(StunMessage *r, t_tuid tuid, + const list<t_dialog *> &l) const; + t_dialog *match_call_id_tags(const string &call_id, + const string &to_tag, const string &from_tag, + const list<t_dialog *> &l) const; + + // Get the dialog with id == did. If dialog does not exist + // then NULL is returned. + t_dialog *get_dialog(t_object_id did) const; + + // Clean up terminated dialogs + void cleanup(void); + + // Cleanup all open and pending dialogs + void cleanup_open_pending(void); + + // Forcefully cleanup all dialogs + void cleanup_forced(void); + + // Cleanup state for a transfer with consultation. + // If the call on this line is a consult, then the consult state of + // the line that is to be transferred will be cleaned too. + // If the call on this line is to be transferred, then the consult + // state of the consultation line will be cleared too. + void cleanup_transfer_consult_state(void); + +public: + // Call history record + t_call_record call_hist_record; + + t_line(t_phone *_phone, unsigned short _line_number); + ~t_line(); + + t_line_state get_state(void) const; + t_line_substate get_substate(void) const; + t_refer_state get_refer_state(void) const; + + // Timer operations + void start_timer(t_line_timer timer, t_object_id did = 0); + void stop_timer(t_line_timer timer, t_object_id did = 0); + + /** @name Actions */ + //@{ + /** + * Send INIVTE request. + * @param pu The phone user making this call. + * @param to_uri The URI to be used a request-URI and To header URI + * @param to_display Display name for To header. + * @param subject If not empty, this string will go into the Subject header. + * @param hdr_referred_by The Reffered-By header to be put in the INVITE. + * @param hdr_replaces The Replaces header to be put in the INVITE. + * @param hdr_require Required extensions to be put in the Require header. + * @param hdr_request_disposition Request-Disposition header to be put in the INVITE. + * @param anonymous Inidicates if the INVITE should be sent anonymous. + * + * @pre The line is idle. + */ + void invite(t_phone_user *pu, const t_url &to_uri, const string &to_display, + const string &subject, const t_hdr_referred_by &hdr_referred_by, + const t_hdr_replaces &hdr_replaces, const t_hdr_require &hdr_require, + const t_hdr_request_disposition &hdr_request_disposition, + bool anonymous); + + /** + * Send INIVTE request. + * @param pu The phone user making this call. + * @param to_uri The URI to be used a request-URI and To header URI + * @param to_display Display name for To header. + * @param subject If not empty, this string will go into the Subject header. + * @param no_fork If true, put a no-fork request disposition in the outgoing INVITE + * @param anonymous Inidicates if the INVITE should be sent anonymous. + * + * @pre The line is idle. + */ + void invite(t_phone_user *pu, const t_url &to_uri, const string &to_display, + const string &subject, bool no_fork, bool anonymous); + + void answer(void); + void reject(void); + void redirect(const list<t_display_url> &destinations, int code, string reason = ""); + void end_call(void); + void send_dtmf(char digit, bool inband, bool info); + //@} + + // OPTIONS inside dialog + void options(void); + + bool hold(bool rtponly = false); // returns false if call cannot be put on hold + void retrieve(void); + + // Kill all RTP stream associated with this line + void kill_rtp(void); + + void refer(const t_url &uri, const string &display); + + // Mute/unmute a call + // - enable = true -> mute + // - enable = false -> unmute + void mute(bool enable); + + /** @name Handle incoming responses */ + //@{ + void recvd_provisional(t_response *r, t_tuid tuid, t_tid tid); + void recvd_success(t_response *r, t_tuid tuid, t_tid tid); + void recvd_redirect(t_response *r, t_tuid tuid, t_tid tid); + void recvd_client_error(t_response *r, t_tuid tuid, t_tid tid); + void recvd_server_error(t_response *r, t_tuid tuid, t_tid tid); + void recvd_global_error(t_response *r, t_tuid tuid, t_tid tid); + //@} + + /** @name Handle incoming requests */ + //@{ + void recvd_invite(t_phone_user *pu, t_request *r, t_tid tid, const string &ringtone); + void recvd_ack(t_request *r, t_tid tid); + void recvd_cancel(t_request *r, t_tid cancel_tid, t_tid target_tid); + void recvd_bye(t_request *r, t_tid tid); + void recvd_options(t_request *r, t_tid tid); + void recvd_register(t_request *r, t_tid tid); + void recvd_prack(t_request *r, t_tid tid); + void recvd_subscribe(t_request *r, t_tid tid); + void recvd_notify(t_request *r, t_tid tid); + void recvd_info(t_request *r, t_tid tid); + void recvd_message(t_request *r, t_tid tid); + + /** + * Process REFER request. + * @return true, if refer has been accepted sofar. The refer may still + * be rejected by the user. + * @return false, if the refer has been rejected. + */ + bool recvd_refer(t_request *r, t_tid tid); + //@} + + // Handle the response from the user on the question for refer + // permission. This response is received on the dialog that received + // the REFER before. + // The request (r) is the REFER request that was received. + void recvd_refer_permission(bool permission, t_request *r); + + void recvd_stun_resp(StunMessage *r, t_tuid tuid, t_tid tid); + + void failure(t_failure failure, t_tid tid); + + void timeout(t_line_timer timer, t_object_id did); + void timeout_sub(t_subscribe_timer timer, t_object_id did, + const string &event_type, const string &event_id); + + // Return true if the response or request matches a dialog that + // is owned by this line + bool match(t_response *r, t_tuid tuid) const; + bool match(t_request *r) const; + bool match_cancel(t_request *r, t_tid target_tid) const; + bool match(StunMessage *r, t_tuid tuid) const; + + /** + * RFC 3891 Match info from Replaces header + * Match call id, to-tag and from tag like an incoming request. + * @param call_id [in] The Call ID of the Replaces header. + * @param to_tag [in] to-tag of the Replaces header. + * @param from_tag [in] from-tag of the Replaces header. + * @param no_fork_req_disposition [in] Indicates if the incoming request + * contains a no-fork request disposition. + * @param early_matched [out] When a match is found, early_matched + * indicates if the match was on an early dialog. + * @return true if a match is found with an associated dialog. + */ + bool match_replaces(const string &call_id, const string &to_tag, + const string &from_tag, + bool no_fork_req_disposition, + bool &early_matched) const; + + // Check if an incoming INVITE is a retransmission of an INVITE + // that is already being processed by this line + bool is_invite_retrans(t_request *r); + + // Process a retransmission of an incoming INVITE + void process_invite_retrans(void); + + // Create user uri and contact uri + string create_user_contact(const string &auto_ip) const; + string create_user_uri(void) const; + + // Create a response to an OPTIONS request + // Argument 'in-dialog' indicates if the OPTIONS response is + // sent within a dialog. + t_response *create_options_response(t_request *r, + bool in_dialog = false) const; + + // Send a response/request + void send_response(t_response *r, t_tuid tuid, t_tid tid); + void send_request(t_request *r, t_tuid tuid); + + t_phone *get_phone(void) const; + unsigned short get_line_number(void) const; + bool get_is_on_hold(void) const; + bool get_is_muted(void) const; + bool get_hide_user(void) const; + + // If this is a transfer consult, then true will be returned and + // lineno will be set to the line that must be transferred. + bool get_is_transfer_consult(unsigned short &lineno) const; + + // When setting the transfer consult indication to true, the + // line that must be transferred must be passed. + void set_is_transfer_consult(bool enable, unsigned short lineno); + + // If this line is to be transferred after consultation, then + // true will be returned and lineno will be set to the line + // where this line should be transferred to. + bool get_to_be_transferred(unsigned short &lineno) const; + + // When setting the to be transferred indication to true, the + // line to which must be transferred must be passed. + void set_to_be_transferred(bool enable, unsigned short lineno); + + bool get_is_encrypted(void) const; + bool get_try_to_encrypt(void) const; + bool get_auto_answer(void) const; + void set_auto_answer(bool enable); + bool is_refer_succeeded(void) const; + bool has_media(void) const; + + /** @name Remote (target) uri/display */ + //@{ + /** + * Get the remote target URI of the active dialog. + * @return Remote target URI. If there is no active dialog, then an + * empty URI is returned. + */ + t_url get_remote_target_uri(void) const; + + /** + * Get the remote target URI of the first pending dialog. + * @return Remote target URI. If there is no pending dialog, then an + * empty URI is returned. + */ + t_url get_remote_target_uri_pending(void) const; + + /** + * Get the remote target display name of the active dialog. + * @return Remote target display name. If there is no active dialog, + * then an empty string is returned. + */ + string get_remote_target_display(void) const; + + /** + * Get the remote target display name of the first pending dialog. + * @return Remote target display name. If there is no pending dialog, + * then an empty string is returned. + */ + string get_remote_target_display_pending(void) const; + + /** + * Get the remote URI of the active dialog. + * @return Remote URI. If there is no active dialog, then an + * empty URI is returned. + */ + t_url get_remote_uri(void) const; + + /** + * Get the remote URI of the first pending dialog. + * @return Remote URI. If there is no pending dialog, then an + * empty URI is returned. + */ + t_url get_remote_uri_pending(void) const; + + /** + * Get the remote display name of the active dialog. + * @return Remote display name. If there is no active dialog, + * then an empty string is returned. + */ + string get_remote_display(void) const; + + /** + * Get the remote display name of the first pending dialog. + * @return Remote display name. If there is no pending dialog, + * then an empty string is returned. + */ + string get_remote_display_pending(void) const; + //@} + + /** @name Call identification */ + //@{ + /** + * Get the call-id of the active dialog + * @return If there is no active dialog, then an empty string is returned. + */ + string get_call_id(void) const; + + /** + * Get the call-id of the first pending dialog + * @return If there is no pending dialog, then an empty string is returned. + */ + string get_call_id_pending(void) const; + + /** + * Get the local tag of the active dialog + * @return If there is no active dialog, then an empty string is returned. + */ + string get_local_tag(void) const; + + /** + * Get the local tag of the first pending dialog + * @return If there is no pending dialog, then an empty string is returned. + */ + string get_local_tag_pending(void) const; + + /** + * Get the remote tag of the active dialog + * @return If there is no active dialog, then an empty string is returned. + */ + string get_remote_tag(void) const; + + /** + * Get the remote tag of the first pending dialog + * @return If there is no pending dialog, then an empty string is returned. + */ + string get_remote_tag_pending(void) const; + //@} + + // Returns true if the remote party of the active dialog supports + // the extension. + // If there is no active dialog, then false is returned. + bool remote_extension_supported(const string &extension) const; + + // Seize the line. User wants to make an outgoing call, so + // the line must be marked as busy, such that an incoming call + // cannot take this line. + // Returns false if seizure failed + bool seize(void); + + // Unseize the line + void unseize(void); + + // Return the (audio) session belonging to this line. + // Returns NULL if there is no (audio) session + t_session *get_session(void) const; + t_audio_session *get_audio_session(void) const; + + void notify_refer_progress(t_response *r); + + // Called by dialog if retrieve/hold actions failed. + void failed_retrieve(void); + void failed_hold(void); + + // Called by dialog if retry of a retrieve after a glare (491 response) + // succeeded. + void retry_retrieve_succeeded(void); + + // Get the call info record + t_call_info get_call_info(void) const; + void ci_set_dtmf_supported(bool supported, bool inband = false, bool info = false); + void ci_set_last_provisional_reason(const string &reason); + void ci_set_send_codec(t_audio_codec codec); + void ci_set_recv_codec(t_audio_codec codec); + void ci_set_refer_supported(bool supported); + + // Initialize the RTP port for this line based on the settings + // in the user profile. + void init_rtp_port(void); + + /** Get the RTP port to be used for a call on this line. */ + unsigned short get_rtp_port(void) const; + + /** + * Get the user profile of the user using the phone. + * @return a pointer to the user object owned by the line. + * NOT a copy. + */ + t_user *get_user(void) const; + + /** + * Get the phone user using the phone. + * @return Pointer to the phone user. + */ + t_phone_user *get_phone_user(void) const; + + // Get the ring tone to be played for an incoming call + string get_ringtone(void) const; + + // ZRTP actions + void confirm_zrtp_sas(void); + void reset_zrtp_sas_confirmation(void); + void enable_zrtp(void); + void zrtp_request_go_clear(void); + void zrtp_go_clear_ok(void); + + // Force a line to the idle state (during termination of Twinkle) + void force_idle(void); + + // Indicate if the line must be seized after releasing + void set_keep_seized(bool seize); + bool get_keep_seized(void) const; + + /** + * Get a dialog that has an active session (RTP stream). + * @return The dialog that has an active session. + * @return NULL, if there is no dialog with an active session. + * @note There can be at most 1 dialog with an active session. + */ + t_dialog *get_dialog_with_active_session(void) const; +}; + +#endif |