Index: pjproject/branches/projects/pjsua2/build.mak.in
===================================================================
--- pjproject/branches/projects/pjsua2/build.mak.in	(revision 4637)
+++ pjproject/branches/projects/pjsua2/build.mak.in	(revision 4638)
@@ -145,5 +145,6 @@
 	$(APP_THIRD_PARTY_EXT)\
 	-lpj-$(TARGET_NAME)\
-	@LIBS@
+	@LIBS@ \
+	-lstdc++
 #  x   x  x  x  x  x  x   x  x  x  x  x  x   x  x  x  x  x  x   x  x  x  x  x
 #
Index: pjproject/branches/projects/pjsua2/pjsip-apps/src/samples/pjsua2_demo.cpp
===================================================================
--- pjproject/branches/projects/pjsua2/pjsip-apps/src/samples/pjsua2_demo.cpp	(revision 4637)
+++ pjproject/branches/projects/pjsua2/pjsip-apps/src/samples/pjsua2_demo.cpp	(revision 4638)
@@ -23,14 +23,13 @@
 using namespace pj;
 
-class MyAccountCallback : public AccountCallback
+class MyAccount : public Account
 {
 public:
-    MyAccountCallback()
-    : AccountCallback()
+    MyAccount()
     {}
 
     virtual void onRegState(OnRegStateParam &prm)
     {
-	AccountInfo ai = account()->getInfo();
+	AccountInfo ai = getInfo();
 	std::cout << (ai.regIsActive? "*** Register: code=" : "*** Unregister: code=")
 		  << prm.code << std::endl;
@@ -40,5 +39,5 @@
 static void mainProg() throw(Error)
 {
-    Endpoint & ep = Endpoint::instance();
+    Endpoint ep;
 
     // Create library
@@ -46,5 +45,7 @@
 
     // Init library
-    ep.libInit( EpConfig() );
+    EpConfig ep_cfg;
+    ep_cfg.logConfig.level = 4;
+    ep.libInit( ep_cfg );
 
     // Transport
@@ -63,5 +64,5 @@
     acc_cfg.sipConfig.authCreds.push_back( AuthCredInfo("digest", "*",
                                                         "test1", 0, "test1") );
-    std::auto_ptr<Account> acc(new Account(new MyAccountCallback, NULL));
+    std::auto_ptr<Account> acc(new MyAccount);
     acc->create(acc_cfg);
 
@@ -70,5 +71,4 @@
     // Destroy library
     std::cout << "*** PJSUA2 SHUTTING DOWN ***" << std::endl;
-    ep.libDestroy();
 }
 
@@ -84,6 +84,4 @@
     }
 
-    Endpoint::instance().libDestroy();
-
     return ret;
 }
Index: pjproject/branches/projects/pjsua2/pjsip-apps/src/swig/java/Makefile
===================================================================
--- pjproject/branches/projects/pjsua2/pjsip-apps/src/swig/java/Makefile	(revision 4637)
+++ pjproject/branches/projects/pjsua2/pjsip-apps/src/swig/java/Makefile	(revision 4638)
@@ -43,4 +43,6 @@
 MY_LDFLAGS	 = $(PJ_LDFLAGS) -lpjsua2-$(TARGET_NAME) $(PJ_LDLIBS) $(MY_JNI_LDFLAGS) -static-libstdc++
 
+.PHONY: all java
+
 all: $(LIBPJSUA2_SO) java
 
@@ -57,6 +59,10 @@
 	rm -rf $(OUT_DIR)/pjsua2_wrap.cpp $(OUT_DIR)/pjsua2_wrap.o $(LIBPJSUA2_SO) $(OUT_DIR)/*.java $(OUT_DIR)/*.class
 
-java:
+java: output/Error.class output/test.class
+
+output/Error.class: output/Error.java
 	$(MY_JAVAC) -d $(OUT_DIR) $(OUT_DIR)/*.java
+
+output/test.class: test.java
 	$(MY_JAVAC) -d $(OUT_DIR) -classpath "$(OUT_DIR)" test.java
 
Index: pjproject/branches/projects/pjsua2/pjsip-apps/src/swig/pjsua2.i
===================================================================
--- pjproject/branches/projects/pjsua2/pjsip-apps/src/swig/pjsua2.i	(revision 4637)
+++ pjproject/branches/projects/pjsua2/pjsip-apps/src/swig/pjsua2.i	(revision 4638)
@@ -10,5 +10,5 @@
 //
 %{
-#include "pjsua2/endpoint.hpp"
+#include "pjsua2.hpp"
 using namespace std;
 using namespace pj;
@@ -167,4 +167,6 @@
 %rename("%s", regexmatch$name="PJSUA_CALL_HOLD_TYPE_.*") "";// Unignore this
 %rename("%s") pjsua_acc_id;				// Unignore this
+%rename("%s") pjsua_destroy_flag;			// Unignore this
+%rename("%s", regexmatch$name="PJSUA_DESTROY_.*") "";	// Unignore this
 %include "pjsua-lib/pjsua.h"
 
@@ -175,7 +177,14 @@
 
 //
+// Ignore stuffs in pjsua2 itself
+//
+%ignore fromPj;
+%ignore toPj;
+
+//
 // Now include the API itself.
 //
 %include "pjsua2/types.hpp"
 %include "pjsua2/endpoint.hpp"
+#include "pjsua2/account.hpp"
 
Index: pjproject/branches/projects/pjsua2/pjsip-apps/src/swig/python/helper.mak
===================================================================
--- pjproject/branches/projects/pjsua2/pjsip-apps/src/swig/python/helper.mak	(revision 4637)
+++ pjproject/branches/projects/pjsua2/pjsip-apps/src/swig/python/helper.mak	(revision 4638)
@@ -17,4 +17,4 @@
 
 target_name:
-	$(TARGET_NAME)
+	@echo $(TARGET_NAME)
 	
Index: pjproject/branches/projects/pjsua2/pjsip/include/pjsua2/account.hpp
===================================================================
--- pjproject/branches/projects/pjsua2/pjsip/include/pjsua2/account.hpp	(revision 4637)
+++ pjproject/branches/projects/pjsua2/pjsip/include/pjsua2/account.hpp	(revision 4638)
@@ -878,7 +878,7 @@
 {
     /**
-     * The library call index allocated for the new call.
-     */
-    int			callIndex;
+     * The library call ID allocated for the new call.
+     */
+    int			callId;
 
     /**
@@ -917,5 +917,5 @@
      * SIP reason phrase received.
      */
