/* Copyright (C) 2005-2009 Michel de Boer 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, see . */ /** * @file * Subscription (RFC 3265) */ #ifndef _SUBSCRIPTION_H #define _SUBSCRIPTION_H #include #include #include "abstract_dialog.h" /** Subscription role */ enum t_subscription_role { SR_SUBSCRIBER, /**< Subscriber */ SR_NOTIFIER /**< Notifier */ }; /** Subscription state */ enum t_subscription_state { SS_NULL, /**< Initial state */ SS_ESTABLISHED, /**< Subscription is in place */ SS_UNSUBSCRIBING, /**< A request to unsubscribe has been sent */ SS_UNSUBSCRIBED, /**< An outoging unsubscribe was successful. Waiting for the final NOTIFY. */ SS_TERMINATED, /**< Subscription ended */ }; /** * Convert a subscription state to string. * @param state [in] Subscription state. * @return String representation of state. */ string t_subscription_state2str(t_subscription_state state); /** * RFC 3265 * Generic subscription state for subscribers and notifiers * For each event type this class should be subclassed. */ class t_subscription { protected: t_subscription_role role; t_subscription_state state; /** * When a subscriber subscription is terminated, this reason indicates * the reason conveyed in the NOTIFY, if any. */ string reason_termination; /** * If the NOTIFY indicated that the subscriber may retry subscription at * a later time, then resubscribe_after indicates the number of seconds to wait. */ unsigned long resubscribe_after; /** Indicates if a re-subscribe may be done after a failure. */ bool may_resubscribe; t_abstract_dialog *dialog; /**< Dialog owning the subscription */ string event_type; string event_id; /** * User profile of user using the line * This is a pointer to the user_config owned by a phone user. * So this pointer should never be deleted. */ t_user *user_config; bool pending; /**< Indicates if not active yet. */ /** @name Timers */ //@{ /** * For a subscriber the subscription_timeout timer indicates when * the subscription must be refreshed. * For a notifier it indicates when the subscription expires. */ unsigned short id_subscription_timeout; /** * Indicates if a subscriber automatically refreshes the subscritption * when the subscription timer expires. If not, then the subscription * terminates at expiry. */ bool auto_refresh; /** Subcription expiry for a SUBSCRIBE request */ unsigned long subscription_expiry; /** Default duration for a subscription */ unsigned long default_duration; //@} /** Protect constructor from being used */ t_subscription() {}; /** Write event type and id to log file */ void log_event() const; /** * Remove a pending request. Pass one of the client request pointers. * @param cr [in] Client request to remove. */ void remove_client_request(t_client_request **cr); /** @name Create requests based on the event type */ //@{ /** * Create a SUBSCRIBE request. * Creating a SUBSCRIBE is for subscription refreshment/unsubscribe. * @param expires [in] Expiry time in seconds. */ virtual t_request *create_subscribe(unsigned long expires) const; /** * Create a NOTIFY request. * @param sub_state [in] Subscription state to be put in the Subscription-State header. * @param reason [in] The reason parameter of the Subscription-State header. */ virtual t_request *create_notify(const string &sub_state, const string &reason = "") const; //@} /** * Send request. * @param user_config [in] User profile of user sending the request. * @param r [in] Request to send. * @param tuid [in] Transaction user id. */ void send_request(t_user *user_config, t_request *r, t_tuid tuid) const; /** * Send response. * @param user_config [in] User profile of user sending the response. * @param r [in] Response to send. * @param tuid [in] Transaction user id. * @param tid [in] Transaction id. */ void send_response(t_user *user_config, t_response *r, t_tuid tuid, t_tid tid) const; /** * Start a subscription timer. * @param timer [in] Type of subscription timer. * @param duration [in] Duration of timer in ms */ void start_timer(t_subscribe_timer timer, long duration); /** * Stop a subscription timer. * @param timer [in] Type of subscription timer. */ void stop_timer(t_subscribe_timer timer); public: /** Pending request */ t_client_request *req_out; /** * Queue of pending outgoing NOTIFY requests. A next NOTIFY * will only be sent after the previous NOTIFY has been * answered. */ queue queue_notify; /** * Constructor * @param _dialog [in] Dialog owning this subscription. SUBSCRIBE and NOTIFY * requests are sent within this dialog. * @param _role [in] Role * @param _event_type [in] Event type of the subscription. */ t_subscription(t_abstract_dialog *_dialog, t_subscription_role _role, const string &_event_type); /** * Constructor * @param _dialog [in] Dialog owning this subscription. SUBSCRIBE and NOTIFY * requests are sent within this dialog. * @param _role [in] Role * @param _event_type [in] Event type of the subscription. * @param _event_id [in] Event id. */ t_subscription(t_abstract_dialog *_dialog, t_subscription_role _role, const string &_event_type, const string &_event_id); /** Destructor */ virtual ~t_subscription(); /** @name Getters */ //@{ t_subscription_role get_role(void) const; t_subscription_state get_state(void) const; string get_reason_termination(void) const; unsigned long get_resubscribe_after(void) const; bool get_may_resubscribe(void) const; string get_event_type(void) const; string get_event_id(void) const; unsigned long get_expiry(void) const; //@} /** @name Receive requests */ //@{ /** * Reveive SUBSCRIBE request * @param r [in] Received request. * @param tuid [in] Transaction user id. * @param tid [in] Transaction id. * @return The return value indicates if processing is finished. * This way a subclass can first call the parent class method. * If the parent indicates that process is finished, then the child * does not need to further process. * Note that recv_subscribe returns false if the SUBSCRIBE is valid. The * subscription timer will be started, but no response is sent. The subclass * MUST further handle the SUBSCRIBE, i.e. send a response and a NOTIFY. */ virtual bool recv_subscribe(t_request *r, t_tuid tuid, t_tid tid); /** * Receive NOTIFY request. * @param r [in] Received request. * @param tuid [in] Transaction user id. * @param tid [in] Transaction id. * @return When the NOTIFY is valid, false is returned. The subclass MUST further * handle the NOTIFY, i.e. send a response. */ virtual bool recv_notify(t_request *r, t_tuid tuid, t_tid tid); //@} /** @name Receive responses */ //@{ /** * Receive NOTIFY/SUBSCRIBE response. * @param r [in] Received response. * @param tuid [in] Transaction user id. * @param tid [in] Transaction id. * @return The return value indicates if processing is finished. */ virtual bool recv_response(t_response *r, t_tuid tuid, t_tid tid); /** * Receive NOTIFY response. * @param r [in] Received response. * @param tuid [in] Transaction user id. * @param tid [in] Transaction id. * @return The return value indicates if processing is finished. */ virtual bool recv_notify_response(t_response *r, t_tuid tuid, t_tid tid); /** * Receive SUBSCRIBE response. * @param r [in] Received response. * @param tuid [in] Transaction user id. * @param tid [in] Transaction id. * @return The return value indicates if processing is finished. */ virtual bool recv_subscribe_response(t_response *r, t_tuid tuid, t_tid tid); //@} /** * Process timeouts * @param timer [in] Type of subscription timer. * @return The return value indicates if processing is finished. */ virtual bool timeout(t_subscribe_timer timer); /** * Match timer id with a running timer. * @param timer [in] Type of subscription timer. * @return True, if id matches, otherwise false. */ virtual bool match_timer(t_subscribe_timer timer, t_object_id id_timer) const; /** * Does incoming request match with event type and id? * @param r [in] Request to match. * @return True if request matches, otherwise false. */ virtual bool match(t_request *r) const; /** * Check if subscription is pending. * @return True if subscription is pending, otherwise false. */ bool is_pending(void) const; /** * Subscribe to an event. * @param expires [in] Expiry in seconds. If expires == 0, then the default duration is used. */ virtual void subscribe(unsigned long expires); /** Unsubscribe from an event. */ virtual void unsubscribe(void); /** Refresh subscription. */ virtual void refresh_subscribe(void); }; #endif