diff options
Diffstat (limited to 'src/phone_user.h')
-rw-r--r-- | src/phone_user.h | 491 |
1 files changed, 491 insertions, 0 deletions
diff --git a/src/phone_user.h b/src/phone_user.h new file mode 100644 index 0000000..387baba --- /dev/null +++ b/src/phone_user.h @@ -0,0 +1,491 @@ +/* + 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 +*/ + +// State of active phone user + +#ifndef _PHONE_USER_H +#define _PHONE_USER_H + +#include <string> +#include <list> +#include "auth.h" +#include "protocol.h" +#include "service.h" +#include "transaction_layer.h" +#include "user.h" +#include "im/msg_session.h" +#include "mwi/mwi.h" +#include "mwi/mwi_dialog.h" +#include "parser/request.h" +#include "parser/response.h" +#include "stun/stun.h" +#include "presence/buddy.h" + +using namespace std; +using namespace im; + +// Forward declarations +class t_client_request; +class t_presence_epa; + +class t_phone_user { +private: + t_user *user_config; + + // State + // Indicates that this user is active. A non-active user + // is not removed from the user list as some transactions may + // still need the user info after the user got de-activated. + bool active; + + // Requests outside a dialog + t_client_request *r_options; + t_client_request *r_register; + t_client_request *r_deregister; + t_client_request *r_query_register; + t_client_request *r_message; + + // STUN request + t_client_request *r_stun; + + /** + * Pending MESSAGE requests. + * Twinkle will only send one message at a time per user. + * This satisfies the requirements in RFC 3428 8. + * NOTE: as an optimization a message queue per destination + * could be kept. This way a pending message for one destination + * will not block a message for another destination. + */ + list<t_request *> pending_messages; + + /** @name Registration data */ + //@{ + string register_call_id; /**< Call-ID for REGISTER requests. */ + unsigned long register_seqnr; /**< Last seqnr issued. */ + bool is_registered; /**< Indicates if user is registered. */ + unsigned long registration_time; /**< Expiration in seconds */ + bool last_reg_failed; /** Indicates if last registration failed. */ + + /** Destination of last REGISTER */ + t_ip_port register_ip_port; + + /** Service Route, collected from REGISTER responses */ + list<t_route> service_route; + //@} + + // A STUN request can be triggered by the following events: + // + // * Registration + // * MWI subscription. + // + // These events should take place after the STUN transaction has + // finished. The following indicators indicate which events should + // take place. + bool register_after_stun; + bool mwi_subscribe_after_stun; + bool stun_binding_inuse_registration; + bool stun_binding_inuse_mwi; + + // Authorizor + t_auth authorizor; + + // MWI dialog + t_mwi_dialog *mwi_dialog; + + /** + * Indicates if MWI must be automatically resubscribed to, if the + * subscription terminates with a reason telling that resubscription + * is possible. + */ + bool mwi_auto_resubscribe; + + /** Buddy list for presence susbcriptions. */ + t_buddy_list *buddy_list; + + /** Event publication agent for presence */ + t_presence_epa *presence_epa; + + /** + * Resend the request: a new sequence number will be assigned and a new via + * header created (new transaction). + * @param req [in] The request to resend. + * @param is_register [in] indicates if this request is a register + * @param cr [in] is the current client request wrapper for this request. + * @note In case of a REGISTER, the internal register seqnr will be increased. + */ + void resend_request(t_request *req, bool is_register, t_client_request *cr); + + /** @name Handle responses. */ + //@{ + /** + * Process a repsonse on a registration request. + * @param r [in] The response. + * @param re_register [out] Indicates if an automatic re-registration needs + * to be done. + */ + void handle_response_register(t_response *r, bool &re_register); + + /** + * Process a response on a de-registration request. + * @param r [in] The response. + */ + void handle_response_deregister(t_response *r); + + /** + * Process a response on a registration query request. + * @param r [in] The response. + */ + void handle_response_query_register(t_response *r); + + /** + * Process a response on an OPTIONS request. + * @param r [in] The response. + */ + void handle_response_options(t_response *r); + + /** + * Process a response on a MESSAGE request. + * @param r [in] The response. + */ + void handle_response_message(t_response *r); + //@} + + /** Send a NAT keep alive packet. */ + void send_nat_keepalive(void); + + /** Send a TCP ping packet. */ + void send_tcp_ping(void); + + /** Handle MWI dialog termination. */ + void cleanup_mwi_dialog(void); + + /** Cleanup registration data for STUN and NAT keep alive. */ + void cleanup_registration_data(void); + +public: + /** @name Timers */ + //@{ + unsigned short id_registration; /**< Registration timeout */ + unsigned short id_nat_keepalive; /**< NAT keepalive interval */ + unsigned short id_tcp_ping; /**< TCP ping timer */ + unsigned short id_resubscribe_mwi; /**< MWI re-subscribe after failure */ + //@} + + /** Supplementary services */ + t_service *service; + + /** Message Waiting Indication data. */ + t_mwi mwi; + + /** @name STUN data */ + //@{ + bool use_stun; /**< Indicates if STUN must be used. */ + bool use_nat_keepalive; /**< Send NAT keepalive ? */ + unsigned long stun_public_ip_sip; /**< Public IP for SIP */ + unsigned short stun_public_port_sip; /**< Public port for SIP */ + + /** Number of presence subscriptions using the STUN binding. */ + unsigned short stun_binding_inuse_presence; + + /**< Subscribe to presence after STUN transaction completed. */ + bool presence_subscribe_after_stun; + //@} + + /** + * The constructor will create a copy of profile. + * @param profile [in] User profile of this phone user. + */ + t_phone_user(const t_user &profile); + + /** Destructor. */ + ~t_phone_user(); + + /** Send STUN request. */ + void send_stun_request(void); + + /** Cleanup STUN data if not in use anymore. */ + void cleanup_stun_data(void); + + /** Stop sending NAT keep alives when not necessary anymore. */ + void cleanup_nat_keepalive(void); + + /** + * Synchronize the sending of NAT keep alives with the user config. + * Start sending if keep alives are enabled but currently not being + * sent. + */ + void sync_nat_keepalive(void); + + /** Stop sending TCP ping packets when not necessary anumore. */ + void cleanup_tcp_ping(void); + + /** @name Getters */ + //@{ + t_user *get_user_profile(void); + t_buddy_list *get_buddy_list(void); + t_presence_epa *get_presence_epa(void); + //@} + + // Handle responses for out-of-dialog requests + void handle_response_out_of_dialog(t_response *r, t_tuid tuid, t_tid tid); + void handle_response_out_of_dialog(StunMessage *r, t_tuid tuid); + + /** + * Send a registration, de-registration or query registration request. + * @param register_type [in] Type of registration request. + * @param re_register [in] Indicates if this registration request is a re-registration. + * @param expires [in] Epxiry time to put in registration request. + * @note If needed a STUN request is sent before doing a registration. + */ + void registration(t_register_type register_type, bool re_register, + unsigned long expires = 0); + + // OPTIONS outside dialog + void options(const t_url &to_uri, const string &to_display = ""); + + /** @name MWI */ + //@{ + /** Subscribe to MWI. */ + void subscribe_mwi(void); + + /** Unsusbcribe to MWI. */ + void unsubscribe_mwi(void); + + /** + * Check if an MWI subscription is established. + * @return true, if an MWI subscription is established. + * @return false, otherwise + */ + bool is_mwi_subscribed(void) const; + + /** + * Check if an MWI dialog does exist. + * @return true, if there is no MWI subscription dialog. + * @return false, otherwise + */ + bool is_mwi_terminated(void) const; + + /** + * Process an unsollicited NOTIFY for MWI. + * @param r [in] The NOTIFY request. + * @param tid [in] Transaction identifier of the NOTIFY transaction. + */ + void handle_mwi_unsollicited(t_request *r, t_tid tid); + //@} + + /** @name Presence */ + //@{ + /** Subscribe to presence of buddies in buddy list. */ + void subscribe_presence(void); + + /** Unsusbcribe to presence of buddies in buddy list. */ + void unsubscribe_presence(void); + + /** + * Check if all presence subscriptions are terminated. + * @return true, if all presence subscriptions are terminated. + * @return false, otherwise + */ + bool is_presence_terminated(void) const; + + /** + * Publish presence. + * @param basic_state [in] The basic presence state to publish. + */ + void publish_presence(t_presence_state::t_basic_state basic_state); + + /** Unpublish presence. */ + void unpublish_presence(void); + //@} + + /** + * Send a text message. + * @param to_uri [in] Destination URI of recipient. + * @param to_display [in] Display name of recipient. + * @param msg [in] The message to send. + * @return True if sending succeeded, otherwise false. + */ + bool send_message(const t_url &to_uri, const string &to_display, const t_msg &message); + + /** + * @param to_uri [in] Destination URI of recipient. + * @param to_display [in] Display name of recipient. + * @param state [in] Message composing state. + * @param refresh [in] The refresh interval in seconds (when state is active). + * @return True if sending succeeded, false otherwise. + * @note For the idle state, the value of refresh has no meaning. + */ + bool send_im_iscomposing(const t_url &to_uri, const string &to_display, + const string &state, time_t refresh); + + /** + * Process incoming MESSAGE request. + * @param r [in] The MESSAGE request. + * @param tid [in] Transaction id of the request transaction. + */ + void recvd_message(t_request *r, t_tid tid); + + /** + * Process incoming NOTIFY reqeust. + * @param r [in] The NOTIFY request. + * @param tid [in] Transaction id of the request transaction. + */ + void recvd_notify(t_request *r, t_tid tid); + + /** @name Process timeouts */ + //@{ + /** + * Process phone timer expiry. + * @param timer [in] Type of expired phone timer. + */ + void timeout(t_phone_timer timer); + + /** + * Proces subscribe timer expiry. + * @param timer [in] Type of expired subscribe timer. + * @param id_timer [in] Id of expired timer. + */ + void timeout_sub(t_subscribe_timer timer, t_object_id id_timer); + + /** + * Proces publish timer expiry. + * @param timer [in] Type of expired subscribe timer. + * @param id_timer [in] Id of expired timer. + */ + void timeout_publish(t_publish_timer timer, t_object_id id_timer); + //@} + + /** Handle a broken persistent connection. */ + void handle_broken_connection(void); + + /** Match subscribe timeout with a subcription + * @param timer [in] Type of expired subscribe timer. + * @param id_timer [in] Id of expired timer. + * @return True if timer matches a subscription owned by the phone user. + * @return False, otherwise. + */ + bool match_subscribe_timer(t_subscribe_timer timer, t_object_id id_timer) const; + + /** Match publish timeout with a subcription + * @param timer [in] Type of expired publish timer. + * @param id_timer [in] Id of expired timer. + * @return True if timer matches a publication owned by the phone user. + * @return False, otherwise. + */ + bool match_publish_timer(t_publish_timer timer, t_object_id id_timer) const; + + /** + * Start the re-subscribe timer after an MWI subscription failure. + * @param duration [in] Duration before trying a re-subscribe (s) + */ + void start_resubscribe_mwi_timer(unsigned long duration); + + /** Stop MWI re=subscribe timer. */ + void stop_resubscribe_mwi_timer(void); + + /** + * Create request. + * Headers that are the same for each request + * are already populated: Via, From, Max-Forwards, User-Agent. + * All possible destinations for a failover are calculated. + * @param m [in] Request method. + * @param request_uri [in] Request-URI. + * @return The created request. + */ + t_request *create_request(t_method m, const t_url &request_uri) 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; + + // Get registration status + bool get_is_registered(void) const; + bool get_last_reg_failed(void) const; + + /** + * Get local IP address for SIP. + * @param auto_ip [in] IP address to use if no IP address has been determined through + * some NAT procedure. + * @return The IP address. + */ + string get_ip_sip(const string &auto_ip) const; + + /** + * Get local port for SIP. + * @return SIP port. + */ + unsigned short get_public_port_sip(void) const; + + /** + * Get the service route. + * @return The service route. + */ + list<t_route> get_service_route(void) const; + + // Try to match message with phone user + bool match(t_response *r, t_tuid tuid) const; + bool match(t_request *r) const; + bool match(StunMessage *r, t_tuid tuid) const; + + /** + * Authorize the request based on the challenge in the response + * @param r [inout] The request to be authorized. + * @param resp [in] The response containing the challenge (401/407). + * @param True if authorization succeeds, false otherwise. + * @post On succesful return the request r contains the correct authorization + * header (based on 401/407 response). + */ + bool authorize(t_request *r, t_response *resp); + + /** + * Resend the request: a new sequence number will be assigned and a new via + * header created (new transaction). + * @param req [in] The request to resend. + * @param cr [in] is the current client request wrapper for this request. + * @note In case of a REGISTER, the internal register seqnr will be increased. + */ + void resend_request(t_request *req, t_client_request *cr); + + /** + * Remove cached credentials for a particular realm. + * @param realm [in] The realm. + */ + void remove_cached_credentials(const string &realm); + + /** + * Check if this phone user is active. + * @return True if phone user is active, false otherwise. + */ + bool is_active(void) const; + + /** + * Activate phone user. + * @param user [in] The user profile of the user. + * @note The passed user profile will replace the current user profile + * owned by phone user. During the deactivated state the profile may + * have been update. + */ + void activate(const t_user &user); + + /** Deactivate phone user. */ + void deactivate(void); +}; + +#endif |