-    pj_str_t		reason;
+    string		reason;
 
     /**
@@ -1085,19 +1085,138 @@
 };
 
-/**
- * Account callback
- */
-class AccountCallback
+
+/**
+ * @}  // PJSUA2_Acc_Data_Structure
+ */
+
+/**
+ * @addtogroup PJSUA2_ACC
+ * @{
+ */
+
+
+/**
+ * Account.
+ */
+class Account
 {
 public:
-    /** Virtual destructor */
-    virtual ~AccountCallback() {}
-
-    /**
-     * Get the account associated with this callback.
-     */
-    Account *account()
-    { return acc; }
-
+    /**
+     * Constructor.
+     */
+    Account();
+
+    /**
+     * Destructor. Note that if the account is deleted, it will also delete
+     * the corresponding account in the PJSUA-LIB.
+     */
+    virtual ~Account();
+
+    /**
+     * Create the account.
+     *
+     * @param cfg		The account config.
+     * @param make_default	Make this the default account.
+     */
+    void create(const AccountConfig &cfg,
+                bool make_default=false) throw(Error);
+
+    /**
+     * Modify the account to use the specified account configuration.
+     * Depending on the changes, this may cause unregistration or
+     * reregistration on the account.
+     *
+     * @param cfg 		New account config to be applied to the account.
+     */
+    void modify(const AccountConfig &acc) throw(Error);
+
+    /**
+     * Check if this account is still valid.
+     *
+     * @return			True if it is.
+     */
+    bool isValid() const;
+
+    /**
+     * Set this as default account to be used when incoming and outgoing
+     * requests don't match any accounts.
+     *
+     * @return			PJ_SUCCESS on success.
+     */
+    void setDefault() throw(Error);
+
+    /**
+     * Check if this account is the default account. Default account will be
+     * used for incoming and outgoing requests that don't match any other
+     * accounts.
+     *
+     * @return			True if this is the default account.
+     */
+    bool isDefault() const;
+
+    /**
+     * Get PJSUA-LIB account ID or index associated with this account.
+     *
+     * @return			Integer greater than or equal to zero.
+     */
+    int getId() const;
+
+    /**
+     * Get the Account class for the specified account Id.
+     *
+     * @param acc_id		The account ID to lookup
+     *
+     * @return			The Account instance or NULL if not found.
+     */
+    static Account *lookup(int acc_id);
+
+    /**
+     * Get account info.
+     *
+     * @return			Account info.
+     */
+    AccountInfo getInfo() const throw(Error);
+
+    /**
+     * Update registration or perform unregistration. Application normally
+     * only needs to call this function if it wants to manually update the
+     * registration or to unregister from the server.
+     *
+     * @param renew		If False, this will start unregistration
+     * 				process.
+     */
+    void setRegistration(bool renew) throw(Error);
+
+    /**
+     * Set or modify account's presence online status to be advertised to
+     * remote/presence subscribers. This would trigger the sending of
+     * outgoing NOTIFY request if there are server side presence subscription
+     * for this account, and/or outgoing PUBLISH if presence publication is
+     * enabled for this account.
+     *
+     * @param pres_st		Presence online status.
+     */
+    void setOnlineStatus(const AccountPresenceStatus &pres_st) throw(Error);
+
+    /**
+     * Lock/bind this account to a specific transport/listener. Normally
+     * application shouldn't need to do this, as transports will be selected
+     * automatically by the library according to the destination.
+     *
+     * When account is locked/bound to a specific transport, all outgoing
+     * requests from this account will use the specified transport (this
+     * includes SIP registration, dialog (call and event subscription), and
+     * out-of-dialog requests such as MESSAGE).
+     *
+     * Note that transport id may be specified in AccountConfig too.
+     *
+     * @param tp_id		The transport ID.
+     */
+    void setTransport(TransportId tp_id) throw(Error);
+
+public:
+    /*
+     * Callbacks
+     */
     /**
      * Notify application on incoming call.
@@ -1202,159 +1321,9 @@
 
 protected:
-    AccountCallback()
-    : acc(NULL)
-    {}
-
-private:
-    Account *acc;
-
-    /** Set the account. Must only be called by Account class */
-    void setAccount(Account *the_acc)
-    { acc = the_acc; }
-
-    friend class Account;
-};
-
-
-/**
- * @}  // PJSUA2_Acc_Data_Structure
- */
-
-/**
- * @addtogroup PJSUA2_ACC
- * @{
- */
-
-
-/**
- * Account.
- */
-class Account
-{
-public:
-    /**
-     * Constructor.
-     */
-    Account(AccountCallback *cb, Token user_data);
-
-    /**
-     * Destructor.
-     */
-    ~Account();
-
-    /**
-     * Create the account.
-     *
-     * @param cfg		The account config.
-     * @param make_default	Make this the default account.
-     */
-    void create(const AccountConfig &cfg,
-                bool make_default=false) throw(Error);
-
-    /**
-     * Modify the account to use the specified account configuration.
-     * Depending on the changes, this may cause unregistration or
-     * reregistration on the account.
-     *
-     * @param cfg 		New account config to be applied to the account.
-     */
-    void modify(const AccountConfig &acc) throw(Error);
-
-    /**
-     * Check if this account is still valid.
-     *
-     * @return			True if it is.
-     */
-    bool isValid() const;
-
-    /**
-     * Set this as default account to be used when incoming and outgoing
-     * requests don't match any accounts.
-     *
-     * @return			PJ_SUCCESS on success.
-     */
-    void setDefault() throw(Error);
-
-    /**
-     * Check if this account is the default account. Default account will be
-     * used for incoming and outgoing requests that don't match any other
-     * accounts.
-     *
-     * @return			True if this is the default account.
-     */
-    bool isDefault() const;
-
-    /**
-     * Get PJSUA-LIB account ID or index associated with this account.
-     *
-     * @return			Integer greater than or equal to zero.
-     */
-    int getIndex() const;
-
-    /**
-     * Set arbitrary data to be associated with the account.
-     *
-     * @param user_data		User/application data.
-     */
-    void setUserData(Token user_data);
-
-    /**
-     * Get the user data that was associated with the account.
-     *
-     * @return			The user data.
-     */
-    Token getUserData() const;
-
-    /**
-     * Get account info.
-     *
-     * @return			Account info.
-     */
-    AccountInfo getInfo() const throw(Error);
-
-    /**
-     * Update registration or perform unregistration. Application normally
-     * only needs to call this function if it wants to manually update the
-     * registration or to unregister from the server.
-     *
-     * @param renew		If False, this will start unregistration
-     * 				process.
-     */
-    void setRegistration(bool renew) throw(Error);
-
-    /**
-     * Set or modify account's presence online status to be advertised to
-     * remote/presence subscribers. This would trigger the sending of
-     * outgoing NOTIFY request if there are server side presence subscription
-     * for this account, and/or outgoing PUBLISH if presence publication is
-     * enabled for this account.
-     *
-     * @param pres_st		Presence online status.
-     */
-    void setOnlineStatus(const AccountPresenceStatus &pres_st) throw(Error);
-
-    /**
-     * Lock/bind this account to a specific transport/listener. Normally
-     * application shouldn't need to do this, as transports will be selected
-     * automatically by the library according to the destination.
-     *
-     * When account is locked/bound to a specific transport, all outgoing
-     * requests from this account will use the specified transport (this
-     * includes SIP registration, dialog (call and event subscription), and
-     * out-of-dialog requests such as MESSAGE).
-     *
-     * Note that transport id may be specified in AccountConfig too.
-     *
-     * @param tp_id		The transport ID.
-     */
-    void setTransport(TransportId tp_id) throw(Error);
-
-protected:
     friend class Endpoint;
 
 private:
     pjsua_acc_id 	 id;
-    AccountCallback 	*cb;
-    Token		 userData;
+    string		 tmpReason;	// for saving response's reason
 };
 
