The code is a bit rough in that it needs a voicemail call number so that
when you hit the voicemail notifier it actually goes to your mailbox
instead of the sipdroid dial something dialogue. It also looks like we
could share the authentication code between the subscribe and register
messages (this would give subscribe proxy auth as well).
James
---
Index: src/org/sipdroid/sipua/SipdroidEngine.java
===================================================================
--- src/org/sipdroid/sipua/SipdroidEngine.java (revision 329)
+++ src/org/sipdroid/sipua/SipdroidEngine.java (working copy)
@@ -212,6 +212,18 @@
wl.release();
}
+ public void onMWIUpdate(boolean voicemail, int number) {
+ if (voicemail) {
+ String msgs = getUIContext().getString(R.string.voicemail);
+ if (number != 0) {
+ msgs = msgs + ": " + number;
+ }
+ Receiver.onText(Receiver.MWI_NOTIFICATION, msgs,android.R.drawable.stat_notify_voicemail,0);
+ } else {
+ Receiver.onText(Receiver.MWI_NOTIFICATION, null, 0,0);
+ }
+ }
+
static long lasthalt;
/** When a UA failed on (un)registering. */
Index: src/org/sipdroid/sipua/RegisterAgent.java
===================================================================
--- src/org/sipdroid/sipua/RegisterAgent.java (revision 329)
+++ src/org/sipdroid/sipua/RegisterAgent.java (working copy)
@@ -27,6 +27,8 @@
import org.sipdroid.sipua.ui.Sipdroid;
import org.zoolu.sip.address.NameAddress;
import org.zoolu.sip.authentication.DigestAuthentication;
+import org.zoolu.sip.dialog.SubscriberDialog;
+import org.zoolu.sip.dialog.SubscriberDialogListener;
import org.zoolu.sip.header.AuthorizationHeader;
import org.zoolu.sip.header.ContactHeader;
import org.zoolu.sip.header.ExpiresHeader;
@@ -44,12 +46,13 @@
import org.zoolu.sip.transaction.TransactionClientListener;
import org.zoolu.tools.Log;
import org.zoolu.tools.LogLevel;
+import org.zoolu.tools.Parser;
/**
* Register User Agent. It registers (one time or periodically) a contact
* address with a registrar server.
*/
-public class RegisterAgent implements TransactionClientListener {
+public class RegisterAgent implements TransactionClientListener, SubscriberDialogListener {
/** Max number of registration attempts. */
static final int MAX_ATTEMPTS = 3;
@@ -103,6 +106,10 @@
UserAgentProfile user_profile;
+ SubscriberDialog sd;
+ Message currentSubscribeMessage;
+ public final int SUBSCRIPTION_EXPIRES = 184000;
+
/**
* Creates a new RegisterAgent with authentication credentials (i.e.
* username, realm, and passwd).
@@ -223,9 +230,151 @@
/** Unregister with the registrar server */
public boolean unregister() {
+ stopMWI();
return register(0);
}
+ void stopMWI()
+ {
+ if (sd != null) {
+ synchronized (sd) {
+ sd.notify();
+ }
+ }
+ listener.onMWIUpdate(false, 0);
+ }
+
+ Message getSubscribeMessage(boolean current)
+ {
+ String empty = null;
+ Message req;
+
+ // Need to restart subscriber dialogue state engine
+ if (sd != null) {
+ synchronized (sd) {
+ sd.notify();
+ }
+ }
+ sd = new SubscriberDialog(sip_provider, "message-summary", "", this);
+ if (current) {
+ req = currentSubscribeMessage;
+ req.setCSeqHeader(req.getCSeqHeader().incSequenceNumber());
+ } else {
+ req = MessageFactory.createSubscribeRequest(sip_provider,
+ target.getAddress(), target, target,
+ contact, sd.getEvent(),
+ sd.getId(), empty, empty);
+ }
+ req.setExpiresHeader(new ExpiresHeader(SUBSCRIPTION_EXPIRES));
+ currentSubscribeMessage = req;
+ return req;
+ }
+
+
+ void startMWI()
+ {
+ Message req = getSubscribeMessage(false);
+ sd.subscribe(req);
+ }
+
+ void delayStartMWI()
+ {
+ Thread t = new Thread(new Runnable() {
+ public void run() {
+ Object o = new Object();
+ try {
+ synchronized (o) {
+ o.wait(10000);
+ }
+ } catch (Exception E) {
+ }
+ startMWI();
+ }
+ });
+ t.start();
+ }
+
+ // **************** Subscription callback functions *****************
+ public void onDlgSubscriptionSuccess(SubscriberDialog dialog, int code,
+ String reason, Message resp)
+ {
+ final int expires;
+ if (resp.hasExpiresHeader()) {
+ expires = resp.getExpiresHeader().getDeltaSeconds();
+ } else {
+ expires = SUBSCRIPTION_EXPIRES;
+ }
+ Thread t = new Thread(new Runnable() {
+ public void run() {
+ try {
+ synchronized (sd) {
+ sd.wait(expires*1000);
+ }
+ startMWI();
+ } catch(Exception E) {
+ }
+ }
+ });
+ t.start();
+ }
+
+ public void onDlgSubscriptionFailure(SubscriberDialog dialog, int code,
+ String reason, Message resp)
+ {
+ if (code == 401) {
+ Message req = getSubscribeMessage(true);
+ WwwAuthenticateHeader wah = resp.getWwwAuthenticateHeader();
+ String qop_options = wah.getQopOptionsParam();
+
+
+ qop = (qop_options != null) ? "auth" : null;
+
+ AuthorizationHeader ah = (new DigestAuthentication(
+ SipMethods.SUBSCRIBE, req.getRequestLine().getAddress()
+ .toString(), wah, qop, null, username, passwd))
+ .getAuthorizationHeader();
+ req.setAuthorizationHeader(ah);
+ sd.subscribe(req);
+ } else {
+ delayStartMWI();
+ }
+ }
+
+ public void onDlgSubscribeTimeout(SubscriberDialog dialog)
+ {
+ delayStartMWI();
+ }
+
+ public void onDlgSubscriptionTerminated(SubscriberDialog dialog)
+ {
+ startMWI();
+ }
+
+ public void onDlgNotify(SubscriberDialog dialog, NameAddress target,
+ NameAddress notifier, NameAddress contact, String state,
+ String content_type, String body, Message msg)
+ {
+ Parser p = new Parser(body);
+ final char[] propertysep = { ':', '\r', '\n' };
+ final char[] vmailsep = { '/' };
+ boolean voicemail = false;
+ int nummsg = 0;
+ while (p.hasMore()) {
+ String property = p.getWord(propertysep);
+ p.skipChar();
+ p.skipWSP();
+ String value = p.getWord(p.CRLF);
+ if (property.equalsIgnoreCase("Messages-Waiting") && value.equalsIgnoreCase("yes")) {
+ voicemail = true;
+ } else if (property.equalsIgnoreCase("Voice-Message")) {
+ Parser np = new Parser(value);
+ String num = np.getWord(vmailsep);
+ nummsg = Integer.parseInt(num);
+ }
+ }
+ listener.onMWIUpdate(voicemail, nummsg);
+ }
+
// **************** Transaction callback functions *****************
/** Callback function called when client sends back a failure response. */
@@ -274,6 +423,7 @@
if (listener != null)
{
listener.onUaRegistrationSuccess(this, target, contact, result);
+ startMWI();
Receiver.reRegister(expires);
}
}
@@ -306,6 +456,7 @@
{
listener.onUaRegistrationFailure(this, target, contact,
result);
+ stopMWI();
Receiver.reRegister(1000);
}
}
@@ -316,6 +467,7 @@
{
listener.onUaRegistrationFailure(this, target, contact,
result);
+ stopMWI();
}
}
@@ -412,6 +564,7 @@
{
listener.onUaRegistrationFailure(this, target, contact,
"Timeout");
+ stopMWI();
Receiver.reRegister(1000);
}
}
@@ -422,6 +575,7 @@
{
listener.onUaRegistrationFailure(this, target, contact,
"Timeout");
+ stopMWI();
}
}
}
Index: src/org/sipdroid/sipua/RegisterAgentListener.java
===================================================================
--- src/org/sipdroid/sipua/RegisterAgentListener.java (revision 329)
+++ src/org/sipdroid/sipua/RegisterAgentListener.java (working copy)
@@ -29,6 +29,8 @@
public void onUaRegistrationSuccess(RegisterAgent ra, NameAddress target,
NameAddress contact, String result);
+ public void onMWIUpdate(boolean voicemail, int number);
+
/** When a UA failed on (un)registering. */
public void onUaRegistrationFailure(RegisterAgent ra, NameAddress target,
NameAddress contact, String result);
Index: src/org/sipdroid/sipua/ui/Receiver.java
===================================================================
--- src/org/sipdroid/sipua/ui/Receiver.java (revision 329)
+++ src/org/sipdroid/sipua/ui/Receiver.java (working copy)
@@ -69,6 +69,7 @@
public final static int CALL_NOTIFICATION = 2;
public final static int MISSED_CALL_NOTIFICATION = 3;
public final static int AUTO_ANSWER_NOTIFICATION = 4;
+ public final static int MWI_NOTIFICATION = 5;
final static long[] vibratePattern = {0,1000,1000};
Index: res/values/strings.xml
===================================================================
--- res/values/strings.xml (revision 329)
+++ res/values/strings.xml (working copy)
@@ -51,6 +51,8 @@
<string name="regok">Registered</string>
<string name="regfailed">Registration failed</string>
+<string name="voicemail">Message(s) Waiting</string>
+
<string name="auto_enabled">Auto-Answer/Speakerphone</string>
<string name="auto_disabled">Auto-Answer off</string>
<string name="hint">Called Party Address</string>
What's a google code id? (Google search doesn't turn up anything useful)
> When checking this in please add an advanced option (defaulting to on)
> for MWI display. I would like to be able to turn this off because I
> receive my voicemail over email and two notifications would be too
> much.
Sure thing ... I was debating adding this since some sip servers do
silly things with MWI subscriptions.
> Also please complete the patch to call to the voicemail number if the
> notification is clicked on.
Will do ... it's annoying me as I use the patch, so I will add this.
James
Oh ... ok, I really don't have one of those. I created a gmail account
for android and then disabled it again ... proliferation of mailbox
problems and all. The address above is what I use to login to the
google site, so it's likely what you need.
James
This version has a preference to disable using SIP MWI plus a setting
for the voicemail box to call when you click on the notification. This
patch also abstracts the authentication handling so both register and
subscribe can use it.
There was one problem that showed up in testing. It seems that during a
call, the onDlgSubscribeSuccess() notification gets called spuriously
(lots of times). I fixed this by simply tracking an alreadySubscribed
state and ignoring the notification of success if we're subscribed.
James
---
res/values/strings.xml | 6
res/xml/preferences.xml | 8
src/org/sipdroid/sipua/RegisterAgent.java | 189 ++++++++++++++++++++--
src/org/sipdroid/sipua/RegisterAgentListener.java | 2
src/org/sipdroid/sipua/SipdroidEngine.java | 16 +
src/org/sipdroid/sipua/ui/Receiver.java | 15 +
src/org/sipdroid/sipua/ui/Settings.java | 4
7 files changed, 220 insertions(+), 20 deletions(-)
Index: src/org/sipdroid/sipua/SipdroidEngine.java
===================================================================
--- src/org/sipdroid/sipua/SipdroidEngine.java (revision 329)
+++ src/org/sipdroid/sipua/SipdroidEngine.java (working copy)
@@ -208,10 +208,25 @@
} else
Receiver.onText(Receiver.REGISTER_NOTIFICATION, null, 0,0);
Receiver.registered();
+ if (PreferenceManager.getDefaultSharedPreferences(getUIContext()).getBoolean("MWI_enabled",true)) {
+ ra.startMWI();
+ }
if (wl.isHeld())
wl.release();
}
+ public void onMWIUpdate(boolean voicemail, int number) {
+ if (voicemail) {
+ String msgs = getUIContext().getString(R.string.voicemail);
+ if (number != 0) {
+ msgs = msgs + ": " + number;
+ }
+ Receiver.onText(Receiver.MWI_NOTIFICATION, msgs,android.R.drawable.stat_notify_voicemail,0);
+ } else {
+ Receiver.onText(Receiver.MWI_NOTIFICATION, null, 0,0);
+ }
+ }
+
static long lasthalt;
/** When a UA failed on (un)registering. */
@@ -225,6 +240,7 @@
sip_provider.haltConnections();
}
updateDNS();
+ ra.stopMWI();
}
public void updateDNS() {
@@ -103,6 +106,11 @@
UserAgentProfile user_profile;
+ SubscriberDialog sd;
+ boolean alreadySubscribed = false;
+ Message currentSubscribeMessage;
+ public final int SUBSCRIPTION_EXPIRES = 184000;
+
/**
* Creates a new RegisterAgent with authentication credentials (i.e.
* username, realm, and passwd).
@@ -223,9 +231,151 @@
/** Unregister with the registrar server */
public boolean unregister() {
+ stopMWI();
return register(0);
}
+ public void stopMWI()
+ {
+ if (sd != null) {
+ synchronized (sd) {
+ sd.notify();
+ }
+ }
+ sd = null;
+ public void startMWI()
+ {
+ if (alreadySubscribed) {
+ return;
+ /* Can get replays of the subscription notice, so ignore */
+ if (alreadySubscribed) {
+ return;
+ }
+ alreadySubscribed = true;
+ if (resp.hasExpiresHeader()) {
+ expires = resp.getExpiresHeader().getDeltaSeconds();
+ } else {
+ expires = SUBSCRIPTION_EXPIRES;
+ }
+ Thread t = new Thread(new Runnable() {
+ public void run() {
+ try {
+ synchronized (sd) {
+ sd.wait(expires*1000);
+ }
+ alreadySubscribed = false;
+ startMWI();
+ } catch(Exception E) {
+ }
+ }
+ });
+ t.start();
+ }
+
+ public void onDlgSubscriptionFailure(SubscriberDialog dialog, int code,
+ String reason, Message resp)
+ {
+ Message req = getSubscribeMessage(true);
+ if (handleAuthentication(code, resp, req)) {
+ sd.subscribe(req);
+ } else {
+ delayStartMWI();
+ }
+ }
+
+ public void onDlgSubscribeTimeout(SubscriberDialog dialog)
+ {
+ delayStartMWI();
+ }
+
+ public void onDlgSubscriptionTerminated(SubscriberDialog dialog)
+ {
+ alreadySubscribed = false;
@@ -324,7 +474,7 @@
}
}
- private boolean generateRequestWithProxyAuthorizationheader(TransactionClient transaction,
+ private boolean generateRequestWithProxyAuthorizationheader(
Message resp, Message req){
if(resp.hasProxyAuthenticateHeader()
&& resp.getProxyAuthenticateHeader().getRealmParam()
@@ -338,20 +488,17 @@
qop = (qop_options != null) ? "auth" : null;
ProxyAuthorizationHeader ah = (new DigestAuthentication(
- SipMethods.REGISTER, req.getRequestLine().getAddress()
+ req.getTransactionMethod(), req.getRequestLine().getAddress()
.toString(), pah, qop, null, username, passwd))
.getProxyAuthorizationHeader();
req.setProxyAuthorizationHeader(ah);
- TransactionClient t = new TransactionClient(sip_provider, req, this);
-
- t.request();
return true;
}
return false;
}
- private boolean generateRequestWithWwwAuthorizationheader(TransactionClient transaction,
+ private boolean generateRequestWithWwwAuthorizationheader(
Message resp, Message req){
if(resp.hasWwwAuthenticateHeader()
&& resp.getWwwAuthenticateHeader().getRealmParam()
@@ -365,18 +512,26 @@
qop = (qop_options != null) ? "auth" : null;
AuthorizationHeader ah = (new DigestAuthentication(
- SipMethods.REGISTER, req.getRequestLine().getAddress()
+ req.getTransactionMethod(), req.getRequestLine().getAddress()
.toString(), wah, qop, null, username, passwd))
.getAuthorizationHeader();
req.setAuthorizationHeader(ah);
-
- TransactionClient t = new TransactionClient(sip_provider, req, this);
-
- t.request();
return true;
}
return false;
}
+
+ private boolean handleAuthentication(int respCode, Message resp,
+ Message req) {
+ switch (respCode) {
+ case 407:
+ return generateRequestWithProxyAuthorizationheader(resp, req);
+ case 401:
+ return generateRequestWithWwwAuthorizationheader(resp, req);
+ }
+ return false;
+ }
+
private boolean processAuthenticationResponse(TransactionClient transaction,
Message resp, int respCode){
@@ -385,11 +540,11 @@
Message req = transaction.getRequestMessage();
req.setCSeqHeader(req.getCSeqHeader().incSequenceNumber());
- switch(respCode) {
- case 407:
- return generateRequestWithProxyAuthorizationheader(transaction, resp, req);
- case 401:
- return generateRequestWithWwwAuthorizationheader(transaction, resp, req);
+ if (handleAuthentication(respCode, resp, req)) {
+ TransactionClient t = new TransactionClient(sip_provider, req, this);
+
+ t.request();
+ return true;
}
}
return false;
Index: src/org/sipdroid/sipua/RegisterAgentListener.java
===================================================================
--- src/org/sipdroid/sipua/RegisterAgentListener.java (revision 329)
+++ src/org/sipdroid/sipua/RegisterAgentListener.java (working copy)
@@ -29,6 +29,8 @@
public void onUaRegistrationSuccess(RegisterAgent ra, NameAddress target,
NameAddress contact, String result);
+ public void onMWIUpdate(boolean voicemail, int number);
+
/** When a UA failed on (un)registering. */
public void onUaRegistrationFailure(RegisterAgent ra, NameAddress target,
NameAddress contact, String result);
Index: src/org/sipdroid/sipua/ui/Settings.java
===================================================================
--- src/org/sipdroid/sipua/ui/Settings.java (revision 329)
+++ src/org/sipdroid/sipua/ui/Settings.java (working copy)
@@ -60,6 +60,7 @@
Editor edit = getPreferenceScreen().getSharedPreferences().edit();
edit.putBoolean("wlan", true);
+ edit.putBoolean("MWI_enabled", true);
edit.putString("port", ""+SipStack.default_port);
edit.putString("server", "pbxes.org");
edit.putString("domain", "");
@@ -110,7 +111,8 @@
key.equals("protocol") ||
key.equals("minedge") ||
key.equals("pos") ||
- key.equals("posurl")) {
+ key.equals("posurl") ||
+ key.equals("MWI_enabled")) {
if (key.equals("wlan") || key.equals("3g"))
updateSleep();
Receiver.engine(this).halt();
Index: src/org/sipdroid/sipua/ui/Receiver.java
===================================================================
--- src/org/sipdroid/sipua/ui/Receiver.java (revision 329)
+++ src/org/sipdroid/sipua/ui/Receiver.java (working copy)
@@ -69,6 +69,7 @@
public final static int CALL_NOTIFICATION = 2;
public final static int MISSED_CALL_NOTIFICATION = 3;
public final static int AUTO_ANSWER_NOTIFICATION = 4;
+ public final static int MWI_NOTIFICATION = 5;
final static long[] vibratePattern = {0,1000,1000};
@@ -227,14 +228,18 @@
if (text != null) {
Notification notification = new Notification();
notification.icon = mInCallResId;
- if (type == MISSED_CALL_NOTIFICATION) {
+ if (type == MISSED_CALL_NOTIFICATION) {
notification.flags |= Notification.FLAG_AUTO_CANCEL;
notification.setLatestEventInfo(mContext, text, mContext.getString(R.string.app_name),
PendingIntent.getActivity(mContext, 0, createCallLogIntent(), 0));
} else {
- notification.contentIntent = PendingIntent.getActivity(mContext, 0,
+ if (type == MWI_NOTIFICATION) {
+ notification.contentIntent = PendingIntent.getActivity(mContext, 0, createMWIIntent(), 0);
+ } else {
+ notification.contentIntent = PendingIntent.getActivity(mContext, 0,
createIntent(type == AUTO_ANSWER_NOTIFICATION?
AutoAnswer.class:Sipdroid.class), 0);
+ }
notification.flags |= Notification.FLAG_ONGOING_EVENT;
RemoteViews contentView = new RemoteViews(mContext.getPackageName(),
R.layout.ongoing_call_notification);
@@ -412,6 +417,12 @@
intent.addCategory(Intent.CATEGORY_HOME);
return intent;
}
+
+ static Intent createMWIIntent() {
+ String num = PreferenceManager.getDefaultSharedPreferences(mContext).getString("MWI_location", null);
+ Intent intent = new Intent(Intent.ACTION_CALL, Uri.parse("sip:" + num));
+ return intent;
+ }
public static void moveTop() {
onText(CALL_NOTIFICATION, mContext.getString(R.string.card_title_in_progress), R.drawable.stat_sys_phone_call, 0);
Index: res/values/strings.xml
===================================================================
--- res/values/strings.xml (revision 329)
+++ res/values/strings.xml (working copy)
@@ -51,6 +51,8 @@
<string name="regok">Registered</string>
<string name="regfailed">Registration failed</string>
+<string name="voicemail">Message(s) Waiting</string>
+
<string name="auto_enabled">Auto-Answer/Speakerphone</string>
<string name="auto_disabled">Auto-Answer off</string>
<string name="hint">Called Party Address</string>
@@ -91,6 +93,10 @@
<string name="settings_auto_on2">Short vibrating alert when screen is on</string>
<string name="settings_auto_ondemand">Auto-Answer on demand</string>
<string name="settings_auto_ondemand2">Show toggle switch in status bar</string>
+<string name="settings_MWI">Check for Voicemail</string>
+<string name="settings_MWI2">Subscribe to SIP message waiting</string>
+<string name="settings_MWI_number">Voicemail Location</string>
+<string name="settings_MWI_number2">SIP URL to call to pick up voicemail</string>
<string name="settings_advanced_options">Advanced Options</string>
<string name="settings_minedge">Signal Bars for EDGE Calls</string>
Index: res/xml/preferences.xml
===================================================================
--- res/xml/preferences.xml (revision 329)
+++ res/xml/preferences.xml (working copy)
@@ -57,6 +57,14 @@
android:key="auto_ondemand"
android:title="@string/settings_auto_ondemand"
android:summary="@string/settings_auto_ondemand2" />
+ <CheckBoxPreference
+ android:key="MWI_enabled"
+ android:title="@string/settings_MWI"
+ android:summary="@string/settings_MWI2" />
+ <EditTextPreference
+ android:key="MWI_location"
+ android:title="@string/settings_MWI_number"
+ android:summary="@string/settings_MWI_number2" />
</PreferenceCategory>
</PreferenceScreen>
<PreferenceScreen android:title="@string/settings_advanced_options">
Sure ... I'm not quite au fait with what goes on here ... do you just
apply patches straight from the mailing list to the tree, or does
something else have to happen?
> I would prefer leaving the setting for MWI number out. This should be
> retrieved from the server, from the MWI notification itself.
RFC3842 doesn't define how you get the message retrieval call number
(message account isn't the same thing as the uri to call). I'm sure
there are systems that can supply it as part of the notify extended
headers, but it would be a system specific extension, which is why for
the general case, you need to supply the number to call to get to
voicemail.
James
OK, so that means I'll need commit rights. I assume someone needs an
ssh key?
> Before committing, let's discuss getting the number from the message-
> account field instead of a configurable option.
Sure ... but we still need a configurable field, even if it gets
pre-populated
> It seems some phones are really doing this like the Snom. And all
> providers I have checked supply the right number in the message-
> account field. What is your experience with the provider you are using?
OK, so asterisk, which is what I use just follows the RFCs, so no call
number. Where is this defined for the other systems? It's going to be
a simple body field ... I just need to know what it is.
James
OK, so here's the update. It takes the voicemail number from the
Message-Account header ... it strips the realm because they're usually
wrong for private asterisk because of nat problems and then vectors to
it. If there's no account, it just dumps the user in a dialer.
James
---
Index: src/org/sipdroid/sipua/SipdroidEngine.java
===================================================================
--- src/org/sipdroid/sipua/SipdroidEngine.java (revision 330)
+++ src/org/sipdroid/sipua/SipdroidEngine.java (working copy)
@@ -216,10 +216,26 @@
} else
Receiver.onText(Receiver.REGISTER_NOTIFICATION, null, 0,0);
Receiver.registered();
+ if (PreferenceManager.getDefaultSharedPreferences(getUIContext()).getBoolean("MWI_enabled",true)) {
+ ra.startMWI();
+ }
if (wl.isHeld())
wl.release();
}
+ public void onMWIUpdate(boolean voicemail, int number, String vmacc) {
+ if (voicemail) {
+ String msgs = getUIContext().getString(R.string.voicemail);
+ if (number != 0) {
+ msgs = msgs + ": " + number;
+ }
+ Receiver.MWI_account = vmacc;
+ Receiver.onText(Receiver.MWI_NOTIFICATION, msgs,android.R.drawable.stat_notify_voicemail,0);
+ } else {
+ Receiver.onText(Receiver.MWI_NOTIFICATION, null, 0,0);
+ }
+ }
+
static long lasthalt;
/** When a UA failed on (un)registering. */
@@ -233,6 +249,7 @@
sip_provider.haltConnections();
}
updateDNS();
+ ra.stopMWI();
}
public void updateDNS() {
Index: src/org/sipdroid/sipua/RegisterAgent.java
===================================================================
--- src/org/sipdroid/sipua/RegisterAgent.java (revision 330)
@@ -223,9 +231,157 @@
/** Unregister with the registrar server */
public boolean unregister() {
+ stopMWI();
return register(0);
}
+ public void stopMWI()
+ {
+ if (sd != null) {
+ synchronized (sd) {
+ sd.notify();
+ }
+ }
+ sd = null;
+ listener.onMWIUpdate(false, 0, null);
+ final char[] vmboxsep = { '@', '\r', '\n' };
+ String vmaccount = null;
+ boolean voicemail = false;
+ int nummsg = 0;
+ while (p.hasMore()) {
+ String property = p.getWord(propertysep);
+ p.skipChar();
+ p.skipWSP();
+ String value = p.getWord(p.CRLF);
+ if (property.equalsIgnoreCase("Messages-Waiting") && value.equalsIgnoreCase("yes")) {
+ voicemail = true;
+ } else if (property.equalsIgnoreCase("Voice-Message")) {
+ Parser np = new Parser(value);
+ String num = np.getWord(vmailsep);
+ nummsg = Integer.parseInt(num);
+ } else if (property.equalsIgnoreCase("Message-Account")) {
+ Parser np = new Parser(value);
+ // strip the @<pbx> because it may have nat problems
+ vmaccount = np.getWord(vmboxsep);
+ }
+ }
+ listener.onMWIUpdate(voicemail, nummsg, vmaccount);
+ }
+
// **************** Transaction callback functions *****************
/** Callback function called when client sends back a failure response. */
@@ -324,7 +480,7 @@
}
}
- private boolean generateRequestWithProxyAuthorizationheader(TransactionClient transaction,
+ private boolean generateRequestWithProxyAuthorizationheader(
Message resp, Message req){
if(resp.hasProxyAuthenticateHeader()
&& resp.getProxyAuthenticateHeader().getRealmParam()
@@ -338,20 +494,17 @@
qop = (qop_options != null) ? "auth" : null;
ProxyAuthorizationHeader ah = (new DigestAuthentication(
- SipMethods.REGISTER, req.getRequestLine().getAddress()
+ req.getTransactionMethod(), req.getRequestLine().getAddress()
.toString(), pah, qop, null, username, passwd))
.getProxyAuthorizationHeader();
req.setProxyAuthorizationHeader(ah);
- TransactionClient t = new TransactionClient(sip_provider, req, this);
-
- t.request();
return true;
}
return false;
}
- private boolean generateRequestWithWwwAuthorizationheader(TransactionClient transaction,
+ private boolean generateRequestWithWwwAuthorizationheader(
Message resp, Message req){
if(resp.hasWwwAuthenticateHeader()
&& resp.getWwwAuthenticateHeader().getRealmParam()
@@ -365,18 +518,26 @@
@@ -385,11 +546,11 @@
Message req = transaction.getRequestMessage();
req.setCSeqHeader(req.getCSeqHeader().incSequenceNumber());
- switch(respCode) {
- case 407:
- return generateRequestWithProxyAuthorizationheader(transaction, resp, req);
- case 401:
- return generateRequestWithWwwAuthorizationheader(transaction, resp, req);
+ if (handleAuthentication(respCode, resp, req)) {
+ TransactionClient t = new TransactionClient(sip_provider, req, this);
+
+ t.request();
+ return true;
}
}
return false;
Index: src/org/sipdroid/sipua/RegisterAgentListener.java
===================================================================
--- src/org/sipdroid/sipua/RegisterAgentListener.java (revision 330)
+++ src/org/sipdroid/sipua/RegisterAgentListener.java (working copy)
@@ -29,6 +29,8 @@
public void onUaRegistrationSuccess(RegisterAgent ra, NameAddress target,
NameAddress contact, String result);
+ public void onMWIUpdate(boolean voicemail, int number, String vmacc);
+
/** When a UA failed on (un)registering. */
public void onUaRegistrationFailure(RegisterAgent ra, NameAddress target,
NameAddress contact, String result);
Index: src/org/sipdroid/sipua/ui/Settings.java
===================================================================
--- src/org/sipdroid/sipua/ui/Settings.java (revision 330)
+++ src/org/sipdroid/sipua/ui/Settings.java (working copy)
@@ -60,6 +60,7 @@
Editor edit = getPreferenceScreen().getSharedPreferences().edit();
edit.putBoolean("wlan", true);
+ edit.putBoolean("MWI_enabled", true);
edit.putString("port", ""+SipStack.default_port);
edit.putString("server", "pbxes.org");
edit.putString("domain", "");
@@ -111,7 +112,8 @@
key.equals("minedge") ||
key.equals("pos") ||
key.equals("posurl") ||
- key.equals("callerid")) {
+ key.equals("callerid") ||
+ key.equals("MWI_enabled")) {
if (key.equals("wlan") || key.equals("3g"))
updateSleep();
Receiver.engine(this).halt();
Index: src/org/sipdroid/sipua/ui/Receiver.java
===================================================================
--- src/org/sipdroid/sipua/ui/Receiver.java (revision 330)
+++ src/org/sipdroid/sipua/ui/Receiver.java (working copy)
@@ -69,6 +69,7 @@
public final static int CALL_NOTIFICATION = 2;
public final static int MISSED_CALL_NOTIFICATION = 3;
public final static int AUTO_ANSWER_NOTIFICATION = 4;
+ public final static int MWI_NOTIFICATION = 5;
final static long[] vibratePattern = {0,1000,1000};
@@ -82,6 +83,7 @@
public static int call_state;
public static String pstn_state;
+ public static String MWI_account;
private static String laststate,lastnumber;
public static MediaPlayer ringbackPlayer;
@@ -227,14 +229,18 @@
if (text != null) {
Notification notification = new Notification();
notification.icon = mInCallResId;
- if (type == MISSED_CALL_NOTIFICATION) {
+ if (type == MISSED_CALL_NOTIFICATION) {
notification.flags |= Notification.FLAG_AUTO_CANCEL;
notification.setLatestEventInfo(mContext, text, mContext.getString(R.string.app_name),
PendingIntent.getActivity(mContext, 0, createCallLogIntent(), 0));
} else {
- notification.contentIntent = PendingIntent.getActivity(mContext, 0,
+ if (type == MWI_NOTIFICATION) {
+ notification.contentIntent = PendingIntent.getActivity(mContext, 0, createMWIIntent(), 0);
+ } else {
+ notification.contentIntent = PendingIntent.getActivity(mContext, 0,
createIntent(type == AUTO_ANSWER_NOTIFICATION?
AutoAnswer.class:Sipdroid.class), 0);
+ }
notification.flags |= Notification.FLAG_ONGOING_EVENT;
RemoteViews contentView = new RemoteViews(mContext.getPackageName(),
R.layout.ongoing_call_notification);
@@ -412,6 +418,16 @@
intent.addCategory(Intent.CATEGORY_HOME);
return intent;
}
+
+ static Intent createMWIIntent() {
+ Intent intent;
+
+ if (MWI_account != null)
+ intent = new Intent(Intent.ACTION_CALL, Uri.parse(MWI_account));
+ else
+ intent = new Intent(Intent.ACTION_DIAL);
+ return intent;
+ }
public static void moveTop() {
onText(CALL_NOTIFICATION, mContext.getString(R.string.card_title_in_progress), R.drawable.stat_sys_phone_call, 0);
Index: res/values/strings.xml
===================================================================
--- res/values/strings.xml (revision 330)
+++ res/values/strings.xml (working copy)
@@ -51,6 +51,8 @@
<string name="regok">Registered</string>
<string name="regfailed">Registration failed</string>
+<string name="voicemail">Message(s) Waiting</string>
+
<string name="auto_enabled">Auto-Answer/Speakerphone</string>
<string name="auto_disabled">Auto-Answer off</string>
<string name="hint">Called Party Address</string>
@@ -91,6 +93,8 @@
<string name="settings_auto_on2">Short vibrating alert when screen is on</string>
<string name="settings_auto_ondemand">Auto-Answer on demand</string>
<string name="settings_auto_ondemand2">Show toggle switch in status bar</string>
+<string name="settings_MWI">Check for Voicemail</string>
+<string name="settings_MWI2">Subscribe to SIP message waiting</string>
<string name="settings_advanced_options">Advanced Options</string>
<string name="settings_minedge">Signal Bars for EDGE Calls</string>
Index: res/xml/preferences.xml
===================================================================
--- res/xml/preferences.xml (revision 330)
+++ res/xml/preferences.xml (working copy)
@@ -56,6 +56,10 @@
android:key="auto_ondemand"
android:title="@string/settings_auto_ondemand"
android:summary="@string/settings_auto_ondemand2" />
+ <CheckBoxPreference
+ android:key="MWI_enabled"
+ android:title="@string/settings_MWI"
+ android:summary="@string/settings_MWI2" />