Message Waiting Indication for sip protocol (rfc3842).

cusax-fix
Damian Minkov 16 years ago
parent 086f50cb96
commit 8eb053c908

@ -765,6 +765,7 @@ plugin.sipaccregwizz.XCAP_USE_SIP_CREDENTIALS=Use SIP credentials
plugin.sipaccregwizz.XCAP_USER=User
plugin.sipaccregwizz.XCAP_PASSWORD=Password
plugin.sipaccregwizz.XCAP_SERVER_URI=Server URI
plugin.sipaccregwizz.VOICEMAIL_URI=Voicemail URI
# skin manager
plugin.skinmanager.SKINS=Skins

@ -473,9 +473,21 @@ public synchronized void sendMessage(ContactMsnImpl to, String content)
*/
private class MessageToSend
{
/**
* Message sent to.
*/
private ContactMsnImpl to;
/**
* Content of message.
*/
private String content;
/**
* Creates MessageToSend.
* @param to contact to.
* @param content content to be sent.
*/
MessageToSend(ContactMsnImpl to, String content)
{
this.to = to;

@ -241,6 +241,30 @@ protected Subscription getSubscription(Address toAddress, String eventId)
return null;
}
/**
* Gets the <tt>Subscription</tt> from the list of subscriptions managed by
* this instance which is associated with a specific id tag in its Event
* header. Returns the first found one.
*
* @param eventId the id tag placed in the Event header of the
* <tt>Subscription</tt> to be retrieved if there is one or <tt>null</tt> if
* the <tt>Subscription</tt> should have no id tag in its Event header
* @return an existing <tt>Subscription</tt> from the list of subscriptions
* managed by this instance with the specified id tag in its Event
* header; <tt>null</tt> if no such <tt>Subscription</tt> exists in the list
* of subscriptions managed by this instance
*/
protected Subscription getSubscriptionByEventID(String eventId)
{
synchronized (subscriptions)
{
for (Subscription subscription : subscriptions.values())
if (eventId.equals(subscription.getEventId()))
return subscription;
}
return null;
}
/**
* Gets the <tt>Subscription</tt> from the list of subscriptions managed by
* this instance which is associated with a specific CallId.

@ -0,0 +1,422 @@
/*
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package net.java.sip.communicator.impl.protocol.sip;
import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.service.protocol.event.*;
import net.java.sip.communicator.util.*;
import javax.sip.*;
import javax.sip.address.*;
import java.io.*;
import java.util.*;
import java.util.regex.*;
/**
* Message Waiting Indication Event rfc3842.
*
* @author Damian Minkov
*/
public class OperationSetMessageWaitingSipImpl
implements OperationSetMessageWaiting,
RegistrationStateChangeListener
{
/**
* Our class logger.
*/
private static final Logger logger
= Logger.getLogger(OperationSetMessageWaitingSipImpl.class);
/**
* The provider that created us.
*/
private final ProtocolProviderServiceSipImpl provider;
/**
* The timer which will handle all the scheduled tasks
*/
private final TimerScheduler timer = new TimerScheduler();
/**
* The name of the event package supported by
* <tt>OperationSetMessageWaitingSipImpl</tt> in SUBSCRIBE
* and NOTIFY requests.
*/
static final String EVENT_PACKAGE = "message-summary";
/**
* The content sub-type of the content supported in NOTIFY requests handled
* by <tt>OperationSetMessageWaitingSipImpl</tt>.
*/
private static final String CONTENT_SUB_TYPE = "simple-message-summary";
/**
* The time in seconds after which a <tt>Subscription</tt> should be expired
* by the <tt>OperationSetMessageWaitingSipImpl</tt> instance
* which manages it.
*/
private static final int SUBSCRIPTION_DURATION = 3600;
/**
* The <code>EventPackageSubscriber</code> which provides the ability of
* this instance to act as a subscriber
* for the message-summary event package.
*/
private EventPackageSubscriber messageWaitingSubscriber = null;
/**
* How many seconds before a timeout should we refresh our state
*/
private static final int REFRESH_MARGIN = 60;
/**
* Listeners that would receive event notifications for
* new messages by msg type.
*/
private final Map<MessageType, List<MessageWaitingListener>>
messageWaitingNotificationListeners
= new HashMap<MessageType,
List<MessageWaitingListener>>();
/**
* Creates this operation set.
* @param provider
*/
OperationSetMessageWaitingSipImpl(
ProtocolProviderServiceSipImpl provider)
{
this.provider = provider;
this.provider.addRegistrationStateChangeListener(this);
}
/**
* Registers a <tt>MessageWaitingListener</tt> with this
* operation set so that it gets notifications of new and old
* messages waiting.
*
* @param type register the listener for certain type of messages.
* @param listener the <tt>MessageWaitingListener</tt>
* to register.
*/
public void addMessageWaitingNotificationListener(
MessageType type,
MessageWaitingListener listener)
{
synchronized (messageWaitingNotificationListeners)
{
List<MessageWaitingListener> l =
this.messageWaitingNotificationListeners.get(type);
if(l == null)
{
l = new ArrayList<MessageWaitingListener>();
this.messageWaitingNotificationListeners.put(type, l);
}
if(!l.contains(listener))
l.add(listener);
}
}
/**
* Unregisters <tt>listener</tt> so that it won't receive any further
* notifications upon new messages waiting notifications delivery.
*
* @param type register the listener for certain type of messages.
* @param listener the <tt>MessageWaitingListener</tt>
* to unregister.
*/
public void removeMessageWaitingNotificationListener(
MessageType type,
MessageWaitingListener listener)
{
synchronized (messageWaitingNotificationListeners)
{
List l = this.messageWaitingNotificationListeners.get(type);
if(l != null)
this.messageWaitingNotificationListeners.remove(listener);
}
}
/**
* The method is called by a <code>ProtocolProviderService</code>
* implementation whenever a change in the registration state of the
* corresponding provider had occurred.
*
* @param evt the event describing the status change.
*/
public void registrationStateChanged(RegistrationStateChangeEvent evt)
{
if (evt.getNewState().equals(RegistrationState.REGISTERED))
{
messageWaitingSubscriber =
new EventPackageSubscriber(
provider,
EVENT_PACKAGE,
SUBSCRIPTION_DURATION,
CONTENT_SUB_TYPE,
timer,
REFRESH_MARGIN)
{
/**
* We may receive some message-waiting notifications
* out of dialog but we still want to process them, as
* the server is just not rfc compliant.
* This happens with asterisk when using qualify option
* for configured user(user is behind nat and we * ping it),
* as the sent packet pings delete our subscription dialog.
*
* @param callId the CallId associated with the
* <tt>Subscription</tt> to be retrieved
* @return the Subscription.
*/
@Override
protected Subscription getSubscription(String callId)
{
Subscription resultSub = super.getSubscription(callId);
if(resultSub != null)
return resultSub;
return (Subscription)getSubscriptionByEventID(
OperationSetMessageWaitingSipImpl
.EVENT_PACKAGE);
}
};
try
{
Address subscribeAddress;
String vmAddressURI = (String)provider.getAccountID()
.getAccountProperty(
ProtocolProviderFactory.VOICEMAIL_URI);
if(StringUtils.isNullOrEmpty(vmAddressURI))
subscribeAddress = provider.getRegistrarConnection()
.getAddressOfRecord();
else
subscribeAddress = provider.parseAddressString(
vmAddressURI);
messageWaitingSubscriber.subscribe(
new MessageSummarySubscriber(subscribeAddress));
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
/**
* Subscribes and receive result for message-summary event package.
*/
private class MessageSummarySubscriber
extends EventPackageSubscriber.Subscription
{
/**
* Matching messages count
* group 1 - new messages count.
* group 2 - old messages count.
* group 3 - new urgent messages count.
* group 4 - old urgent messages count.
*/
private Pattern messageWaitingCountPattern = Pattern.compile(
"(\\d+)/(\\d+) \\((\\d+)/(\\d+)\\)");
/**
* Initializes a new <tt>Subscription</tt> instance with a specific
* subscription <tt>Address</tt>/Request URI and an id tag of the
* associated Event headers of value <tt>null</tt>.
*
* @param toAddress the subscription <tt>Address</tt>/Request URI which is
* to be the target of the SUBSCRIBE requests associated with
* the new instance
*/
public MessageSummarySubscriber(Address toAddress)
{
super(toAddress, "message-summary");
}
/**
* Notifies this <tt>Subscription</tt> that an active NOTIFY
* <tt>Request</tt> has been received and it may process the
* specified raw content carried in it.
*
* @param requestEvent the <tt>RequestEvent</tt> carrying the full details of
* the received NOTIFY <tt>Request</tt> including the raw
* content which may be processed by this
* <tt>Subscription</tt>
* @param rawContent an array of bytes which represents the raw content carried
* in the body of the received NOTIFY <tt>Request</tt>
* and extracted from the specified <tt>RequestEvent</tt>
* for the convenience of the implementers
*/
@Override
protected void processActiveRequest(
RequestEvent requestEvent, byte[] rawContent)
{
try
{
String messageAccount = null;
BufferedReader input = new BufferedReader(new InputStreamReader(
new ByteArrayInputStream(rawContent)));
String line;
while((line = input.readLine()) != null)
{
String lcaseLine = line.toLowerCase();
if(lcaseLine.startsWith("messages-waiting"))
{
// we fire event for every message notification
}
else if(lcaseLine.startsWith("message-account"))
{
messageAccount =
line.substring(line.indexOf(":") + 1).trim();
}
else if(lcaseLine.startsWith(MessageType.VOICE.toString())
|| lcaseLine.startsWith(MessageType.FAX.toString())
|| lcaseLine.startsWith(MessageType.MULTIMEDIA.toString())
|| lcaseLine.startsWith(MessageType.PAGER.toString())
|| lcaseLine.startsWith(MessageType.TEXT.toString())
|| lcaseLine.startsWith(MessageType.NONE.toString()))
{
String msgType =
lcaseLine.substring(0, line.indexOf(":")).trim();
String messagesCountValue =
line.substring(line.indexOf(":") + 1).trim();
Matcher matcher = messageWaitingCountPattern.matcher(
messagesCountValue);
if(matcher.find())
{
fireVoicemailNotificationEvent(
msgType,
messageAccount,
Integer.valueOf(matcher.group(1)),
Integer.valueOf(matcher.group(2)),
Integer.valueOf(matcher.group(3)),
Integer.valueOf(matcher.group(4)));
}
}
}
}
catch(IOException ex)
{
logger.error("Error processing message waiting info");
}
}
/**
* Notifies this <tt>Subscription</tt> that a <tt>Response</tt>
* to a previous SUBSCRIBE <tt>Request</tt> has been received with a
* status code in the failure range and it may process the status code
* carried in it.
*
* @param responseEvent the <tt>ResponseEvent</tt> carrying the full details
* of the received <tt>Response</tt> including the status
* code which may be processed by this
* <tt>Subscription</tt>
* @param statusCode the status code carried in the <tt>Response</tt> and
* extracted from the specified <tt>ResponseEvent</tt>
* for the convenience of the implementers
*/
@Override
protected void processFailureResponse(
ResponseEvent responseEvent, int statusCode)
{
if(logger.isDebugEnabled())
logger.debug("Processing failed: " + statusCode);
}
/**
* Notifies this <tt>Subscription</tt> that a <tt>Response</tt>
* to a previous SUBSCRIBE <tt>Request</tt> has been received with a
* status code in the success range and it may process the status code
* carried in it.
*
* @param responseEvent the <tt>ResponseEvent</tt> carrying the full details
* of the received <tt>Response</tt> including the status
* code which may be processed by this
* <tt>Subscription</tt>
* @param statusCode the status code carried in the <tt>Response</tt> and
* extracted from the specified <tt>ResponseEvent</tt>
* for the convenience of the implementers
*/
@Override
protected void processSuccessResponse(
ResponseEvent responseEvent, int statusCode)
{
if(logger.isDebugEnabled())
logger.debug("Cannot subscripe to presence watcher info!");
}
/**
* Notifies this <tt>Subscription</tt> that a terminating NOTIFY
* <tt>Request</tt> has been received and it may process the reason
* code carried in it.
*
* @param requestEvent the <tt>RequestEvent</tt> carrying the full details of
* the received NOTIFY <tt>Request</tt> including the
* reason code which may be processed by this
* <tt>Subscription</tt>
* @param reasonCode the code of the reason for the termination carried in the
* NOTIFY <tt>Request</tt> and extracted from the
* specified <tt>RequestEvent</tt> for the convenience of
* the implementers
*/
@Override
protected void processTerminatedRequest(
RequestEvent requestEvent, String reasonCode)
{
if(logger.isDebugEnabled())
logger.debug("Processing terminated: " + reasonCode);
}
}
/**
* Fires new event on message waiting = yes.
* @param account the account to reach the messages.
* @param unreadMessages number of unread messages.
* @param readMessages number of old messages.
* @param unreadUrgentMessages number of unread urgent messages.
* @param readUrgentMessages number of old urgent messages.
*/
private void fireVoicemailNotificationEvent(
String msgTypeStr,
String account,
int unreadMessages,
int readMessages,
int unreadUrgentMessages,
int readUrgentMessages)
{
MessageType msgType = MessageType.valueOfByType(msgTypeStr);
MessageWaitingEvent event =
new MessageWaitingEvent(
provider,
msgType,
account,
unreadMessages,
readMessages,
unreadUrgentMessages,
readUrgentMessages);
Iterable<MessageWaitingListener> listeners;
synchronized (messageWaitingNotificationListeners)
{
listeners =
new ArrayList<MessageWaitingListener>(
messageWaitingNotificationListeners.get(msgType));
}
for (MessageWaitingListener listener : listeners)
{
listener.messageWaitingNotify(event);
}
}
}

@ -661,6 +661,10 @@ protected void initialize(String sipAddress,
OperationSetTelephonyConferencing.class,
new OperationSetTelephonyConferencingSipImpl(this));
addSupportedOperationSet(
OperationSetMessageWaiting.class,
new OperationSetMessageWaitingSipImpl(this));
//initialize our OPTIONS handler
new ClientCapabilities(this);

@ -7,6 +7,7 @@
package net.java.sip.communicator.impl.protocol.sip;
import gov.nist.javax.sip.*;
import gov.nist.javax.sip.header.*;
import gov.nist.javax.sip.stack.*;
import java.io.*;
@ -545,38 +546,9 @@ public void processRequest(RequestEvent event)
{
try
{
/*
* Max-Forwards is required, yet there are UAs which do not
* place it. SipProvider#getNewServerTransaction(Request)
* will throw an exception in the case of a missing
* Max-Forwards header and this method will eventually just
* log it thus ignoring the whole event. Since these
* requests come often in some cases (e.g. ippi.fr),
* performance-wise it makes sense to just prevent the
* exceptions and ignore the event early.
*/
if (request.getHeader(MaxForwardsHeader.NAME) == null)
{
//it appears that some buggy providers do send requests
//with no Max-Forwards headers, so let's at least try
//to save calls.
if(Request.INVITE.equals(request.getMethod()))
{
MaxForwardsHeader maxForwards = SipFactory
.getInstance().createHeaderFactory()
.createMaxForwardsHeader(70);
request.setHeader(maxForwards);
}
else
{
if (logger.isTraceEnabled())
logger.trace(
"Ignoring request without Max-Forwards header: "
+ event);
return;
}
}
// apply some hacks if needed on incoming request
// to be compliant with some servers/clients
dirtyHacks(event);
SipProvider source = (SipProvider) event.getSource();
ServerTransaction transaction
@ -1061,4 +1033,70 @@ public java.net.InetSocketAddress getLocalAddressForDestination(
return (java.net.InetSocketAddress)(((SipStackImpl)this.stack)
.obtainLocalAddress(dst, dstPort, localAddress, 0));
}
/**
* Place to put some hacks if needed on incoming requests.
*
* @param event the incoming request event.
*/
private void dirtyHacks(RequestEvent event)
{
Request request = event.getRequest();
try
{
/*
* Max-Forwards is required, yet there are UAs which do not
* place it. SipProvider#getNewServerTransaction(Request)
* will throw an exception in the case of a missing
* Max-Forwards header and this method will eventually just
* log it thus ignoring the whole event. Since these
* requests come often in some cases (e.g. ippi.fr),
* performance-wise it makes sense to just prevent the
* exceptions and ignore the event early.
*/
if (request.getHeader(MaxForwardsHeader.NAME) == null)
{
//it appears that some buggy providers do send requests
//with no Max-Forwards headers, so let's at least try
//to save calls.
if(Request.INVITE.equals(request.getMethod()))
{
MaxForwardsHeader maxForwards = SipFactory
.getInstance().createHeaderFactory()
.createMaxForwardsHeader(70);
request.setHeader(maxForwards);
}
else
{
if (logger.isTraceEnabled())
logger.trace(
"Ignoring request without Max-Forwards header: "
+ event);
return;
}
}
// using asterisk voice mail initial notify for messages
// is ok, but on the fly received messages their notify comes
// without subscription-state, so we add it in order to be able to
// process message.
if(request.getMethod().equals(Request.NOTIFY)
&& request.getHeader(EventHeader.NAME) != null
&& ((EventHeader)request.getHeader(EventHeader.NAME))
.getEventType().equals(
OperationSetMessageWaitingSipImpl.EVENT_PACKAGE)
&& request.getHeader(SubscriptionStateHeader.NAME)
== null)
{
request.addHeader(
new HeaderFactoryImpl()
.createSubscriptionStateHeader(
SubscriptionStateHeader.ACTIVE));
}
}
catch(Throwable ex)
{
logger.warn("Cannot apply incoming request modification!", ex);
}
}
}

@ -35,6 +35,8 @@ public class ConnectionPanel
private final JTextField proxyPortField = new JTextField(4);
private final JTextField voicemailField = new JTextField(4);
private final JCheckBox proxyAutoCheckBox;
private JComboBox transportCombo = new JComboBox(new Object[]
@ -190,6 +192,18 @@ public void actionPerformed(ActionEvent evt)
mainPanel.add(Box.createVerticalStrut(5));
mainPanel.add(encryptionPanel);
JPanel voicemailPanel
= new TransparentPanel(new BorderLayout(10, 10));
voicemailPanel.add(new JLabel(
Resources.getString("plugin.sipaccregwizz.VOICEMAIL_URI")),
BorderLayout.WEST);
voicemailPanel.add(voicemailField, BorderLayout.CENTER);
voicemailField.setText(regform.getRegistration().getVoicemailURI());
mainPanel.add(Box.createVerticalStrut(5));
mainPanel.add(voicemailPanel);
this.add(mainPanel, BorderLayout.NORTH);
}
@ -486,6 +500,15 @@ String getKeepAliveInterval()
return keepAliveIntervalValue.getText();
}
/**
* Returns the voicemail URI.
* @return the voicemail URI.
*/
String getVoicemailURI()
{
return voicemailField.getText();
}
/**
* Sets the keep alive interval
* @param keepAliveInterval the keep alive interval

@ -78,6 +78,11 @@ public class SIPAccountRegistration
private String xCapPassword;
/**
* The voicemail uri if any.
*/
private String voicemailURI;
public String getPreferredTransport()
{
return preferredTransport;
@ -605,4 +610,22 @@ public void setProxyAutoConfigure(boolean proxyAutoConfigure)
{
this.proxyAutoConfigure = proxyAutoConfigure;
}
/**
* The voicemail URI.
* @return the voicemail URI.
*/
public String getVoicemailURI()
{
return voicemailURI;
}
/**
* Sets voicemail URI.
* @param voicemailURI new URI.
*/
public void setVoicemailURI(String voicemailURI)
{
this.voicemailURI = voicemailURI;
}
}

@ -259,6 +259,7 @@ public boolean commitPage(SIPAccountRegistration registration)
registration.setXCapUser(presencePanel.getXCapUser());
registration
.setXCapPassword(new String(presencePanel.getXCapPassword()));
registration.setVoicemailURI(connectionPanel.getVoicemailURI());
return true;
}

@ -281,6 +281,11 @@ public Iterator<Map.Entry<String, String>> getSummary()
Resources.getString("service.gui.NO"));
}
if(!StringUtils.isNullOrEmpty(registration.getVoicemailURI(), true))
summaryTable.put(
Resources.getString("plugin.sipaccregwizz.VOICEMAIL_URI"),
registration.getVoicemailURI());
return summaryTable.entrySet().iterator();
}
@ -480,6 +485,11 @@ else if(serverAddress == null &&
}
}
if(!StringUtils.isNullOrEmpty(registration.getVoicemailURI(), true))
accountProperties.put(
ProtocolProviderFactory.VOICEMAIL_URI,
registration.getVoicemailURI());
if(isModification)
{
accountProperties.put(ProtocolProviderFactory.USER_ID, userName);

@ -0,0 +1,95 @@
/*
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package net.java.sip.communicator.service.protocol;
import net.java.sip.communicator.service.protocol.event.*;
/**
* Provides notifications for message waiting notifications.
*
* @author Damian Minkov
*/
public interface OperationSetMessageWaiting
extends OperationSet
{
/**
* Message waiting types.
*/
public enum MessageType
{
VOICE("voice-message"),
FAX("fax-message"),
PAGER("pager-message"),
MULTIMEDIA("multimedia-message"),
TEXT("text-message"),
NONE("none");
/**
* Message type String.
*/
private String type;
/**
* Creates new message type.
* @param type the type.
*/
private MessageType(String type)
{
this.type = type;
}
/**
* Returns the type ot the message type enum element.
* @return the message type.
*/
public String toString()
{
return type;
}
/**
* Returns MessageType by its type name.
* @param type the type.
* @return the corresponding MessageType.
*/
public static MessageType valueOfByType(String type)
{
for(MessageType mt : values())
{
if(mt.toString().equals(type))
return mt;
}
return valueOf(type);
}
}
/**
* Registers a <tt>MessageWaitingListener</tt> with this
* operation set so that it gets notifications of new and old
* messages waiting.
*
* @param type register the listener for certain type of messages.
* @param listener the <tt>MessageWaitingListener</tt>
* to register.
*/
public void addMessageWaitingNotificationListener(
MessageType type,
MessageWaitingListener listener);
/**
* Unregisters <tt>listener</tt> so that it won't receive any further
* notifications upon new messages waiting notifications delivery.
*
* @param type register the listener for certain type of messages.
* @param listener the <tt>MessageWaitingListener</tt>
* to unregister.
*/
public void removeMessageWaitingNotificationListener(
MessageType type,
MessageWaitingListener listener);
}

@ -304,6 +304,12 @@ public abstract class ProtocolProviderFactory
*/
public static final String STUN_IS_TURN_SUPPORTED = "IS_TURN_SUPPORTED";
/**
* Address used to reach voicemail box, by services able to
* subscribe for voicemail new messages notifications.
*/
public static final String VOICEMAIL_URI = "VOICEMAIL_URI";
/**
* The <code>BundleContext</code> containing (or to contain) the service
* registration of this factory.

@ -0,0 +1,138 @@
/*
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package net.java.sip.communicator.service.protocol.event;
import net.java.sip.communicator.service.protocol.*;
import java.util.*;
/**
* <tt>MessageWaitingEvent<tt> indicates a message waiting event
* is received.
*
* @author Damian Minkov
*/
public class MessageWaitingEvent
extends EventObject
{
/**
* The URI we can use to reach messages from provider that is firing
* the event.
*/
private String account;
/**
* Number of new/unread messages.
*/
private int unreadMessages = 0;
/**
* Number of old/read messages.
*/
private int readMessages = 0;
/**
* Number of new/unread urgent messages.
*/
private int unreadUrgentMessages = 0;
/**
* Number of old/read messages.
*/
private int readUrgentMessages = 0;
/**
* The message type for this event.
*/
private OperationSetMessageWaiting.MessageType messageType;
/**
* Constructs the Event with the given source, typically the provider and
* number of messages.
*
* @param messageType the message type for this event.
* @param source the protocol provider from which this event is coming.
* @param account the account URI we can use to reach the messages.
* @param unreadMessages the unread messages.
* @param readMessages the read messages.
* @param unreadUrgentMessages the unread urgent messages.
* @param readUrgentMessages the read urgent messages.
*/
public MessageWaitingEvent(
ProtocolProviderService source,
OperationSetMessageWaiting.MessageType messageType,
String account,
int unreadMessages,
int readMessages,
int unreadUrgentMessages,
int readUrgentMessages)
{
super(source);
this.messageType = messageType;
this.account = account;
this.unreadMessages = unreadMessages;
this.readMessages = readMessages;
this.unreadUrgentMessages = unreadUrgentMessages;
this.readUrgentMessages = readUrgentMessages;
}
/**
* The URI we can use to reach messages from provider that is firing
* the event.
* @return account URI.
*/
public String getAccount()
{
return account;
}
/**
* Number of new/unread messages.
* @return Number of new/unread messages.
*/
public int getUnreadMessages()
{
return unreadMessages;
}
/**
* Number of old/read messages.
* @return Number of old/read messages.
*/
public int getReadMessages()
{
return readMessages;
}
/**
* Number of new/unread urgent messages.
* @return Number of new/unread urgent messages.
*/
public int getUnreadUrgentMessages()
{
return unreadUrgentMessages;
}
/**
* Number of old/read messages.
* @return Number of old/read messages.
*/
public int getReadUrgentMessages()
{
return readUrgentMessages;
}
/**
* The message type for this event.
* @return the message type.
*/
public OperationSetMessageWaiting.MessageType getMessageType()
{
return messageType;
}
}

@ -0,0 +1,21 @@
/*
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package net.java.sip.communicator.service.protocol.event;
/**
* The listener which will gather notifications for message waiting.
*
* @author Damian Minkov
*/
public interface MessageWaitingListener
{
/**
* Notifies for new messages that are waiting.
* @param evt the notification event.
*/
public void messageWaitingNotify(MessageWaitingEvent evt);
}
Loading…
Cancel
Save