Index: pjproject/branches/projects/pjsua2/pjsip/include/pjsua2/endpoint.hpp
===================================================================
--- pjproject/branches/projects/pjsua2/pjsip/include/pjsua2/endpoint.hpp	(revision 4637)
+++ pjproject/branches/projects/pjsua2/pjsip/include/pjsua2/endpoint.hpp	(revision 4638)
@@ -43,5 +43,5 @@
 
 /**
- * Argument to EpCallback::onNatDetectionComplete() callback.
+ * Argument to Endpoint::onNatDetectionComplete() callback.
  */
 struct OnNatDetectionCompleteParam
@@ -73,5 +73,5 @@
 
 /**
- * Argument to EpCallback::onNatCheckStunServersComplete() callback.
+ * Argument to Endpoint::onNatCheckStunServersComplete() callback.
  */
 struct OnNatCheckStunServersCompleteParam
@@ -104,5 +104,5 @@
 
 /**
- * Parameter of EpCallback::OnTimer() callback.
+ * Parameter of Endpoint::onTimer() callback.
  */
 struct OnTimerParam
@@ -121,5 +121,5 @@
 
 /**
- * Parameter of EpCallback::onTransportState() callback.
+ * Parameter of Endpoint::onTransportState() callback.
  */
 struct OnTransportStateParam
@@ -142,5 +142,5 @@
 
 /**
- * Parameter of EpCallback::onSelectAccount() callback.
+ * Parameter of Endpoint::onSelectAccount() callback.
  */
 struct OnSelectAccountParam
@@ -159,75 +159,4 @@
     int			accountIndex;
 };
-
-//////////////////////////////////////////////////////////////////////////////
-
-/**
- * Interface for receiving callbacks from the library. Application inherits
- * this class and specify the instance when calling Endpoint::libInit().
- */
-class EpCallback
-{
-public:
-    /** Virtual destructor */
-    virtual ~EpCallback() {}
-
-    /**
-     * Callback when the Endpoint has finished performing NAT type
-     * detection that is initiated with Endpoint::natDetectType().
-     *
-     * @param prm	Callback parameters containing the detection
-     * 			result.
-     */
-    virtual void onNatDetectionComplete(
-			const OnNatDetectionCompleteParam &prm)
-    {}
-
-    /**
-     * Callback when the Endpoint has finished performing STUN server
-     * checking that is initiated with Endpoint::natCheckStunServers().
-     *
-     * @param prm	Callback parameters.
-     */
-    virtual void onNatCheckStunServersComplete(
-			const OnNatCheckStunServersCompleteParam &prm)
-    {}
-
-    /**
-     * This callback is called when transport state has changed.
-     *
-     * @param prm	Callback parameters.
-     */
-    virtual void onTransportState(
-			const OnTransportStateParam &prm)
-    {}
-
-    /**
-     * Callback when a timer has fired. The timer was scheduled by
-     * Endpoint::utilTimerSchedule().
-     *
-     * @param prm	Callback parameters.
-     */
-    virtual void onTimer(const OnTimerParam &prm)
-    {}
-
-    /**
-     * This callback can be used by application to override the account
-     * to be used to handle an incoming message. Initially, the account to
-     * be used will be calculated automatically by the library. This initial
-     * account will be used if application does not implement this callback,
-     * or application sets an invalid account upon returning from this
-     * callback.
-     *
-     * Note that currently the incoming messages requiring account assignment
-     * are INVITE, MESSAGE, SUBSCRIBE, and unsolicited NOTIFY. This callback
-     * may be called before the callback of the SIP event itself, i.e:
-     * incoming call, pager, subscription, or unsolicited-event.
-     *
-     * @param prm	Callback parameters.
-     */
-    virtual void onSelectAccount(OnSelectAccountParam &prm)
-    {}
-};
-
 
 //////////////////////////////////////////////////////////////////////////////
@@ -313,5 +242,5 @@
      *
      * If this is enabled, the library will respond 200/OK to the NOTIFY
-     * request and forward the request to EpCallback.onMwiInfo() callback.
+     * request and forward the request to Endpoint::onMwiInfo() callback.
      *
      * See also AccountMwiConfig.enabled.
@@ -407,6 +336,6 @@
 
     /**
-     * Custom log writer, if required. If specified, the instance of LogWriter
-     * must be kept alive througout the duration of the application.
+     * Custom log writer, if required. This instance will be destroyed
+     * by the endpoint when the endpoint is destroyed.
      */
     LogWriter		*writer;
@@ -655,8 +584,11 @@
 public:
     /** Retrieve the singleton instance of the endpoint */
-    static Endpoint &instance();
-
-    /* For testing */
-    void testException() throw(Error);
+    static Endpoint &instance() throw(Error);
+
+    /** Default constructor */
+    Endpoint();
+
+    /** Virtual destructor */
+    virtual ~Endpoint();
 
 
@@ -688,11 +620,6 @@
      *
      * @param prmEpConfig	Endpoint configurations
-     * @param prmCb		Optional callback to receive events from the
-     * 				library. If specified, this instance must be
-     * 				kept alive throughout the lifetime of the
-     * 				library.
-     */
-    void libInit( const EpConfig &prmEpConfig,
-                  EpCallback *prmCb = NULL) throw(Error);
+     */
+    void libInit( const EpConfig &prmEpConfig) throw(Error);
 
     /**
@@ -770,5 +697,5 @@
     /**
      * Schedule a timer with the specified interval and user data. When the
-     * interval elapsed, EpCallback::OnTimer() callback will be
+     * interval elapsed, Endpoint::onTimer() callback will be
      * called. Note that the callback may be executed by different thread,
      * depending on whether worker thread is enabled or not.
@@ -803,5 +730,5 @@
      * This is a utility function to detect NAT type in front of this endpoint.
      * Once invoked successfully, this function will complete asynchronously
-     * and report the result in EpCallback::onNatDetectionComplete().
+     * and report the result in Endpoint::onNatDetectionComplete().
      *
      * After NAT has been detected and the callback is called, application can
@@ -817,5 +744,5 @@
      * Get the NAT type as detected by #natDetectType() function. This
      * function will only return useful NAT type after #natDetectType()
-     * has completed successfully and EpCallback::onNatDetectionComplete()
+     * has completed successfully and Endpoint::onNatDetectionComplete()
      * callback has been called.
      *
@@ -926,17 +853,72 @@
     void transportClose(TransportId id) throw(Error);
 
+public:
+    /*
+     * Overrideables callbacks
+     */
+
+    /**
+     * Callback when the Endpoint has finished performing NAT type
+     * detection that is initiated with Endpoint::natDetectType().
+     *
+     * @param prm	Callback parameters containing the detection
+     * 			result.
+     */
+    virtual void onNatDetectionComplete(
+			const OnNatDetectionCompleteParam &prm)
+    {}
+
+    /**
+     * Callback when the Endpoint has finished performing STUN server
+     * checking that is initiated with Endpoint::natCheckStunServers().
+     *
+     * @param prm	Callback parameters.
+     */
+    virtual void onNatCheckStunServersComplete(
+			const OnNatCheckStunServersCompleteParam &prm)
+    {}
+
+    /**
+     * This callback is called when transport state has changed.
+     *
+     * @param prm	Callback parameters.
+     */
+    virtual void onTransportState(
+			const OnTransportStateParam &prm)
+    {}
+
+    /**
+     * Callback when a timer has fired. The timer was scheduled by
+     * Endpoint::utilTimerSchedule().
+     *
+     * @param prm	Callback parameters.
+     */
+    virtual void onTimer(const OnTimerParam &prm)
+    {}
+
+    /**
+     * This callback can be used by application to override the account
+     * to be used to handle an incoming message. Initially, the account to
+     * be used will be calculated automatically by the library. This initial
+     * account will be used if application does not implement this callback,
+     * or application sets an invalid account upon returning from this
+     * callback.
+     *
+     * Note that currently the incoming messages requiring account assignment
+     * are INVITE, MESSAGE, SUBSCRIBE, and unsolicited NOTIFY. This callback
+     * may be called before the callback of the SIP event itself, i.e:
+     * incoming call, pager, subscription, or unsolicited-event.
+     *
+     * @param prm	Callback parameters.
+     */
+    virtual void onSelectAccount(OnSelectAccountParam &prm)
+    {}
+
 
 private:
-    /* Anybody else can't instantiate Endpoint */
-    Endpoint();
-
-private:
-    /* Custom writer, if any */
-    LogWriter	*writer;
-    EpCallback	*epCallback;
-
-    /*
-     * Callbacks (static)
-     */
+    static Endpoint	*instance_;	// static instance
+    LogWriter		*writer;	// Custom writer, if any
+
+    /* Endpoint static callbacks */
     static void logFunc(int level, const char *data, int len);
     static void stun_resolve_cb(const pj_stun_resolve_result *result);
@@ -947,4 +929,53 @@
     				   pjsip_transport_state state,
     				   const pjsip_transport_state_info *info);
+
+private:
+    /*
+     * Account
+     */
+    static Account	*lookupAcc(int acc_id, const char *op);
+
+    /* static callbacks */
+    static void on_incoming_call(pjsua_acc_id acc_id,
+                                 pjsua_call_id call_id,
+                                 pjsip_rx_data *rdata);
+    static void on_reg_started(pjsua_acc_id acc_id,
+                               pj_bool_t renew);
+    static void on_reg_state2(pjsua_acc_id acc_id,
+                              pjsua_reg_info *info);
+    static void on_incoming_subscribe(pjsua_acc_id acc_id,
+				      pjsua_srv_pres *srv_pres,
+				      pjsua_buddy_id buddy_id,
+				      const pj_str_t *from,
+				      pjsip_rx_data *rdata,
+				      pjsip_status_code *code,
+				      pj_str_t *reason,
+				      pjsua_msg_data *msg_data);
+    static void on_pager2(pjsua_call_id call_id,
+                          const pj_str_t *from,
+                          const pj_str_t *to,
+                          const pj_str_t *contact,
+                          const pj_str_t *mime_type,
+                          const pj_str_t *body,
+                          pjsip_rx_data *rdata,
+                          pjsua_acc_id acc_id);
+    static void on_pager_status2(pjsua_call_id call_id,
+				 const pj_str_t *to,
+				 const pj_str_t *body,
+				 void *user_data,
+				 pjsip_status_code status,
+				 const pj_str_t *reason,
+				 pjsip_tx_data *tdata,
+				 pjsip_rx_data *rdata,
+				 pjsua_acc_id acc_id);
+    static void on_typing2(pjsua_call_id call_id,
+                           const pj_str_t *from,
+                           const pj_str_t *to,
+                           const pj_str_t *contact,
+                           pj_bool_t is_typing,
+                           pjsip_rx_data *rdata,
+                           pjsua_acc_id acc_id);
+    static void on_mwi_info(pjsua_acc_id acc_id,
+                            pjsua_mwi_info *mwi_info);
 };
 
Index: pjproject/branches/projects/pjsua2/pjsip/include/pjsua2/types.hpp
===================================================================
--- pjproject/branches/projects/pjsua2/pjsip/include/pjsua2/types.hpp	(revision 4637)
+++ pjproject/branches/projects/pjsua2/pjsip/include/pjsua2/types.hpp	(revision 4638)
@@ -71,9 +71,8 @@
 
 /*
- * Forward declaration of Account, AccountCallback, AccountConfig, to be used
+ * Forward declaration of Account, AccountConfig, to be used
  * by Endpoint.
  */
 class Account;
-class AccountCallback;
 class AccountConfig;
 
@@ -522,4 +521,9 @@
      */
     unsigned		srcPort;
+
+    /**
+     * Construct from PJSIP's pjsip_rx_data
+     */
+    void fromPj(pjsip_rx_data &rdata);
 };
 
Index: pjproject/branches/projects/pjsua2/pjsip/src/pjsua2/account.cpp
===================================================================
--- pjproject/branches/projects/pjsua2/pjsip/src/pjsua2/account.cpp	(revision 4637)
+++ pjproject/branches/projects/pjsua2/pjsip/src/pjsua2/account.cpp	(revision 4638)
@@ -351,13 +351,18 @@
 ///////////////////////////////////////////////////////////////////////////////
 
-Account::Account(AccountCallback *param_cb, Token user_data)
-: id(PJSUA_INVALID_ID), cb(param_cb), userData(user_data)
-{
-    cb->setAccount(this);
+Account::Account()
+: id(PJSUA_INVALID_ID)
+{
 }
 
 Account::~Account()
 {
-    delete cb;
+    /* If this instance is deleted, also delete the corresponding account in
+     * PJSUA library.
+     */
+    if (isValid() && pjsua_get_state() < PJSUA_STATE_CLOSING) {
+	PJSUA2_CHECK_EXPR( pjsua_acc_set_user_data(id, NULL) );
+	PJSUA2_CHECK_EXPR( pjsua_acc_del(id) );
+    }
 }
 
@@ -367,4 +372,5 @@
     pjsua_acc_config pj_acc_cfg = acc_cfg.toPj();
 
+    pj_acc_cfg.user_data = (void*)this;
     PJSUA2_CHECK_EXPR( pjsua_acc_add(&pj_acc_cfg, make_default, &id) );
 }
@@ -392,17 +398,12 @@
 }
 
-int Account::getIndex() const
+int Account::getId() const
 {
     return id;
 }
 
-void Account::setUserData(Token user_data)
-{
-    userData = user_data;
-}
-
-Token Account::getUserData() const
-{
-    return userData;
+Account *Account::lookup(int acc_id)
+{
+    return (Account*)pjsua_acc_get_user_data(acc_id);
 }
 
Index: pjproject/branches/projects/pjsua2/pjsip/src/pjsua2/endpoint.cpp
===================================================================
--- pjproject/branches/projects/pjsua2/pjsip/src/pjsua2/endpoint.cpp	(revision 4637)
+++ pjproject/branches/projects/pjsua2/pjsip/src/pjsua2/endpoint.cpp	(revision 4638)
@@ -18,4 +18,5 @@
  */
 #include <pjsua2/endpoint.hpp>
+#include <pjsua2/account.hpp>
 #include "util.hpp"
 
@@ -34,4 +35,5 @@
 };
 
+Endpoint *Endpoint::instance_;
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -210,19 +212,31 @@
  */
 Endpoint::Endpoint()
-: writer(NULL), epCallback(NULL)
-{
-}
-
-Endpoint& Endpoint::instance()
-{
-    static Endpoint lib_;
-    return lib_;
-}
-
-void Endpoint::testException() throw(Error)
-{
-    PJSUA2_CHECK_RAISE_ERROR(PJ_EINVALIDOP);
-}
-
+: writer(NULL)
+{
+    if (instance_) {
+	PJSUA2_RAISE_ERROR(PJ_EEXISTS);
+    }
+
+    instance_ = this;
+}
+
+Endpoint& Endpoint::instance() throw(Error)
+{
+    if (!instance_) {
+	PJSUA2_RAISE_ERROR(PJ_ENOTFOUND);
+    }
+    return *instance_;
+}
+
+Endpoint::~Endpoint()
+{
+    try {
+	libDestroy();
+    } catch (Error &err) {
+	// Ignore
+    }
+    delete writer;
+    instance_ = NULL;
+}
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -250,5 +264,5 @@
     Endpoint &ep = Endpoint::instance();
 
-    if (!ep.epCallback || !res)
+    if (!res)
 	return;
 
@@ -265,5 +279,5 @@
     }
 
-    ep.epCallback->onNatCheckStunServersComplete(prm);
+    ep.onNatCheckStunServersComplete(prm);
 }
 
@@ -274,8 +288,8 @@
     UserTimer *ut = (UserTimer*) entry->user_data;
 
-    if (!ep.epCallback || ut->signature != TIMER_SIGNATURE)
-	return;
-
-    ep.epCallback->onTimer(ut->prm);
+    if (ut->signature != TIMER_SIGNATURE)
+	return;
+
+    ep.onTimer(ut->prm);
 }
 
@@ -284,5 +298,5 @@
     Endpoint &ep = Endpoint::instance();
 
-    if (!ep.epCallback || !res)
+    if (!res)
 	return;
 
@@ -294,5 +308,5 @@
     prm.natTypeName = res->nat_type_name;
 
-    ep.epCallback->onNatDetectionComplete(prm);
+    ep.onNatDetectionComplete(prm);
 }
 
@@ -303,7 +317,4 @@
     Endpoint &ep = Endpoint::instance();
 
-    if (!ep.epCallback)
-	return;
-
     OnTransportStateParam prm;
 
@@ -312,6 +323,221 @@
     prm.lastError = info ? info->status : PJ_SUCCESS;
 
-    ep.epCallback->onTransportState(prm);
-}
+    ep.onTransportState(prm);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+/*
+ * Account static callbacks
+ */
+
+Account *Endpoint::lookupAcc(int acc_id, const char *op)
+{
+    Account *acc = Account::lookup(acc_id);
+    if (!acc) {
+	PJ_LOG(1,(THIS_FILE,
+		  "Error: cannot find Account instance for account id %d in "
+		  "%s", acc_id, op));
+    }
+
+    return acc;
+}
+
+void Endpoint::on_incoming_call(pjsua_acc_id acc_id, pjsua_call_id call_id,
+                                pjsip_rx_data *rdata)
+{
+    Account *acc = lookupAcc(acc_id, "on_incoming_call()");
+    if (!acc) {
+	pjsua_call_hangup(call_id, PJSIP_SC_INTERNAL_SERVER_ERROR, NULL, NULL);
+	return;
+    }
+
+    /* call callback */
+    OnIncomingCallParam prm;
+    prm.callId = call_id;
+    prm.rdata.fromPj(*rdata);
+
+    acc->onIncomingCall(prm);
+
+    /* disconnect if callback doesn't handle the call */
+    pjsua_call_info ci;
+
+    pjsua_call_get_info(call_id, &ci);
+    if (!pjsua_call_get_user_data(call_id) &&
+	ci.state != PJSIP_INV_STATE_DISCONNECTED)
+    {
+	pjsua_call_hangup(call_id, PJSIP_SC_INTERNAL_SERVER_ERROR, NULL, NULL);
+    }
+}
+
+void Endpoint::on_reg_started(pjsua_acc_id acc_id, pj_bool_t renew)
+{
+    Account *acc = lookupAcc(acc_id, "on_reg_started()");
+    if (!acc) {
+	return;
+    }
+
+    OnRegStartedParam prm;
+    prm.renew = renew;
+    acc->onRegStarted(prm);
+}
+
+void Endpoint::on_reg_state2(pjsua_acc_id acc_id, pjsua_reg_info *info)
+{
+    Account *acc = lookupAcc(acc_id, "on_reg_state2()");
+    if (!acc) {
+	return;
+    }
+
+    OnRegStateParam prm;
+    prm.status		= info->cbparam->status;
+    prm.code 		= (pjsip_status_code) info->cbparam->code;
+    prm.reason		= pj2Str(info->cbparam->reason);
+    if (info->cbparam->rdata)
+	prm.rdata.fromPj(*info->cbparam->rdata);
+    prm.expiration	= info->cbparam->expiration;
+
+    acc->onRegState(prm);
+}
+
+void Endpoint::on_incoming_subscribe(pjsua_acc_id acc_id,
+                                     pjsua_srv_pres *srv_pres,
+                                     pjsua_buddy_id buddy_id,
+                                     const pj_str_t *from,
+                                     pjsip_rx_data *rdata,
+                                     pjsip_status_code *code,
+                                     pj_str_t *reason,
+                                     pjsua_msg_data *msg_data)
+{
+    Account *acc = lookupAcc(acc_id, "on_incoming_subscribe()");
+    if (!acc) {
+	/* default behavior should apply */
+	return;
+    }
+
+    OnIncomingSubscribeParam prm;
+    prm.fromUri 	= pj2Str(*from);
+    prm.rdata.fromPj(*rdata);
+    prm.code		= *code;
+    prm.reason		= pj2Str(*reason);
+
+    acc->onIncomingSubscribe(prm);
+
+    *code = prm.code;
+    acc->tmpReason = prm.reason;
+    *reason = str2Pj(acc->tmpReason);
+    // TODO:
+    //	apply msg_data
+}
+
+void Endpoint::on_pager2(pjsua_call_id call_id,
+                         const pj_str_t *from,
+                         const pj_str_t *to,
+                         const pj_str_t *contact,
+                         const pj_str_t *mime_type,
+                         const pj_str_t *body,
+                         pjsip_rx_data *rdata,
+                         pjsua_acc_id acc_id)
+{
+    OnInstantMessageParam prm;
+    prm.fromUri		= pj2Str(*from);
+    prm.toUri		= pj2Str(*to);
+    prm.contactUri	= pj2Str(*contact);
+    prm.contentType	= pj2Str(*mime_type);
+    prm.msgBody		= pj2Str(*body);
+    prm.rdata.fromPj(*rdata);
+
+    if (call_id != PJSUA_INVALID_ID) {
+	// TODO:
+	//	handle call pager
+	return;
+    } else {
+	Account *acc = lookupAcc(acc_id, "on_pager2()");
+	if (!acc) {
+	    /* Ignored */
+	    return;
+	}
+
+	acc->onInstantMessage(prm);
+    }
+}
+
+void Endpoint::on_pager_status2( pjsua_call_id call_id,
+				 const pj_str_t *to,
+				 const pj_str_t *body,
+				 void *user_data,
+				 pjsip_status_code status,
+				 const pj_str_t *reason,
+				 pjsip_tx_data *tdata,
+				 pjsip_rx_data *rdata,
+				 pjsua_acc_id acc_id)
+{
+    OnInstantMessageStatusParam prm;
+    prm.userData	= user_data;
+    prm.toUri		= pj2Str(*to);
+    prm.msgBody		= pj2Str(*body);
+    prm.status		= status;
+    prm.reason		= pj2Str(*reason);
+    if (rdata)
+	prm.rdata.fromPj(*rdata);
+
+    if (call_id != PJSUA_INVALID_ID) {
+	// TODO:
+	//	handle call pager
+    } else {
+	Account *acc = lookupAcc(acc_id, "on_pager_status2()");
+	if (!acc) {
+	    /* Ignored */
+	    return;
+	}
+
+	acc->onInstantMessageStatus(prm);
+    }
+}
+
+void Endpoint::on_typing2( pjsua_call_id call_id,
+			   const pj_str_t *from,
+			   const pj_str_t *to,
+			   const pj_str_t *contact,
+			   pj_bool_t is_typing,
+			   pjsip_rx_data *rdata,
+			   pjsua_acc_id acc_id)
+{
+    OnTypingIndicationParam prm;
+    prm.fromUri		= pj2Str(*from);
+    prm.toUri		= pj2Str(*to);
+    prm.contactUri	= pj2Str(*contact);
+    prm.isTyping	= is_typing != 0;
+    prm.rdata.fromPj(*rdata);
+
+    if (call_id != PJSUA_INVALID_ID) {
+	// TODO:
+	//	handle call indication
+    } else {
+	Account *acc = lookupAcc(acc_id, "on_typing2()");
+	if (!acc) {
+	    /* Ignored */
+	    return;
+	}
+
+	acc->onTypingIndication(prm);
+    }
+}
+
+void Endpoint::on_mwi_info(pjsua_acc_id acc_id,
+                           pjsua_mwi_info *mwi_info)
+{
+    OnMwiInfoParam prm;
+    prm.state	= pjsip_evsub_get_state(mwi_info->evsub);
+    prm.rdata.fromPj(*mwi_info->rdata);
+
+    Account *acc = lookupAcc(acc_id, "on_mwi_info()");
+    if (!acc) {
+	/* Ignored */
+	return;
+    }
+
+    acc->onMwiInfo(prm);
+}
+
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -321,8 +547,5 @@
 void Endpoint::libCreate() throw(Error)
 {
-    pj_status_t status;
-
-    status = pjsua_create();
-    PJSUA2_CHECK_RAISE_ERROR(status);
+    PJSUA2_CHECK_EXPR( pjsua_create() );
 }
 
@@ -332,11 +555,9 @@
 }
 
-void Endpoint::libInit( const EpConfig &prmEpConfig,
-                        EpCallback *prmCb) throw(Error)
+void Endpoint::libInit(const EpConfig &prmEpConfig) throw(Error)
 {
     pjsua_config ua_cfg;
     pjsua_logging_config log_cfg;
     pjsua_media_config med_cfg;
-    pj_status_t status;
 
     ua_cfg = prmEpConfig.uaConfig.toPj();
@@ -352,28 +573,33 @@
     /* Setup UA callbacks */
     pj_bzero(&ua_cfg.cb, sizeof(ua_cfg.cb));
-    ua_cfg.cb.on_nat_detect = &Endpoint::on_nat_detect;
+    ua_cfg.cb.on_nat_detect 	= &Endpoint::on_nat_detect;
     ua_cfg.cb.on_transport_state = &Endpoint::on_transport_state;
 
+    ua_cfg.cb.on_incoming_call	= &Endpoint::on_incoming_call;
+    ua_cfg.cb.on_reg_started	= &Endpoint::on_reg_started;
+    ua_cfg.cb.on_reg_state2	= &Endpoint::on_reg_state2;
+    ua_cfg.cb.on_incoming_subscribe = &Endpoint::on_incoming_subscribe;
+    ua_cfg.cb.on_pager2		= &Endpoint::on_pager2;
+    ua_cfg.cb.on_pager_status2	= &Endpoint::on_pager_status2;
+    ua_cfg.cb.on_typing2	= &Endpoint::on_typing2;
+    ua_cfg.cb.on_mwi_info	= &Endpoint::on_mwi_info;
+
     /* Init! */
-    status = pjsua_init(&ua_cfg, &log_cfg, &med_cfg);
-    PJSUA2_CHECK_RAISE_ERROR(status);
+    PJSUA2_CHECK_EXPR( pjsua_init(&ua_cfg, &log_cfg, &med_cfg) );
 }
 
 void Endpoint::libStart() throw(Error)
 {
+    PJSUA2_CHECK_EXPR(pjsua_start());
+}
+
+void Endpoint::libDestroy(unsigned flags) throw(Error)
+{
     pj_status_t status;
 
-    status = pjsua_start();
-    PJSUA2_CHECK_RAISE_ERROR(status);
-}
-
-void Endpoint::libDestroy(unsigned flags) throw(Error)
-{
-    pj_status_t status;
-
     status = pjsua_destroy2(flags);
 
+    delete this->writer;
     this->writer = NULL;
-    this->epCallback = NULL;
 
     if (pj_log_get_log_func() == &Endpoint::logFunc) {
@@ -469,8 +695,6 @@
     pj_ssl_cipher ciphers[64];
     unsigned count = PJ_ARRAY_SIZE(ciphers);
-    pj_status_t status;
-
-    status = pj_ssl_cipher_get_availables(ciphers, &count);
-    PJSUA2_CHECK_RAISE_ERROR(status);
+
+    PJSUA2_CHECK_EXPR( pj_ssl_cipher_get_availables(ciphers, &count) );
 
     return IntVector(ciphers, ciphers + count);
@@ -486,8 +710,5 @@
 void Endpoint::natDetectType(void) throw(Error)
 {
-    pj_status_t status;
-
-    status = pjsua_detect_nat_type();
-    PJSUA2_CHECK_RAISE_ERROR(status);
+    PJSUA2_CHECK_EXPR( pjsua_detect_nat_type() );
 }
 
@@ -495,8 +716,6 @@
 {
     pj_stun_nat_type type;
-    pj_status_t status;
-
-    status = pjsua_get_nat_type(&type);
-    PJSUA2_CHECK_RAISE_ERROR(status);
+
+    PJSUA2_CHECK_EXPR( pjsua_get_nat_type(&type) );
 
     return type;
@@ -509,5 +728,4 @@
     pj_str_t srv[MAX_STUN_SERVERS];
     unsigned i, count = 0;
-    pj_status_t status;
 
     for (i=0; i<servers.size() && i<MAX_STUN_SERVERS; ++i) {
@@ -517,7 +735,6 @@
     }
 
-    status = pjsua_resolve_stun_servers(count, srv, wait, token,
-    					&Endpoint::stun_resolve_cb);
-    PJSUA2_CHECK_RAISE_ERROR(status);
+    PJSUA2_CHECK_EXPR(pjsua_resolve_stun_servers(count, srv, wait, token,
+                                                 &Endpoint::stun_resolve_cb) );
 }
 
@@ -525,8 +742,5 @@
                                          bool notify_cb) throw(Error)
 {
-    pj_status_t status;
-
-    status = pjsua_cancel_stun_resolution(token, notify_cb);
-    PJSUA2_CHECK_RAISE_ERROR(status);
+    PJSUA2_CHECK_EXPR( pjsua_cancel_stun_resolution(token, notify_cb) );
 }
 
@@ -540,9 +754,7 @@
     pjsua_transport_config tcfg;
     pjsua_transport_id tid;
-    pj_status_t status;
 
     tcfg = cfg.toPj();
-    status = pjsua_transport_create(type, &tcfg, &tid);
-    PJSUA2_CHECK_RAISE_ERROR(status);
+    PJSUA2_CHECK_EXPR( pjsua_transport_create(type, &tcfg, &tid) );
 
     return tid;
@@ -553,8 +765,6 @@
     pjsua_transport_id tids[32];
     unsigned count = PJ_ARRAY_SIZE(tids);
-    pj_status_t status;
-
-    status = pjsua_enum_transports(tids, &count);
-    PJSUA2_CHECK_RAISE_ERROR(status);
+
+    PJSUA2_CHECK_EXPR( pjsua_enum_transports(tids, &count) );
 
     return IntVector(tids, tids+count);
@@ -564,8 +774,6 @@
 {
     pjsua_transport_info tinfo;
-    pj_status_t status;
-
-    status = pjsua_transport_get_info(id, &tinfo);
-    PJSUA2_CHECK_RAISE_ERROR(status);
+
+    PJSUA2_CHECK_EXPR( pjsua_transport_get_info(id, &tinfo) );
 
     return TransportInfo(tinfo);
@@ -574,18 +782,12 @@
 void Endpoint::transportSetEnable(TransportId id, bool enabled) throw(Error)
 {
-    pj_status_t status;
-
-    status = pjsua_transport_set_enable(id, enabled);
-    PJSUA2_CHECK_RAISE_ERROR(status);
+    PJSUA2_CHECK_EXPR( pjsua_transport_set_enable(id, enabled) );
 }
 
 void Endpoint::transportClose(TransportId id) throw(Error)
 {
-    pj_status_t status;
-
-    status = pjsua_transport_close(id, PJ_FALSE);
-    PJSUA2_CHECK_RAISE_ERROR(status);
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
+    PJSUA2_CHECK_EXPR( pjsua_transport_close(id, PJ_FALSE) );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
Index: pjproject/branches/projects/pjsua2/pjsip/src/pjsua2/types.cpp
===================================================================
--- pjproject/branches/projects/pjsua2/pjsip/src/pjsua2/types.cpp	(revision 4637)
+++ pjproject/branches/projects/pjsua2/pjsip/src/pjsua2/types.cpp	(revision 4638)
@@ -214,4 +214,14 @@
 ///////////////////////////////////////////////////////////////////////////////
 
+void SipRxData::fromPj(pjsip_rx_data &rdata)
+{
+    info	= pjsip_rx_data_get_info(&rdata);
+    wholeMsg	= string(rdata.msg_info.msg_buf, rdata.msg_info.len);
+    srcIp	= rdata.pkt_info.src_name;
+    srcPort	= rdata.pkt_info.src_port;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
 void SipHeader::fromPj(const pjsip_hdr *hdr) throw(Error)
 {
