aboutsummaryrefslogtreecommitdiffstats
path: root/src/net/java/sip/communicator/impl/protocol/zeroconf
diff options
context:
space:
mode:
Diffstat (limited to 'src/net/java/sip/communicator/impl/protocol/zeroconf')
-rw-r--r--src/net/java/sip/communicator/impl/protocol/zeroconf/BonjourService.java706
-rw-r--r--src/net/java/sip/communicator/impl/protocol/zeroconf/ClientThread.java499
-rw-r--r--src/net/java/sip/communicator/impl/protocol/zeroconf/ContactGroupZeroconfImpl.java595
-rw-r--r--src/net/java/sip/communicator/impl/protocol/zeroconf/ContactZeroconfImpl.java468
-rw-r--r--src/net/java/sip/communicator/impl/protocol/zeroconf/MessageZeroconfImpl.java234
-rw-r--r--src/net/java/sip/communicator/impl/protocol/zeroconf/OperationSetBasicInstantMessagingZeroconfImpl.java192
-rw-r--r--src/net/java/sip/communicator/impl/protocol/zeroconf/OperationSetPersistentPresenceZeroconfImpl.java852
-rw-r--r--src/net/java/sip/communicator/impl/protocol/zeroconf/OperationSetTypingNotificationsZeroconfImpl.java83
-rw-r--r--src/net/java/sip/communicator/impl/protocol/zeroconf/ProtocolIconZeroconfImpl.java189
-rw-r--r--src/net/java/sip/communicator/impl/protocol/zeroconf/ProtocolProviderFactoryZeroconfImpl.java120
-rw-r--r--src/net/java/sip/communicator/impl/protocol/zeroconf/ProtocolProviderServiceZeroconfImpl.java302
-rw-r--r--src/net/java/sip/communicator/impl/protocol/zeroconf/ZeroconfAccountID.java96
-rw-r--r--src/net/java/sip/communicator/impl/protocol/zeroconf/ZeroconfActivator.java132
-rw-r--r--src/net/java/sip/communicator/impl/protocol/zeroconf/ZeroconfStatusEnum.java136
-rw-r--r--src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/DNSCache.java294
-rw-r--r--src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/DNSConstants.java160
-rw-r--r--src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/DNSEntry.java183
-rw-r--r--src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/DNSIncoming.java524
-rw-r--r--src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/DNSListener.java39
-rw-r--r--src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/DNSOutgoing.java405
-rw-r--r--src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/DNSQuestion.java68
-rw-r--r--src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/DNSRecord.java796
-rw-r--r--src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/DNSState.java139
-rw-r--r--src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/HostInfo.java173
-rw-r--r--src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/JmDNS.java3048
-rw-r--r--src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/ServiceEvent.java124
-rw-r--r--src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/ServiceInfo.java785
-rw-r--r--src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/ServiceListener.java57
-rw-r--r--src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/ServiceTypeListener.java37
-rw-r--r--src/net/java/sip/communicator/impl/protocol/zeroconf/zeroconf.provider.manifest.mf12
30 files changed, 0 insertions, 11448 deletions
diff --git a/src/net/java/sip/communicator/impl/protocol/zeroconf/BonjourService.java b/src/net/java/sip/communicator/impl/protocol/zeroconf/BonjourService.java
deleted file mode 100644
index 8258da7..0000000
--- a/src/net/java/sip/communicator/impl/protocol/zeroconf/BonjourService.java
+++ /dev/null
@@ -1,706 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright @ 2015 Atlassian Pty Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.zeroconf;
-
-import java.io.*;
-import java.net.*;
-import java.util.*;
-
-import net.java.sip.communicator.impl.protocol.zeroconf.jmdns.*;
-import net.java.sip.communicator.service.protocol.*;
-import net.java.sip.communicator.util.*;
-
-/**
- * Class dealing with JmDNS and treating all the
- * incoming connections on the bonjour port
- * @author Christian Vincenot
- */
-public class BonjourService extends Thread
- implements ServiceListener,
- DNSListener
-{
- private static final Logger logger =
- Logger.getLogger(BonjourService.class);
-
- private int port = 5298;
- private ServerSocket sock = null;
- private String id = null;
- private JmDNS jmdns=null;
- private final Map<String, Object> props = new Hashtable<String, Object>();
- private ServiceInfo service = null;
- private boolean dead = false;
-
- private final List<ContactZeroconfImpl> contacts
- = new Vector<ContactZeroconfImpl>();
-
- private ProtocolProviderServiceZeroconfImpl pps;
- OperationSetPersistentPresenceZeroconfImpl opSetPersPresence;
-
- private ZeroconfAccountID acc;
-
- /* Should maybe better get the status directly from OperationSetPresence */
- private PresenceStatus status = ZeroconfStatusEnum.OFFLINE;
-
- /**
- * Returns the corresponding ProtocolProviderService
- * @return corresponding ProtocolProviderService
- */
- public ProtocolProviderServiceZeroconfImpl getPPS()
- {
- return pps;
- }
-
- /**
- * Returns the id of this service.
- * @return returns the id of this service.
- */
- String getID()
- {
- return id;
- }
-
- /**
- * Creates a new instance of the Bonjour service thread
- * @param port TCP Port number on which to try to start the Bonjour service
- * @param pps ProtocolProviderService instance
- * which is creating this BonjourService
- */
- public BonjourService(int port,
- ProtocolProviderServiceZeroconfImpl pps)
- {
- this.acc = (ZeroconfAccountID) pps.getAccountID();
- this.port = port;
- this.id = acc.getUserID();
- this.pps = pps;
-
- opSetPersPresence =
- (OperationSetPersistentPresenceZeroconfImpl) pps
- .getOperationSet(OperationSetPersistentPresence.class);
-
- // Gaim
- props.put("1st", (acc.getFirst() == null)? "":acc.getFirst());
- props.put("email", (acc.getMail() == null)? "":acc.getMail());
- props.put("jid", this.id);
- props.put("last", (acc.getLast() == null)?"":acc.getLast());
- props.put("msg", opSetPersPresence.getCurrentStatusMessage());
- props.put("status", "avail");
-
- //iChat
- props.put("phsh","000");
- //props.put("status","avail");
- //props.put("port.p2pj", "5298");
- props.put("vc", "C!");
- //props.put("1st", "John");
- props.put("txtvers","1");
-
- //XEP-0174 (Final paper)
- props.put("ext","");
- props.put("nick", (acc.getFirst() == null)? this.id:acc.getFirst());
- props.put("ver", "1");
- props.put("node", "SIP Communicator");
-
- //Ours
- props.put("client", "SIP Communicator");
-
- changeStatus(opSetPersPresence.getPresenceStatus());
-
- sock = createSocket(port);
- if (sock == null)
- return;
-
- port = sock.getLocalPort();
-
- if (logger.isDebugEnabled())
- logger.debug("ZEROCONF: ServerSocket bound to port "+port);
-
- props.put("port.p2pj", Integer.toString(port));
- this.setDaemon(true);
- this.start();
- }
-
- /* TODO: Better exception checking to avoid sudden exit and bonjour
- * service shutdown */
-
- /**
- * Walk?
- */
- @Override
- public void run()
- {
- if (logger.isDebugEnabled())
- logger.debug("ZEROCONF: Bonjour Service Thread up and running!");
-
- /* Put jmDNS in DEBUD Mode :
- * Following verbosity levels can be chosen :
- * "INFO" , "WARNING", "SEVERE", "ALL", "FINE", "FINER", "FINEST", etc
- */
- //System.setProperty("jmdns.debug", "0");
-
- while (dead == false)
- {
- if (sock == null || sock.isClosed())
- {
- sock = createSocket(port);
- /* What should we do now? TEMPORARY: shutdown()*/
- if (sock == null) shutdown();
- port = sock.getLocalPort();
- props.put("port.p2pj", Integer.toString(port));
- //TODO: update JmDNS in case the port had to be changed!
- }
- try
- {
- Socket connection = sock.accept();
- ContactZeroconfImpl contact = getContact(null,
- connection.getInetAddress());
- /*if (status.equals(ZeroconfStatusEnum.OFFLINE)
- || status.equals(ZeroconfStatusEnum.INVISIBLE) */
- if (dead == true) break;
-
- if ((contact == null)
- || (contact.getClientThread() != null))
- {
- if (contact == null)
- logger.error("ZEROCONF: Connexion from "
- + "unknown contact ["
- + connection.getInetAddress()
- +"]. REJECTING!");
- else if (contact.getClientThread() == null)
- logger.error("ZEROCONF: Redundant chat "
- + "channel ["
- + contact
- +"]. REJECTING!");
- connection.close();
- }
- else new ClientThread(connection, this);
- }
- catch(Exception e)
- {
- logger.error(e);
- }
- }
-
- if (logger.isDebugEnabled())
- logger.debug("ZEROCONF: Going Offline - "
- +"BonjourService Thread exiting!");
- }
-
- /**
- * Might be used for shutdown...
- */
- public void shutdown()
- {
- if (logger.isDebugEnabled())
- logger.debug("ZEROCONF: Shutdown!");
-
- dead = true;
- try
- { sock.close(); }
- catch (Exception ex)
- { logger.error(ex); }
-
- changeStatus(ZeroconfStatusEnum.OFFLINE);
- if(jmdns != null)
- jmdns.close();
- }
-
- private ServerSocket createSocket(int port)
- {
- ServerSocket sock=null;
- try
- {
- sock = new ServerSocket(port);
- }
- catch(Exception e)
- {
- logger.error("ZEROCONF: Couldn't bind socket to port "
- +port+"! Switching to an other port...");
- try
- {
- sock = new ServerSocket(0);
- }
- catch (IOException ex)
- {
- logger.error("ZEROCONF: FATAL ERROR => "
- +"Couldn't bind to a port!!", ex);
- }
- }
-
- return sock;
- }
-
- /**
- * Changes the status of the local user.
- * @param stat New presence status
- */
- public void changeStatus(PresenceStatus stat)
- {
- /* [old_status == new_status ?] => NOP */
- if (stat.equals(status))
- return;
-
- /* [new_status == OFFLINE ?] => clean up everything */
- if (stat.equals(ZeroconfStatusEnum.OFFLINE))
- {
- if (logger.isDebugEnabled())
- logger.debug("ZEROCONF: Going OFFLINE");
- //jmdns.unregisterAllServices();
- jmdns.removeServiceListener("_presence._tcp.local.", this);
- jmdns.close();
- jmdns=null;
- //dead = true;
-
- // Erase all contacts by putting them OFFLINE
- opSetPersPresence.changePresenceStatusForAllContacts(
- opSetPersPresence.getServerStoredContactListRoot(), stat);
-
- try
- {
- sleep(1000);
- } catch (InterruptedException ex)
- {
- logger.error(ex);
- }
- }
-
- /* [old_status == OFFLINE ?] => register service */
- else if (status.equals(ZeroconfStatusEnum.OFFLINE))
- {
- if (logger.isDebugEnabled())
- logger.debug("ZEROCONF: Getting out of OFFLINE state");
- props.put("status", stat.getStatusName());
- service = new ServiceInfo("_presence._tcp.local.", id,
- port, 0, 0, props);
-
- try
- {
- jmdns = new JmDNS();
- jmdns.registerServiceType("_presence._tcp.local.");
- jmdns.addServiceListener("_presence._tcp.local.", this);
- jmdns.registerService(service);
-
- /* In case the ID had to be changed */
- id = service.getName();
- }
- catch (Exception ex)
- { logger.error(ex); }
-
- //dead = false;
-
- /* Normal status change */
- }
- else
- {
- if (logger.isDebugEnabled())
- logger.debug("ZEROCONF : Changing status");
-
- props.put("status", stat.getStatusName());
-
- /* FIXME: Not totally race condition free since the 3 calls aren't
- * atomic, but that's not really critical since there's little
- * change chance of concurrent local contact change, and this
- * wouldn't have big consequences.
- */
- ServiceInfo info =
- jmdns.getLocalService(id.toLowerCase()+"._presence._tcp.local.");
- if (info == null)
- logger.error("ZEROCONF/JMDNS: PROBLEM GETTING "
- +"LOCAL SERVICEINFO !!");
-
- byte[] old = info.getTextBytes();
- info.setProps(props);
- jmdns.updateInfos(info, old);
- }
-
- status = stat;
- }
-
- private class AddThread extends Thread
- {
- private String type, name;
- public AddThread(String type, String name)
- {
- this.setDaemon(true);
- this.type = type;
- this.name = name;
- this.start();
- }
-
- @Override
- public void run()
- {
- ServiceInfo service = null;
- while ((service == null) && (dead == false)
- && !status.equals(ZeroconfStatusEnum.OFFLINE))
- {
- service = jmdns.getServiceInfo(type, name, 10000);
- if (service == null)
- logger.error("BONJOUR: ERROR - Service Info of "
- + name +" not found in cache!!");
- try
- {
- sleep(2);
- }
- catch (InterruptedException ex)
- {
- logger.error(ex);
- }
- }
- if ((dead == false) && !status.equals(ZeroconfStatusEnum.OFFLINE))
- jmdns.requestServiceInfo(type, name);
- //} else handleResolvedService(name, type, service);
- }
- }
-
- /* Service Listener Implementation */
-
- /**
- * A service has been added.
- *
- * @param event The ServiceEvent providing the name and fully qualified type
- * of the service.
- */
- public void serviceAdded(ServiceEvent event)
- {
- /* WARNING: DONT PUT ANY BLOCKING CALLS OR FLAWED LOOPS IN THIS METHOD.
- * JmDNS calls this method without creating a new thread, so if this
- * method doesn't return, jmDNS will hang !!
- */
-
- String name = event.getName();
- String type = event.getType();
-
- if (name.equals(id))
- return;
-
- if (logger.isDebugEnabled())
- logger.debug("BONJOUR: "+name
- +"["+type+"] detected! Trying to get information...");
- try
- {
- sleep(2);
- }
- catch (InterruptedException ex)
- {
- logger.error(ex);
- }
-
- jmdns.printServices();
-
- new AddThread(type, name);
- }
-
-
-
- /**
- * A service has been removed.
- *
- * @param event The ServiceEvent providing the name and fully qualified type
- * of the service.
- */
- public void serviceRemoved(ServiceEvent event)
- {
- String name = event.getName();
- if (name.equals(id))
- return;
-
- ContactZeroconfImpl contact = getContact(name, null);
-
- if(contact == null)
- return;
-
- opSetPersPresence.changePresenceStatusForContact(contact,
- ZeroconfStatusEnum.OFFLINE);
- if (logger.isDebugEnabled())
- logger.debug("BONJOUR: Received announcement that "
- +name+" went offline!");
-
- }
-
- /**
- * A service has been resolved. Its details are now available in the
- * ServiceInfo record.
- *
- * @param event The ServiceEvent providing the name, the fully qualified
- * type of the service, and the service info record,
- * or null if the service could not be resolved.
- */
- public void serviceResolved(ServiceEvent event)
- {
- String contactID = event.getName();
- String type = event.getType();
- ServiceInfo info = event.getInfo();
-
- if (logger.isDebugEnabled())
- logger.debug("BONJOUR: Information about "
- +contactID+" discovered");
-
- handleResolvedService(contactID, type, info);
- }
-
- private void handleResolvedService(String contactID,
- String type,
- ServiceInfo info)
- {
- if (contactID.equals(id))
- return;
-
- if (info.getAddress().toString().length() > 15)
- {
- if (logger.isDebugEnabled())
- logger.debug("ZEROCONF: Temporarily ignoring IPv6 addresses!");
- return;
- }
-
- ContactZeroconfImpl newFriend;
-
- synchronized(this)
- {
- if (getContact(contactID, info.getAddress()) != null)
- {
- if (logger.isDebugEnabled())
- logger.debug("Contact "
- +contactID+" already in contact list! Skipping.");
- return;
- };
- if (logger.isDebugEnabled())
- logger.debug("ZEROCNF: ContactID " + contactID +
- " Address " + info.getAddress());
-
- if (logger.isDebugEnabled())
- logger.debug(" Address=>"+info.getAddress()
- +":"+info.getPort());
-
- for (Iterator<String> names = info.getPropertyNames();
- names.hasNext();)
- {
- String prop = names.next();
- if (logger.isDebugEnabled())
- logger.debug(" "+prop+"=>"
- +info.getPropertyString(prop));
- }
-
- /* Creating the contact */
- String name = info.getPropertyString("1st");
- if (info.getPropertyString("last") != null)
- name += " "+ info.getPropertyString("last");
-
- int port = Integer.valueOf(
- info.getPropertyString("port.p2pj")).intValue();
-
- if (port < 1)
- {
- logger.error("ZEROCONF: Flawed contact announced himself"
- +"without necessary parameters : "+contactID);
- return;
- }
-
- if (logger.isDebugEnabled())
- logger.debug("ZEROCONF: Detected client "+name);
-
- newFriend =
- opSetPersPresence.createVolatileContact(
- contactID, this, name,
- info.getAddress(), port);
- }
- /* Try to detect which client type it is */
- int clientType = ContactZeroconfImpl.XMPP;
- if (info.getPropertyString("client") != null
- && info.getPropertyString("client").
- compareToIgnoreCase("SIP Communicator") == 0)
- clientType = ContactZeroconfImpl.SIPCOM;
-
- else if ((info.getPropertyString("jid") != null)
- && (info.getPropertyString("node") == null))
- clientType = ContactZeroconfImpl.GAIM;
-
- else if (info.getPropertyString("jid") == null)
- clientType = ContactZeroconfImpl.ICHAT;
-
- newFriend.setClientType(clientType);
- if (logger.isDebugEnabled())
- logger.debug("ZEROCONF: CLIENT TYPE "+clientType);
-
- ZeroconfStatusEnum status =
- ZeroconfStatusEnum.statusOf(info.getPropertyString("status"));
- opSetPersPresence.
- changePresenceStatusForContact(newFriend,
- status == null?ZeroconfStatusEnum.ONLINE:status);
-
- // Listening for changes
- jmdns.addListener(this, new DNSQuestion(info.getQualifiedName(),
- DNSConstants.TYPE_SRV,
- DNSConstants.CLASS_UNIQUE));
- }
-
- /**
- * Callback called by JmDNS to inform the
- * BonjourService of a potential status change of some contacts.
- * @param jmdns JmDNS instance responsible for this
- * @param now Timestamp
- * @param record DNSRecord which changed
- */
- public synchronized void updateRecord( JmDNS jmdns,
- long now,
- DNSRecord record)
- {
- if (logger.isDebugEnabled())
- logger.debug("ZEROCONF/JMDNS: Received record update for "+record);
-
- int clazz = record.getClazz();
- int type = record.getType();
-
- /* Check the info returned by JmDNS since we can't really trust its
- * filtering. */
- if (!(((type & DNSConstants.TYPE_TXT) != 0) &&
- ((clazz & DNSConstants.CLASS_IN) != 0) &&
- record.isUnique() &&
- record.getName().endsWith("_presence._tcp.local.")))
- return;
-
- String name = record.getName().replaceAll("._presence._tcp.local.","");
- ContactZeroconfImpl contact;
-
- synchronized(this)
- {
- contact = getContact(name, null);
-
- if (contact == null) { //return;
- logger.error("ZEROCONF: BUG in jmDNS => Received update without "
- +"previous contact annoucement. Trying to add contact");
- new AddThread("_presence._tcp.local.", name);
- return;
- }
- }
-
- if (logger.isDebugEnabled())
- logger.debug("ZEROCONF: "+ name
- + " changed status. Requesting fresh data!");
-
- /* Since a record was updated, we can be sure that we can do a blocking
- * getServiceInfo without risk. (Still, we use the method with timeout
- * to avoid bad surprises). If some problems of status change refresh
- * appear, we'll have to fall back on the method with callback as we've
- * done for "ServiceAdded".
- */
-
- ServiceInfo info = jmdns.getServiceInfo("_presence._tcp.local.", name,
- 1000);
- if (info == null)
- {
- logger.error("ZEROCONF/JMDNS: Problem!! The service "
- +"information was not in cache. See comment in "
- +"BonjourService.java:updateRecord !!");
- return;
- }
-
- /* Let's change what we can : status, message, etc */
- ZeroconfStatusEnum status =
- ZeroconfStatusEnum.statusOf(info.getPropertyString("status"));
-
- opSetPersPresence.
- changePresenceStatusForContact(contact,
- status == null ? ZeroconfStatusEnum.ONLINE:status);
-
- }
-
- /**
- * Returns an Iterator over all contacts.
- *
- * @return a java.util.Iterator over all contacts
- */
- public Iterator<ContactZeroconfImpl> contacts()
- {
- return contacts.iterator();
- }
-
- /**
- * Adds a contact to the locally stored list of contacts
- * @param contact Zeroconf Contact to add to the local list
- */
- public void addContact(ContactZeroconfImpl contact)
- {
- if (contact == null)
- throw new IllegalArgumentException("contact");
-
- synchronized(contacts)
- {
- contacts.add(contact);
- }
- }
- /**
- * Returns the <tt>Contact</tt> with the specified identifier or IP address.
- *
- * @param id the identifier of the <tt>Contact</tt> we are
- * looking for.
- * @param ip the IP address of the <tt>Contact</tt> we are looking for.
- * @return the <tt>Contact</tt> with the specified id or address.
- */
- public ContactZeroconfImpl getContact(String id, InetAddress ip)
- {
- if (id == null && ip == null) return null;
-
- synchronized(contacts)
- {
- Iterator<ContactZeroconfImpl> contactsIter = contacts();
-
- while (contactsIter.hasNext())
- {
- ContactZeroconfImpl contact = contactsIter.next();
- //System.out.println("ZEROCNF: Comparing "+id+ " "+ip+
- //" with "+ contact.getAddress()+ " " + contact.getIpAddress());
- if (((contact.getAddress().equals(id)) || (id == null))
- && ((contact.getIpAddress().equals(ip)) || (ip == null)))
- return contact;
-
- }
- }
- //System.out.println("ZEROCNF: ERROR - " +
- //"Couldn't find contact to get ["+id+" / "+ip+"]");
- return null;
- }
-
- /**
- * Removes the <tt>Contact</tt> with the specified identifier or IP address.
- *
- *
- * @param id the identifier of the <tt>Contact</tt> we are
- * looking for.
- * @param ip the IP address of the <tt>Contact</tt> we are looking for.
- */
- public void removeContact(String id, InetAddress ip)
- {
- synchronized(contacts)
- {
- Iterator<ContactZeroconfImpl> contactsIter = contacts();
- while (contactsIter.hasNext())
- {
- ContactZeroconfImpl contact = contactsIter.next();
- if (((contact.getAddress().equals(id)) || (id == null))
- &&((contact.getIpAddress().equals(ip)) || (ip == null)))
- {
- if (contact.getClientThread() != null)
- contact.getClientThread().cleanThread();
- contacts.remove(contact);
- return;
- }
- };
- }
- logger.error(
- "ZEROCONF: ERROR - Couldn't find contact to delete ["+id+" / "+ip+"]");
- }
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/zeroconf/ClientThread.java b/src/net/java/sip/communicator/impl/protocol/zeroconf/ClientThread.java
deleted file mode 100644
index 4367eed..0000000
--- a/src/net/java/sip/communicator/impl/protocol/zeroconf/ClientThread.java
+++ /dev/null
@@ -1,499 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright @ 2015 Atlassian Pty Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.zeroconf;
-
-import java.io.*;
-import java.net.*;
-
-import net.java.sip.communicator.service.protocol.*;
-import net.java.sip.communicator.util.*;
-
-/**
- * Class creating a thread responsible for handling the chat
- * with the remote user on the other end of the socket
- *
- * @author Christian Vincenot
- */
-public class ClientThread
- extends Thread
-{
- private static final Logger logger = Logger.getLogger(ClientThread.class);
-
- private OperationSetBasicInstantMessagingZeroconfImpl opSetBasicIM;
- private OperationSetTypingNotificationsZeroconfImpl opSetTyping;
- private Socket sock;
- private InetAddress remoteIPAddress;
- private OutputStream out;
- private DataInputStream in;
- private BonjourService bonjourService;
- private ContactZeroconfImpl contact=null;
- private boolean streamState = false;
-
- private String messagesQueue=null;
-
- /**
- * Sets the contact with which we're chatting in this ClientThread
- * @param contact Zeroconf contact with which we're chatting
- */
- protected void setContact(ContactZeroconfImpl contact)
- {
- this.contact = contact;
- }
-
- /**
- * Set the stream as opened. This means that the
- * conversation with the client is really opened
- * from now on (the XML greetings are over)
- */
- protected void setStreamOpen()
- {
- synchronized(this)
- {
- this.streamState = true;
- }
- }
-
- /**
- * Says if the stream between the local user and the remote user
- * is in an opened state (greetings are over and we can chat)
- * @return Returns true if the stream is "opened" (ie, ready for chat)
- */
- protected boolean isStreamOpened()
- {
- synchronized(this)
- {
- return this.streamState;
- }
- }
-
- /**
- * Creates a new instance of ClientThread reponsible
- * for handling the conversation with the remote user.
- * @param sock Socket created for chatting
- * @param bonjourService BonjourService which spawned this ClientThread
- */
- public ClientThread(Socket sock, BonjourService bonjourService)
- {
- this.sock = sock;
- this.remoteIPAddress = sock.getInetAddress();
- this.bonjourService = bonjourService;
- this.opSetBasicIM =
- (OperationSetBasicInstantMessagingZeroconfImpl) bonjourService
- .getPPS().getOperationSet(
- OperationSetBasicInstantMessaging.class);
-
- this.opSetTyping =
- (OperationSetTypingNotificationsZeroconfImpl) bonjourService
- .getPPS()
- .getOperationSet(OperationSetTypingNotifications.class);
- this.setDaemon(true);
-
- try
- {
- out = sock.getOutputStream();
- in = new DataInputStream(sock.getInputStream());
- }
- catch (IOException e)
- {
- logger.error("Creating ClientThread: Couldn't get I/O for "
- +"the connection", e);
- //System.exit(1);
- return;
- }
-
- this.start();
- }
-
- /*
- * Read a message from the socket.
- * TODO: clean the code a bit and optimize it.
- */
- private String readMessage()
- {
- String line;
- byte[] bytes = new byte[10];
-
- try
- {
- int i=0;
-
- while (i < 9)
- {
- i += in.read(bytes,0,9-i);
- }
-
- line = new String(bytes);
- bytes = new byte[1];
- if ((line.getBytes())[0] == '\n')
- line = line.substring(1);
-
- if (line.startsWith("<message"))
- {
- while (true)
- {
- bytes[0] = in.readByte();
- line += new String(bytes);
-
- if ((line.endsWith("</message>"))
- || (line.endsWith("stream>")))
- return line;
- }
- }
- else
- {
- while (true)
- {
- bytes[0] = in.readByte();
- line += new String(bytes);
- if ( ">".compareTo(new String(bytes)) == 0 )
- return line;
- }
- }
- }
- catch (IOException e)
- {
- logger.error("Couldn't get I/O for the connection", e);
- //System.exit(1);
- }
-
- return null;
- }
-
- /*
- * Parse the payload and extract the information.
- * TODO: If needed, fill in the remaining fields of MessageZeroconfImpl
- * like the baloon icon color, color/size/font of the text.
- */
- private MessageZeroconfImpl parseMessage(String str)
- {
- if (str.startsWith("<?xml") || str.startsWith("<stream"))
- return new MessageZeroconfImpl
- (null, null, MessageZeroconfImpl.STREAM_OPEN);
-
- if (str.endsWith("stream>"))
- return new MessageZeroconfImpl
- (null, null, MessageZeroconfImpl.STREAM_CLOSE);
-
- if ((str.indexOf("<delivered/>") > 0) && (str.indexOf("<body>") < 0))
- return new MessageZeroconfImpl
- (null, null, MessageZeroconfImpl.DELIVERED);
-
- if (!str.startsWith("<message"))
- return new MessageZeroconfImpl
- (null, null, MessageZeroconfImpl.UNDEF);
-
- /* TODO: Parse Enconding (& contact id to be able to double-check
- * the source of a message)
- *
- * TODO: Check that the fields are outside of <body>..</body>
- */
-
- if ((str.indexOf("<body>") < 0) || (str.indexOf("</body>") < 0))
- return new MessageZeroconfImpl
- (null, null, MessageZeroconfImpl.UNDEF);
-
- String temp =
- str.substring(str.indexOf("<body>")+6, str.indexOf("</body>"));
-
- if (logger.isDebugEnabled())
- logger.debug("ZEROCONF: received message ["+temp+"]");
-
- int messageType = MessageZeroconfImpl.MESSAGE;
-
- if ((str.indexOf("<id>") >= 0) && (str.indexOf("</id>") >= 0))
- messageType = MessageZeroconfImpl.TYPING;
-
- MessageZeroconfImpl msg =
- new MessageZeroconfImpl(
- temp,
- null,
- OperationSetBasicInstantMessaging.DEFAULT_MIME_TYPE,
- messageType);
-
- return msg;
- }
-
- private int handleMessage(MessageZeroconfImpl msg)
- {
-
- switch(msg.getType())
- {
- /* STREAM INIT */
- case MessageZeroconfImpl.STREAM_OPEN:
- if (contact == null)
- contact = bonjourService.getContact(null, remoteIPAddress);
- if (!isStreamOpened())
- {
- sendHello();
- setStreamOpen();
- }
- if (messagesQueue != null)
- {
- write(messagesQueue);
- messagesQueue = null;
- }
- break;
-
- /* ACK */
- case MessageZeroconfImpl.DELIVERED : break;
-
- /* NORMAL MESSAGE */
- case MessageZeroconfImpl.MESSAGE:
- if (!isStreamOpened())
- if (logger.isDebugEnabled())
- logger.debug("ZEROCONF: client on the other side "
- +"isn't polite (sending messages without "
- +"saying hello :P");
- if (contact == null)
- //TODO: Parse contact id to double-check
- contact = bonjourService.getContact(null, remoteIPAddress);
-
- /* TODO: If we want to implement invisible status, we'll have to
- * make this test less restrictive to handle messages from
- * unannounced clients.
- */
- if (contact == null)
- {
- logger.error("ZEROCONF: ERROR - Couldn't identify "
- +"contact. Closing socket.");
- return -1;
- }
- else if (contact.getClientThread() == null)
- contact.setClientThread(this);
-
- opSetBasicIM.fireMessageReceived(msg, contact);
-
- opSetTyping.fireTypingNotificationsEvent(contact,
- OperationSetTypingNotificationsZeroconfImpl.STATE_STOPPED);
- break;
-
- case MessageZeroconfImpl.TYPING:
- if (!isStreamOpened())
- if (logger.isDebugEnabled())
- logger.debug("ZEROCONF: client on the other side "
- +"isn't polite (sending messages without "
- +"saying hello :P");
- if (contact == null)
- //TODO: Parse contact id to double-check
- contact = bonjourService.getContact(null, remoteIPAddress);
- opSetTyping.fireTypingNotificationsEvent(contact,
- OperationSetTypingNotificationsZeroconfImpl.STATE_TYPING);
-
- /* TODO: code a private runnable class to be used as timeout
- * to set the typing state to STATE_PAUSED when a few seconds
- * without news have passed.
- */
-
- break;
-
- case MessageZeroconfImpl.STREAM_CLOSE:
- sendBye();
- contact.setClientThread(null);
- return 1;
-
- case MessageZeroconfImpl.UNDEF:
- logger.error("ZEROCONF: received strange message. SKIPPING!");
- break;
- }
-
- //System.out.println("RECEIVED MESSAGE "+ msg.getContent()+
- //" from "+contact.getAddress() + "!!!!!!!!!!!!!!");
- return 0;
- }
-
-
- private void write(String string)
- {
- //System.out.println("Writing " + string + "!!!!!!!!!");
- byte[] bytes = string.getBytes();
- try
- {
- out.write(bytes);
- out.flush();
- }
- catch (IOException e)
- {
- logger.error("Couldn't get I/O for the connection");
- if (contact != null)
- {
- contact.setClientThread(null);
- }
-
- try
- {
- sock.close();
- }
- catch (IOException ex)
- {
- logger.error(ex);
- }
-
- }
- }
-
- /**
- * Say hello :)
- */
- protected void sendHello()
- {
- switch(contact.getClientType())
- {
- case ContactZeroconfImpl.GAIM:
- case ContactZeroconfImpl.ICHAT:
- case ContactZeroconfImpl.SIPCOM:
- write("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>");
- write("<stream:stream xmlns=\"jabber:client\" "
- +"xmlns:stream=\"http://etherx.jabber.org/streams\">");
- break;
- case ContactZeroconfImpl.XMPP:
- write("<stream:stream"
- +"xmlns='jabber:client'"
- +"xmlns:stream='http://etherx.jabber.org/streams'"
- +"from='"+bonjourService.getID()+"'"
- +"to='"+contact.getAddress()+"'"
- +"version='1.0'>\n");
- break;
- }
-
- /* Legacy: OLD XMPP (XEP-0174 Draft) */
- //write("<stream:stream to='"+sock.getInetAddress().getHostAddress()
- //+"' xmlns='jabber:client' stream='http://etherx.jabber.org/streams'>");
- }
-
- private void sendBye()
- {
- write("</stream:stream>\n");
- }
-
- private String toXHTML(MessageZeroconfImpl msg)
- {
- switch(contact.getClientType())
- {
- case ContactZeroconfImpl.XMPP:
- return new String("<message to='"
- +contact.getAddress()+"' from='"
- +bonjourService.getID()+"'>"
- + "<body>"+msg.getContent()+"</body>"
- + "</message>\n");
-
- case ContactZeroconfImpl.SIPCOM:
-
- case ContactZeroconfImpl.ICHAT:
- return new String(
- "<message to='"+sock.getInetAddress().getHostAddress()
- +"' type='chat' id='"+bonjourService.getID()+"'>"
- + "<body>"+msg.getContent()+"</body>"
- + "<html xmlns='http://www.w3.org/1999/xhtml'>"
- + "<body ichatballooncolor='#7BB5EE' "
- + "ichattextcolor='#000000'>"
- + "<font face='Helvetica' ABSZ='12' color='#000000'>"
- + msg.getContent()
- + "</font>"
- + "</body>"
- + "</html>"
- + "<x xmlns='jabber:x:event'>"
- + "<offline/>"
- + "<delivered/>"
- + "<composing/>"
- + (msg.getType()==MessageZeroconfImpl.TYPING?"<id></id>":"")
- + "</x>"
- + "</message>");
-
- case ContactZeroconfImpl.GAIM:
- default:
- return new String(
- "<message to='"+contact.getAddress()
- +"' from='"+bonjourService.getID()
- + "' type='chat'><body>"+msg.getContent()+"</body>"
- + "<html xmlns='http://www.w3.org/1999/xhtml'><body><font>"
- + msg.getContent()
- + "</font></body></html><x xmlns='jabber:x:event'><composing/>"
- + (msg.getType()==MessageZeroconfImpl.TYPING?"<id></id>":"")
- + "</x></message>\n");
- }
- }
-
-
- /**
- * Send a message to the remote user
- * @param msg Message to send
- */
- public void sendMessage(MessageZeroconfImpl msg)
- {
- if (logger.isDebugEnabled())
- logger.debug("ZEROCONF: Sending messag ["
- +msg.getContent()+"] to "
- + contact.getDisplayName());
- if (!isStreamOpened())
- {
- if (logger.isDebugEnabled())
- logger.debug("ZEROCONF: Stream not opened... "
- +"will send the message later");
- messagesQueue += toXHTML(msg);
- }
- else write(toXHTML(msg));
- }
-
- /**
- * Walk?
- */
- @Override
- public void run()
- {
- if (logger.isDebugEnabled())
- logger.debug("Bonjour: NEW CONNEXION from "
- + sock.getInetAddress().getCanonicalHostName()
- +" / "+sock.getInetAddress().getHostAddress());
- String input;
- MessageZeroconfImpl msg=null;
-
-
- input = readMessage();
- msg = parseMessage(input);
-
- while (handleMessage(msg) == 0 && !sock.isClosed())
- {
- input = readMessage();
- msg = parseMessage(input);
- }
-
- if (logger.isDebugEnabled())
- logger.debug("ZEROCONF : OUT OF LOOP !! Closed chat.");
- cleanThread();
- }
-
- /**
- * Clean-up the thread to exit
- */
- public void cleanThread()
- {
- /* I wonder if that's ok... */
- if (sock != null && sock.isClosed() == false)
- {
- sendBye();
- try
- {
- sock.close();
- }
- catch (IOException ex)
- {
- logger.error(ex);
- }
- }
- }
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/zeroconf/ContactGroupZeroconfImpl.java b/src/net/java/sip/communicator/impl/protocol/zeroconf/ContactGroupZeroconfImpl.java
deleted file mode 100644
index 568e087..0000000
--- a/src/net/java/sip/communicator/impl/protocol/zeroconf/ContactGroupZeroconfImpl.java
+++ /dev/null
@@ -1,595 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright @ 2015 Atlassian Pty Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.zeroconf;
-
-import java.util.*;
-
-import net.java.sip.communicator.service.protocol.*;
-
-/**
- * A simple, straightforward implementation of a zeroconf ContactGroup. Since
- * the Zeroconf protocol, we simply store all group details
- * in class fields. You should know that when implementing a real protocol,
- * the contact group implementation would rather encapsulate group objects from
- * the protocol stack and group property values should be returned by consulting
- * the encapsulated object.
- *
- * @author Christian Vincenot
- * @author Maxime Catelin
- * @author Jonathan Martin
- */
-public class ContactGroupZeroconfImpl
- implements ContactGroup
-{
-
- /**
- * The name of this Zeroconf contact group.
- */
- private String groupName = null;
-
- /**
- * The list of this group's members.
- */
- private Vector<Contact> contacts = new Vector<Contact>();
-
- /**
- * The list of sub groups belonging to this group.
- */
- private Vector<ContactGroup> subGroups = new Vector<ContactGroup>();
-
- /**
- * The group that this group belongs to (or null if this is the root group).
- */
- private ContactGroupZeroconfImpl parentGroup = null;
-
- /**
- * Determines whether this group is really in the contact list or whether
- * it is here only temporarily and will be gone next time we restart.
- */
- private boolean isPersistent = false;
-
- /**
- * The protocol provider that created us.
- */
- private ProtocolProviderServiceZeroconfImpl parentProvider = null;
-
- /**
- * Determines whether this group has been resolved on the server.
- * Unresolved groups are groups that were available on previous runs and
- * that the meta contact list has stored. During all next runs, when
- * bootstrapping, the meta contact list would create these groups as
- * unresolved. Once a protocol provider implementation confirms that the
- * groups are still on the server, it would issue an event indicating that
- * the groups are now resolved.
- */
- private boolean isResolved = true;
-
- /**
- * An id uniquely identifying the group. For many protocols this could be
- * the group name itself.
- */
- private String uid = null;
- private static final String UID_SUFFIX = ".uid";
-
- /**
- * Creates a ContactGroupZeroconfImpl with the specified name.
- *
- * @param groupName the name of the group.
- * @param parentProvider the protocol provider that created this group.
- */
- public ContactGroupZeroconfImpl(
- String groupName,
- ProtocolProviderServiceZeroconfImpl parentProvider)
- {
- this.groupName = groupName;
- this.uid = groupName + UID_SUFFIX;
- this.parentProvider = parentProvider;
- }
-
- /**
- * Determines whether the group may contain subgroups or not.
- *
- * @return always true in this implementation.
- */
- public boolean canContainSubgroups()
- {
- return true;
- }
-
- /**
- * Returns the protocol provider that this group belongs to.
- * @return a regerence to the ProtocolProviderService instance that this
- * ContactGroup belongs to.
- */
- public ProtocolProviderService getProtocolProvider()
- {
- return parentProvider;
- }
-
- /**
- * Returns an Iterator over all contacts, member of this
- * <tt>ContactGroup</tt>.
- *
- * @return a java.util.Iterator over all contacts inside this
- * <tt>ContactGroup</tt>
- */
- public Iterator<Contact> contacts()
- {
- return contacts.iterator();
- }
-
- /**
- * Adds the specified contact to this group.
- * @param contactToAdd the ContactZeroconfImpl to add to this group.
- */
- public void addContact(ContactZeroconfImpl contactToAdd)
- {
- this.contacts.add(contactToAdd);
- contactToAdd.setParentGroup(this);
- }
-
- /**
- * Returns the number of <tt>Contact</tt> members of this
- * <tt>ContactGroup</tt>
- *
- * @return an int indicating the number of <tt>Contact</tt>s, members of
- * this <tt>ContactGroup</tt>.
- */
- public int countContacts()
- {
- return contacts.size();
- }
-
- /**
- * Returns the number of subgroups contained by this
- * <tt>ContactGroup</tt>.
- *
- * @return the number of subGroups currently added to this group.
- */
- public int countSubgroups()
- {
- return subGroups.size();
- }
-
- /**
- * Adds the specified contact group to the contained by this group.
- * @param subgroup the ContactGroupZeroconfImpl to add as a
- * subgroup to this group.
- */
- public void addSubgroup(ContactGroupZeroconfImpl subgroup)
- {
- this.subGroups.add(subgroup);
- subgroup.setParentGroup(this);
- }
-
- /**
- * Sets the group that is the new parent of this group
- * @param parent ContactGroupZeroconfImpl
- */
- void setParentGroup(ContactGroupZeroconfImpl parent)
- {
- this.parentGroup = parent;
- }
-
- /**
- * Returns the contact group that currently contains this group or null if
- * this is the root contact group.
- * @return the contact group that currently contains this group or null if
- * this is the root contact group.
- */
- public ContactGroup getParentContactGroup()
- {
- return this.parentGroup;
- }
-
- /**
- * Removes the specified contact group from the this group's subgroups.
- * @param subgroup the ContactGroupZeroconfImpl subgroup to remove.
- */
- public void removeSubGroup(ContactGroupZeroconfImpl subgroup)
- {
- this.subGroups.remove(subgroup);
- subgroup.setParentGroup(null);
- }
-
- /**
- * Returns the group that is parent of the specified zeroconfGroup or null
- * if no parent was found.
- * @param zeroconfGroup the group whose parent we're looking for.
- * @return the ContactGroupZeroconfImpl instance that zeroconfGroup
- * belongs to or null if no parent was found.
- */
- public ContactGroupZeroconfImpl findGroupParent(
- ContactGroupZeroconfImpl zeroconfGroup)
- {
- if ( subGroups.contains(zeroconfGroup) )
- return this;
-
- Iterator<ContactGroup> subGroupsIter = subgroups();
- while (subGroupsIter.hasNext())
- {
- ContactGroupZeroconfImpl subgroup
- = (ContactGroupZeroconfImpl) subGroupsIter.next();
-
- ContactGroupZeroconfImpl parent
- = subgroup.findGroupParent(zeroconfGroup);
-
- if(parent != null)
- return parent;
- }
- return null;
- }
-
- /**
- * Returns the group that is parent of the specified zeroconfContact or
- * null if no parent was found.
- *
- * @param zeroconfContact the contact whose parent we're looking for.
- * @return the ContactGroupZeroconfImpl instance that zeroconfContact
- * belongs to or <tt>null</tt> if no parent was found.
- */
- public ContactGroupZeroconfImpl findContactParent(
- ContactZeroconfImpl zeroconfContact)
- {
- if ( contacts.contains(zeroconfContact) )
- return this;
-
- Iterator<ContactGroup> subGroupsIter = subgroups();
- while (subGroupsIter.hasNext())
- {
- ContactGroupZeroconfImpl subgroup
- = (ContactGroupZeroconfImpl) subGroupsIter.next();
-
- ContactGroupZeroconfImpl parent
- = subgroup.findContactParent(zeroconfContact);
-
- if(parent != null)
- return parent;
- }
- return null;
- }
-
-
-
- /**
- * Returns the <tt>Contact</tt> with the specified address or identifier.
- *
- * @param id the addres or identifier of the <tt>Contact</tt> we are
- * looking for.
- * @return the <tt>Contact</tt> with the specified id or address.
- */
- public Contact getContact(String id)
- {
- Iterator<Contact> contactsIter = contacts();
- while (contactsIter.hasNext())
- {
- ContactZeroconfImpl contact =
- (ContactZeroconfImpl)contactsIter.next();
-
- if (contact.getAddress().equals(id))
- return contact;
-
- }
- return null;
- }
-
- /**
- * Returns the subgroup with the specified index.
- *
- * @param index the index of the <tt>ContactGroup</tt> to retrieve.
- * @return the <tt>ContactGroup</tt> with the specified index.
- */
- public ContactGroup getGroup(int index)
- {
- return subGroups.get(index);
- }
-
- /**
- * Returns the subgroup with the specified name.
- *
- * @param groupName the name of the <tt>ContactGroup</tt> to retrieve.
- * @return the <tt>ContactGroup</tt> with the specified index.
- */
- public ContactGroup getGroup(String groupName)
- {
- Iterator<ContactGroup> groupsIter = subgroups();
- while (groupsIter.hasNext())
- {
- ContactGroupZeroconfImpl contactGroup
- = (ContactGroupZeroconfImpl) groupsIter.next();
- if (contactGroup.getGroupName().equals(groupName))
- return contactGroup;
-
- }
- return null;
-
- }
-
- /**
- * Returns the name of this group.
- *
- * @return a String containing the name of this group.
- */
- public String getGroupName()
- {
- return this.groupName;
- }
-
- /**
- * Sets this group a new name.
- * @param newGrpName a String containing the new name of this group.
- */
- public void setGroupName(String newGrpName)
- {
- this.groupName = newGrpName;
- }
-
- /**
- * Returns an iterator over the sub groups that this
- * <tt>ContactGroup</tt> contains.
- *
- * @return a java.util.Iterator over the <tt>ContactGroup</tt> children
- * of this group (i.e. subgroups).
- */
- public Iterator<ContactGroup> subgroups()
- {
- return subGroups.iterator();
- }
-
- /**
- * Removes the specified contact from this group.
- * @param contact the ContactZeroconfImpl to remove from this group
- */
- public void removeContact(ContactZeroconfImpl contact)
- {
- this.contacts.remove(contact);
- }
-
- /**
- * Returns the contact with the specified id or null if no such contact
- * exists.
- * @param id the id of the contact we're looking for.
- * @return ContactZeroconfImpl
- */
- public ContactZeroconfImpl findContactByID(String id)
- {
- //first go through the contacts that are direct children.
- Iterator<Contact> contactsIter = contacts();
-
- while(contactsIter.hasNext())
- {
- ContactZeroconfImpl mContact =
- (ContactZeroconfImpl)contactsIter.next();
-
- if( mContact.getAddress().equals(id) )
- return mContact;
- }
-
- //if we didn't find it here, let's try in the subougroups
- Iterator<ContactGroup> groupsIter = subgroups();
-
- while( groupsIter.hasNext() )
- {
- ContactGroupZeroconfImpl mGroup =
- (ContactGroupZeroconfImpl)groupsIter.next();
-
- ContactZeroconfImpl mContact = mGroup.findContactByID(id);
-
- if (mContact != null)
- return mContact;
- }
-
- return null;
- }
-
-
- /**
- * Returns a String representation of this group and the contacts it
- * contains (may turn out to be a relatively long string).
- * @return a String representing this group and its child contacts.
- */
- @Override
- public String toString()
- {
-
- StringBuffer buff = new StringBuffer(getGroupName());
- buff.append(".subGroups=" + countSubgroups() + ":\n");
-
- Iterator<ContactGroup> subGroups = subgroups();
- while (subGroups.hasNext())
- {
- ContactGroupZeroconfImpl group =
- (ContactGroupZeroconfImpl)subGroups.next();
- buff.append(group.toString());
- if (subGroups.hasNext())
- buff.append("\n");
- }
-
- buff.append("\nChildContacts="+countContacts()+":[");
-
- Iterator<Contact> contacts = contacts();
- while (contacts.hasNext())
- {
- ContactZeroconfImpl contact = (ContactZeroconfImpl) contacts.next();
- buff.append(contact.toString());
- if(contacts.hasNext())
- buff.append(", ");
- }
- return buff.append("]").toString();
- }
-
- /**
- * Specifies whether or not this contact group is being stored by the server.
- * Non persistent contact groups are common in the case of simple,
- * non-persistent presence operation sets. They could however also be seen
- * in persistent presence operation sets when for example we have received
- * an event from someone not on our contact list and the contact that we
- * associated with that user is placed in a non persistent group. Non
- * persistent contact groups are volatile even when coming from a persistent
- * presence op. set. They would only exist until the application is closed
- * and will not be there next time it is loaded.
- *
- * @param isPersistent true if the contact group is to be persistent and
- * false otherwise.
- */
- public void setPersistent(boolean isPersistent)
- {
- this.isPersistent = isPersistent;
- }
-
- /**
- * Determines whether or not this contact group is being stored by the
- * server. Non persistent contact groups exist for the sole purpose of
- * containing non persistent contacts.
- * @return true if the contact group is persistent and false otherwise.
- */
- public boolean isPersistent()
- {
- return isPersistent;
- }
-
- /**
- * Returns null as no persistent data is required and the contact address is
- * sufficient for restoring the contact.
- * <p>
- * @return null as no such data is needed.
- */
- public String getPersistentData()
- {
- return null;
- }
-
- /**
- * Determines whether or not this contact has been resolved against the
- * server. Unresolved contacts are used when initially loading a contact
- * list that has been stored in a local file until the presence operation
- * set has managed to retrieve all the contact list from the server and has
- * properly mapped contacts to their on-line buddies.
- * @return true if the contact has been resolved (mapped against a buddy)
- * and false otherwise.
- */
- public boolean isResolved()
- {
- return isResolved;
- }
-
- /**
- * Makes the group resolved or unresolved.
- *
- * @param resolved true to make the group resolved; false to
- * make it unresolved
- */
- public void setResolved(boolean resolved)
- {
- this.isResolved = resolved;
- }
-
- /**
- * Returns a <tt>String</tt> that uniquely represnets the group inside
- * the current protocol. The string MUST be persistent (it must not change
- * across connections or runs of the application). In many cases (Jabber,
- * ICQ) the string may match the name of the group as these protocols
- * only allow a single level of contact groups and there is no danger of
- * having the same name twice in the same contact list. Other protocols
- * (no examples come to mind but that doesn't bother me ;) ) may be
- * supporting mutilple levels of grooups so it might be possible for group
- * A and group B to both contain groups named C. In such cases the
- * implementation must find a way to return a unique identifier in this
- * method and this UID should never change for a given group.
- *
- * @return a String representing this group in a unique and persistent
- * way.
- */
- public String getUID()
- {
- return uid;
- }
-
- /**
- * Ugly but tricky conversion method.
- * @param uid the uid we'd like to get a name from
- * @return the name of the group with the specified <tt>uid</tt>.
- */
- static String createNameFromUID(String uid)
- {
- return uid.substring(0, uid.length() - (UID_SUFFIX.length()));
- }
-
- /**
- * Indicates whether some other object is "equal to" this one which in terms
- * of contact groups translates to having the equal names and matching
- * subgroups and child contacts. The resolved status of contactgroups and
- * contacts is deliberately ignored so that groups and/or contacts would
- * be assumed equal even if it differs.
- * <p>
- * @param obj the reference object with which to compare.
- * @return <code>true</code> if this contact group has the equal child
- * contacts and subgroups to those of the <code>obj</code> argument.
- */
- @Override
- public boolean equals(Object obj)
- {
- if(obj == null
- || !(obj instanceof ContactGroupZeroconfImpl))
- return false;
-
- ContactGroupZeroconfImpl zeroconfGroup
- = (ContactGroupZeroconfImpl)obj;
-
- if(!zeroconfGroup.getGroupName().equals(getGroupName()) ||
- !zeroconfGroup.getUID().equals(getUID()) ||
- zeroconfGroup.countContacts() != countContacts() ||
- zeroconfGroup.countSubgroups() != countSubgroups())
- return false;
-
- //traverse child contacts
- Iterator<Contact> theirContacts = zeroconfGroup.contacts();
-
- while(theirContacts.hasNext())
- {
- ContactZeroconfImpl theirContact
- = (ContactZeroconfImpl)theirContacts.next();
-
- ContactZeroconfImpl ourContact
- = (ContactZeroconfImpl)getContact(theirContact.getAddress());
-
- if(ourContact == null
- || !ourContact.equals(theirContact))
- return false;
- }
-
- //traverse subgroups
- Iterator<ContactGroup> theirSubgroups = zeroconfGroup.subgroups();
-
- while(theirSubgroups.hasNext())
- {
- ContactGroupZeroconfImpl theirSubgroup
- = (ContactGroupZeroconfImpl)theirSubgroups.next();
-
- ContactGroupZeroconfImpl ourSubgroup
- = (ContactGroupZeroconfImpl)getGroup(
- theirSubgroup.getGroupName());
-
- if(ourSubgroup == null
- || !ourSubgroup.equals(theirSubgroup))
- return false;
- }
-
- return true;
- }
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/zeroconf/ContactZeroconfImpl.java b/src/net/java/sip/communicator/impl/protocol/zeroconf/ContactZeroconfImpl.java
deleted file mode 100644
index c22cf29..0000000
--- a/src/net/java/sip/communicator/impl/protocol/zeroconf/ContactZeroconfImpl.java
+++ /dev/null
@@ -1,468 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright @ 2015 Atlassian Pty Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.zeroconf;
-
-import java.net.*;
-
-import net.java.sip.communicator.service.protocol.*;
-import net.java.sip.communicator.util.*;
-
-/**
- * A simple, straightforward implementation of a zeroconf Contact. Since
- * the Zeroconf protocol is not a real one, we simply store all contact details
- * in class fields. You should know that when implementing a real protocol,
- * the contact implementation would rather encapsulate contact objects from
- * the protocol stack and group property values should be returned after
- * consulting the encapsulated object.
- *
- * @author Christian Vincenot
- * @author Maxime Catelin
- * @author Jonathan Martin
- */
-public class ContactZeroconfImpl
- extends AbstractContact
-{
- private static final Logger logger
- = Logger.getLogger(ContactZeroconfImpl.class);
-
-
- /**
- * The id of the contact.
- */
- private String contactID = null;
-
- /**
- * The ClientThread attached to this contact if we're already chatting
- * with him.
- */
- private ClientThread thread = null;
-
- /*
- * Type of Client.
- */
- /**
- * Gaim/Pidgin client type
- */
- public static final int GAIM = 1;
- /**
- * iChat client type
- */
- public static final int ICHAT = 2;
- /**
- * XMPP - XEP-0174 client type
- */
- public static final int XMPP = 3;
- /**
- * Another SIP Communicator client
- */
- public static final int SIPCOM = 4;
- private int clientType = XMPP;
-
-
- /**
- * The provider that created us.
- */
- private ProtocolProviderServiceZeroconfImpl parentProvider = null;
-
-
- /*
- * The Bonjour Service who discovered this contact.
- * TODO: This could probably be avoided using only the
- * Protocol Provider.
- */
- private BonjourService bonjourService;
-
- /**
- * The group that belong to.
- */
- private ContactGroupZeroconfImpl parentGroup = null;
-
- /**
- * The presence status of the contact.
- */
- private PresenceStatus presenceStatus = ZeroconfStatusEnum.OFFLINE;
-
- /**
- * Determines whether this contact is persistent,
- * i.e. member of the contact list or whether it is here only temporarily.
- * Chris: should be set to false here
- */
- private boolean isPersistent = false;
-
- /**
- * Determines whether the contact has been resolved (i.e. we have a
- * confirmation that it is still on the server contact list).
- */
- private boolean isResolved = true;
-
- /**
- * IP Address
- */
- private InetAddress ipAddress;
-
- /**
- * Port on which Bonjour is listening.
- */
- private int port;
-
- /**
- * Name announced by Bonjour.
- */
- private String name;
-
- /**
- * Contact personal message
- */
- private String message;
-
-
- /**
- * Creates an instance of a meta contact with the specified string used
- * as a name and identifier.
- * @param bonjourId ID of the contact
- * @param bonjourService BonjourService responsible for handling chat with
- * this contact
- * @param name Display name of this contact
- * @param ipAddress IP address of this contact
- * @param port Port declared by this contact for direct point-to-point chat
- * @param parentProvider the provider that created us.
- */
- public ContactZeroconfImpl(
- String bonjourId,
- ProtocolProviderServiceZeroconfImpl parentProvider,
- BonjourService bonjourService,
- String name,
- InetAddress ipAddress,
- int port)
- {
- this.contactID = bonjourId;
- this.parentProvider = parentProvider;
- this.bonjourService = bonjourService;
- this.name = name;
- this.ipAddress = ipAddress;
- this.port = port;
- bonjourService.addContact(this);
- }
-
- /**
- * This method is only called when the contact is added to a new
- * <tt>ContactGroupZeroconfImpl</tt> by the
- * <tt>ContactGroupZeroconfImpl</tt> itself.
- *
- * @param newParentGroup the <tt>ContactGroupZeroconfImpl</tt> that is now
- * parent of this <tt>ContactZeroconfImpl</tt>
- */
- void setParentGroup(ContactGroupZeroconfImpl newParentGroup)
- {
- this.parentGroup = newParentGroup;
- }
-
- /**
- * Return the BonjourService
- * @return BonjourService
- */
- public BonjourService getBonjourService()
- {
- return bonjourService;
- }
-
- /**
- * Return the ClientThread responsible for handling with this contact
- * @return ClientThread corresponding to the chat with this contact or null
- * if no chat was started
- */
- protected ClientThread getClientThread()
- {
- return thread;
- }
-
- /**
- * Set the ClientThread responsible for handling with this contact
- * @param thread ClientThread corresponding to the chat with this contact
- * or null if the chat is over
- */
- protected void setClientThread(ClientThread thread)
- {
- this.thread = thread;
- }
-
- /**
- * Return the type of client
- * @return Type of client used by this contact
- */
- public int getClientType()
- {
- return clientType;
- }
-
- /**
- * Sets the type of client
- * @param clientType Type of client used by this contact
- */
- public void setClientType(int clientType)
- {
- this.clientType = clientType;
- }
-
- /**
- * Returns a String that can be used for identifying the contact.
- *
- * @return a String id representing and uniquely identifying the contact.
- */
- public String getAddress()
- {
- return contactID;
- }
-
- /**
- * Returns a String that could be used by any user interacting modules
- * for referring to this contact.
- *
- * @return a String that can be used for referring to this contact when
- * interacting with the user.
- */
- public String getDisplayName()
- {
- return name;
- }
-
- /**
- * Returns the IP address declared by this Contact
- * @return IP address declared by this Contact
- */
- public InetAddress getIpAddress()
- {
- return ipAddress;
- }
-
- /**
- * Returns the TCP port declared by this Contact for direct chat
- * @return the TCP port declared by this Contact for direct chat
- */
- public int getPort()
- {
- return port;
- }
-
-
- /**
- * Returns the status/private message displayed by this contact
- * @return the status/private message displayed by this contact
- */
- public String getMessage()
- {
- return message;
- }
-
- /**
- * Sets the status/private message displayed by this contact
- * @param message the status/private message displayed by this contact
- */
- public void setMessage(String message)
- {
- this.message = message;
- }
-
-
- /**
- * Returns a byte array containing an image (most often a photo or an
- * avatar) that the contact uses as a representation.
- *
- * @return byte[] an image representing the contact.
- */
- public byte[] getImage()
- {
- return null;
- }
-
- /**
- * Returns the status of the contact.
- *
- * @return always ZeroconfStatusEnum.
- */
- public PresenceStatus getPresenceStatus()
- {
- return this.presenceStatus;
- }
-
- /**
- * Sets <tt>zeroconfPresenceStatus</tt> as the PresenceStatus that this
- * contact is currently in.
- * @param zeroconfPresenceStatus the <tt>ZeroconfPresenceStatus</tt>
- * currently valid for this contact.
- */
- public void setPresenceStatus(PresenceStatus zeroconfPresenceStatus)
- {
- this.presenceStatus = zeroconfPresenceStatus;
-
- if (zeroconfPresenceStatus == ZeroconfStatusEnum.OFFLINE) {
- try
- {
- bonjourService.opSetPersPresence.unsubscribe(this);
- }
- catch (Exception ex)
- {
- logger.error(ex);
- }
- }
- }
-
- /**
- * Returns a reference to the protocol provider that created the contact.
- *
- * @return a refererence to an instance of the ProtocolProviderService
- */
- public ProtocolProviderService getProtocolProvider()
- {
- return parentProvider;
- }
-
- /**
- * Determines whether or not this contact represents our own identity.
- *
- * @return true in case this is a contact that represents ourselves and
- * false otherwise.
- */
- public boolean isLocal()
- {
- return false;
- }
-
- /**
- * Returns the group that contains this contact.
- * @return a reference to the <tt>ContactGroupZeroconfImpl</tt> that
- * contains this contact.
- */
- public ContactGroup getParentContactGroup()
- {
- return this.parentGroup;
- }
-
- /**
- * Returns a string representation of this contact, containing most of its
- * representative details.
- *
- * @return a string representation of this contact.
- */
- @Override
- public String toString()
- {
- StringBuffer buff
- = new StringBuffer("ContactZeroconfImpl[ DisplayName=")
- .append(getDisplayName()).append("]");
-
- return buff.toString();
- }
-
- /**
- * Determines whether or not this contact is being stored by the server.
- * Non persistent contacts are common in the case of simple, non-persistent
- * presence operation sets. They could however also be seen in persistent
- * presence operation sets when for example we have received an event
- * from someone not on our contact list. Non persistent contacts are
- * volatile even when coming from a persistent presence op. set. They would
- * only exist until the application is closed and will not be there next
- * time it is loaded.
- *
- * @return true if the contact is persistent and false otherwise.
- */
- public boolean isPersistent()
- {
- return isPersistent;
- }
-
- /**
- * Specifies whether or not this contact is being stored by the server.
- * Non persistent contacts are common in the case of simple, non-persistent
- * presence operation sets. They could however also be seen in persistent
- * presence operation sets when for example we have received an event
- * from someone not on our contact list. Non persistent contacts are
- * volatile even when coming from a persistent presence op. set. They would
- * only exist until the application is closed and will not be there next
- * time it is loaded.
- *
- * @param isPersistent true if the contact is persistent and false
- * otherwise.
- */
- public void setPersistent(boolean isPersistent)
- {
- this.isPersistent = isPersistent;
- }
-
-
- /**
- * Returns null as no persistent data is required and the contact address is
- * sufficient for restoring the contact.
- * <p>
- * @return null as no such data is needed.
- */
- public String getPersistentData()
- {
- return null;
- }
-
- /**
- * Determines whether or not this contact has been resolved against the
- * server. Unresolved contacts are used when initially loading a contact
- * list that has been stored in a local file until the presence operation
- * set has managed to retrieve all the contact list from the server and has
- * properly mapped contacts to their on-line buddies.
- *
- * @return true if the contact has been resolved (mapped against a buddy)
- * and false otherwise.
- */
- public boolean isResolved()
- {
- return isResolved;
- }
-
- /**
- * Makes the contact resolved or unresolved.
- *
- * @param resolved true to make the contact resolved; false to
- * make it unresolved
- */
- public void setResolved(boolean resolved)
- {
- this.isResolved = resolved;
- }
-
- /**
- * Returns the persistent presence operation set that this contact belongs
- * to.
- *
- * @return the <tt>OperationSetPersistentPresenceZeroconfImpl</tt> that
- * this contact belongs to.
- */
- public OperationSetPersistentPresenceZeroconfImpl
- getParentPresenceOperationSet()
- {
- return (OperationSetPersistentPresenceZeroconfImpl)parentProvider
- .getOperationSet(OperationSetPersistentPresence.class);
- }
-
- /**
- * Return the current status message of this contact.
- *
- * @return null as the protocol has currently no support of status messages
- */
- public String getStatusMessage()
- {
- return null;
- }
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/zeroconf/MessageZeroconfImpl.java b/src/net/java/sip/communicator/impl/protocol/zeroconf/MessageZeroconfImpl.java
deleted file mode 100644
index 3621edc..0000000
--- a/src/net/java/sip/communicator/impl/protocol/zeroconf/MessageZeroconfImpl.java
+++ /dev/null
@@ -1,234 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright @ 2015 Atlassian Pty Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.zeroconf;
-
-import net.java.sip.communicator.service.protocol.*;
-
-/**
- * Very simple message implementation for the Zeroconf protocol.
- *
- * @author Christian Vincenot
- * @author Maxime Catelin
- * @author Jonathan Martin
- * @author Lubomir Marinov
- */
-public class MessageZeroconfImpl
- extends AbstractMessage
-{
-
- /**
- * Message Type.
- */
- private int type;
-
- /**
- * Message type indicating that a stream is being created
- */
- public static final int STREAM_OPEN = 0x1;
-
- /**
- * Normal chat message
- */
- public static final int MESSAGE = 0x2;
-
- /**
- * Typing notification
- */
- public static final int TYPING = 0x3;
-
- /**
- * Message indicating that the stream is being closed
- */
- public static final int STREAM_CLOSE = 0x4;
-
- /**
- * Message indicating that the previsous message was delivered successfully
- */
- public static final int DELIVERED = 0x5;
-
- /**
- * Undefined message
- */
- public static final int UNDEF = 0x6;
-
- /*
- * The Baloon Icon color. (we probably won't ever use it)
- */
- private int baloonColor = 0x7BB5EE;
-
- /*
- * The Text Color.
- */
- private int textColor = 0x000000;
-
- /*
- * The font of the message.
- */
- private String textFont = "Helvetica";
-
- /*
- * The size of the caracters composing the message.
- */
- private int textSize = 12;
-
- /*
- * The source contact id announced in the message. TODO: Could be set &
- * checked to identify more precisely the contact in case several users
- * would be sharing the same IP.
- */
- private String contactID;
-
- /**
- * Creates a message instance according to the specified parameters.
- *
- * @param content the message body
- * @param contentEncoding message encoding or null for UTF8
- * @param contentType of the message
- * @param type Type of message
- */
- public MessageZeroconfImpl(String content, String contentEncoding,
- String contentType, int type)
- {
- super(content, contentType, contentEncoding, null);
-
- this.type = type;
- }
-
- /**
- * Creates a message instance according to the specified parameters.
- *
- * @param type Type of message
- * @param content the message body
- * @param contentEncoding message encoding or null for UTF8
- */
- public MessageZeroconfImpl(String content, String contentEncoding, int type)
- {
- this(content, contentEncoding,
- OperationSetBasicInstantMessaging.DEFAULT_MIME_TYPE, type);
- }
-
- /**
- * Returns the type of message. Always text/plain for Zeroconf, so null.
- *
- * @return null
- */
- public int getType()
- {
- return type;
- }
-
- /**
- * Gets the baloon color declared in messages sent by iChat-like clients
- *
- * @return baloon color
- */
- public int getBaloonColor()
- {
- return baloonColor;
- }
-
- /**
- * Sets the baloon color declared in messages sent by iChat-like clients
- *
- * @param baloonColor baloon color
- */
- public void setBaloonColor(int baloonColor)
- {
- this.baloonColor = baloonColor;
- }
-
- /**
- * Returns the text color
- *
- * @return Text color
- */
- public int getTextColor()
- {
- return textColor;
- }
-
- /**
- * Sets the text color
- *
- * @param textColor Text color
- */
- public void setTextColor(int textColor)
- {
- this.textColor = textColor;
- }
-
- /**
- * Returns the text font
- *
- * @return Text font
- */
- public String getTextFont()
- {
- return textFont;
- }
-
- /**
- * Sets the text color
- *
- * @param textFont Text font
- */
- public void setTextFont(String textFont)
- {
- this.textFont = textFont;
- }
-
- /**
- * Returns the text size
- *
- * @return Text size
- */
- public int getTextSize()
- {
- return textSize;
- }
-
- /**
- * Sets the text size
- *
- * @param textSize Text size
- */
- public void setTextSize(int textSize)
- {
- this.textSize = textSize;
- }
-
- /**
- * Returns the contact's ID
- *
- * @return String representing the contact's ID
- */
- public String getContactID()
- {
- return contactID;
- }
-
- /**
- * Sets the contact's ID
- *
- * @param contactID String representing the contact's ID
- */
- public void setContactID(String contactID)
- {
- this.contactID = contactID;
- }
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/zeroconf/OperationSetBasicInstantMessagingZeroconfImpl.java b/src/net/java/sip/communicator/impl/protocol/zeroconf/OperationSetBasicInstantMessagingZeroconfImpl.java
deleted file mode 100644
index d49118b..0000000
--- a/src/net/java/sip/communicator/impl/protocol/zeroconf/OperationSetBasicInstantMessagingZeroconfImpl.java
+++ /dev/null
@@ -1,192 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright @ 2015 Atlassian Pty Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.zeroconf;
-
-import java.io.*;
-import java.net.*;
-
-import net.java.sip.communicator.service.protocol.*;
-import net.java.sip.communicator.util.*;
-
-/**
- * Instant messaging functionalities for the Zeroconf protocol.
- *
- * @author Christian Vincenot
- *
- */
-public class OperationSetBasicInstantMessagingZeroconfImpl
- extends AbstractOperationSetBasicInstantMessaging
-{
- private static final Logger logger
- = Logger.getLogger(OperationSetBasicInstantMessagingZeroconfImpl.class);
-
- /**
- * The currently valid persistent presence operation set..
- */
- private final OperationSetPersistentPresenceZeroconfImpl opSetPersPresence;
-
- /**
- * The protocol provider that created us.
- */
- private final ProtocolProviderServiceZeroconfImpl parentProvider;
-
- /**
- * Creates an instance of this operation set keeping a reference to the
- * parent protocol provider and presence operation set.
- *
- * @param provider The provider instance that creates us.
- * @param opSetPersPresence the currently valid
- * <tt>OperationSetPersistentPresenceZeroconfImpl</tt> instance.
- */
- public OperationSetBasicInstantMessagingZeroconfImpl(
- ProtocolProviderServiceZeroconfImpl provider,
- OperationSetPersistentPresenceZeroconfImpl opSetPersPresence)
- {
- this.opSetPersPresence = opSetPersPresence;
- this.parentProvider = provider;
- }
-
- @Override
- public Message createMessage(String content, String contentType,
- String encoding, String subject)
- {
- return new MessageZeroconfImpl(content, encoding, contentType,
- MessageZeroconfImpl.MESSAGE);
- }
-
- /**
- * Sends the <tt>message</tt> to the destination indicated by the
- * <tt>to</tt> contact.
- *
- * @param to the <tt>Contact</tt> to send <tt>message</tt> to
- * @param message the <tt>Message</tt> to send.
- * @throws IllegalStateException if the underlying Zeroconf stack is not
- * registered and initialized.
- * @throws IllegalArgumentException if <tt>to</tt> is not an instance
- * belonging to the underlying implementation.
- */
- public void sendInstantMessage(Contact to, Message message) throws
- IllegalStateException, IllegalArgumentException
- {
- if( !(to instanceof ContactZeroconfImpl) )
- throw new IllegalArgumentException(
- "The specified contact is not a Zeroconf contact."
- + to);
-
- MessageZeroconfImpl msg =
- (MessageZeroconfImpl)createMessage(message.getContent());
-
- deliverMessage(msg, (ContactZeroconfImpl)to);
- }
-
- /**
- * In case the to the <tt>to</tt> Contact corresponds to another zeroconf
- * protocol provider registered with SIP Communicator, we deliver
- * the message to them, in case the <tt>to</tt> Contact represents us, we
- * fire a <tt>MessageReceivedEvent</tt>, and if <tt>to</tt> is simply
- * a contact in our contact list, then we simply echo the message.
- *
- * @param message the <tt>Message</tt> the message to deliver.
- * @param to the <tt>Contact</tt> that we should deliver the message to.
- */
- private void deliverMessage(Message message, ContactZeroconfImpl to)
- {
- ClientThread thread = to.getClientThread();
- try
- {
- if (thread == null)
- {
- Socket sock;
- if (logger.isDebugEnabled())
- logger.debug("ZEROCONF: Creating a chat connexion to "
- +to.getIpAddress()+":"+to.getPort());
- sock = new Socket(to.getIpAddress(), to.getPort());
- thread = new ClientThread(sock, to.getBonjourService());
- thread.setStreamOpen();
- thread.setContact(to);
- to.setClientThread(thread);
- thread.sendHello();
- if (to.getClientType() == ContactZeroconfImpl.GAIM)
- {
- try
- {
- Thread.sleep(300);
- }
- catch (InterruptedException ex)
- {
- logger.error(ex);
- }
- }
- }
-
- //System.out.println("ZEROCONF: Message content => "+
- //message.getContent());
- thread.sendMessage((MessageZeroconfImpl) message);
-
- fireMessageDelivered(message, to);
- }
- catch (IOException ex)
- {
- logger.error(ex);
- }
- }
-
- /**
- * Notifies all registered message listeners that a message has been
- * received.
- *
- * @param message the <tt>Message</tt> that has been received.
- * @param from the <tt>Contact</tt> that <tt>message</tt> was received from.
- */
- @Override
- public void fireMessageReceived(Message message, Contact from)
- {
- super.fireMessageReceived(message, from);
- }
-
- /**
- * Determines whether the protocol provider (or the protocol itself) support
- * sending and receiving offline messages. Most often this method would
- * return true for protocols that support offline messages and false for
- * those that don't. It is however possible for a protocol to support these
- * messages and yet have a particular account that does not (i.e. feature
- * not enabled on the protocol server). In cases like this it is possible
- * for this method to return true even when offline messaging is not
- * supported, and then have the sendMessage method throw an
- * OperationFailedException with code - OFFLINE_MESSAGES_NOT_SUPPORTED.
- *
- * @return <tt>true</tt> if the protocol supports offline messages and
- * <tt>false</tt> otherwise.
- */
- public boolean isOfflineMessagingSupported()
- {
- return true;
- }
-
- /**
- * Determines whether the protocol supports the supplied content type
- *
- * @param contentType the type we want to check
- * @return <tt>true</tt> if the protocol supports it and
- * <tt>false</tt> otherwise.
- */
- public boolean isContentTypeSupported(String contentType)
- {
- return contentType.equals(DEFAULT_MIME_TYPE);
- }
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/zeroconf/OperationSetPersistentPresenceZeroconfImpl.java b/src/net/java/sip/communicator/impl/protocol/zeroconf/OperationSetPersistentPresenceZeroconfImpl.java
deleted file mode 100644
index 412512e..0000000
--- a/src/net/java/sip/communicator/impl/protocol/zeroconf/OperationSetPersistentPresenceZeroconfImpl.java
+++ /dev/null
@@ -1,852 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright @ 2015 Atlassian Pty Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.zeroconf;
-
-import java.net.*;
-import java.util.*;
-
-import net.java.sip.communicator.service.protocol.*;
-import net.java.sip.communicator.service.protocol.event.*;
-import net.java.sip.communicator.util.*;
-
-import org.osgi.framework.*;
-
-/**
- * A Zeroconf implementation of a persistent presence operation set. In order
- * to simulate server persistence, this operation set would simply accept all
- * unresolved contacts and resolve them immediately. A real world protocol
- * implementation would save it on a server using methods provided by the
- * protocol stack.
- *
- * @author Christian Vincenot
- * @author Maxime Catelin
- * @author Jonathan Martin
- */
-public class OperationSetPersistentPresenceZeroconfImpl
- extends AbstractOperationSetPersistentPresence<ProtocolProviderServiceZeroconfImpl>
-{
- private static final Logger logger =
- Logger.getLogger(OperationSetPersistentPresenceZeroconfImpl.class);
-
- /**
- * The root of the zeroconf contact list.
- */
- private ContactGroupZeroconfImpl contactListRoot = null;
-
- /**
- * The currently active status message.
- */
- private String statusMessage = "The truth is out there...";
-
- /**
- * Our default presence status.
- */
- private PresenceStatus presenceStatus = ZeroconfStatusEnum.OFFLINE;
-
- /**
- * The <tt>AuthorizationHandler</tt> instance that we'd have to transmit
- * authorization requests to for approval.
- */
- private AuthorizationHandler authorizationHandler = null;
-
- /**
- * Creates an instance of this operation set keeping a reference to the
- * specified parent <tt>provider</tt>.
- * @param provider the ProtocolProviderServiceZeroconfImpl instance that
- * created us.
- */
- public OperationSetPersistentPresenceZeroconfImpl(
- ProtocolProviderServiceZeroconfImpl provider)
- {
- super(provider);
-
- contactListRoot = new ContactGroupZeroconfImpl("RootGroup", provider);
-
- //add our unregistration listener
- parentProvider.addRegistrationStateChangeListener(
- new UnregistrationListener());
- }
-
- /**
- * Creates a group with the specified name and parent in the server
- * stored contact list.
- *
- * @param parent the group where the new group should be created
- * @param groupName the name of the new group to create.
- */
- public void createServerStoredContactGroup(ContactGroup parent,
- String groupName)
- {
- ContactGroupZeroconfImpl newGroup
- = new ContactGroupZeroconfImpl(groupName, parentProvider);
-
- ((ContactGroupZeroconfImpl)parent).addSubgroup(newGroup);
-
- this.fireServerStoredGroupEvent(
- newGroup, ServerStoredGroupEvent.GROUP_CREATED_EVENT);
- }
-
- /**
- * A Zeroconf Provider method to use for fast filling of a contact list.
- *
- * @param contactGroup the group to add
- */
- public void addZeroconfGroup(ContactGroupZeroconfImpl contactGroup)
- {
- contactListRoot.addSubgroup(contactGroup);
- }
-
- /**
- * A Zeroconf Provider method to use for fast filling of a contact list.
- * This method would add both the group and fire an event.
- *
- * @param parent the group where <tt>contactGroup</tt> should be added.
- * @param contactGroup the group to add
- */
- public void addZeroconfGroupAndFireEvent(
- ContactGroupZeroconfImpl parent
- , ContactGroupZeroconfImpl contactGroup)
- {
- parent.addSubgroup(contactGroup);
-
- this.fireServerStoredGroupEvent(
- contactGroup, ServerStoredGroupEvent.GROUP_CREATED_EVENT);
- }
-
-
- /**
- * Returns a reference to the contact with the specified ID in case we
- * have a subscription for it and null otherwise/
- *
- * @param contactID a String identifier of the contact which we're
- * seeking a reference of.
- * @return a reference to the Contact with the specified
- * <tt>contactID</tt> or null if we don't have a subscription for the
- * that identifier.
- */
- public Contact findContactByID(String contactID)
- {
- return contactListRoot.findContactByID(contactID);
- }
-
- /**
- * Sets the specified status message.
- * @param statusMessage a String containing the new status message.
- */
- public void setStatusMessage(String statusMessage)
- {
- this.statusMessage = statusMessage;
- }
-
- /**
- * Returns the status message that was last set through
- * setCurrentStatusMessage.
- *
- * @return the last status message that we have requested and the aim
- * server has confirmed.
- */
- public String getCurrentStatusMessage()
- {
- return statusMessage;
- }
-
- /**
- * Returns a PresenceStatus instance representing the state this provider
- * is currently in.
- *
- * @return the PresenceStatus last published by this provider.
- */
- public PresenceStatus getPresenceStatus()
- {
- return presenceStatus;
- }
-
- /**
- * Returns the root group of the server stored contact list.
- *
- * @return the root ContactGroup for the ContactList stored by this
- * service.
- */
- public ContactGroup getServerStoredContactListRoot()
- {
- return contactListRoot;
- }
-
- /**
- * Returns the set of PresenceStatus objects that a user of this service
- * may request the provider to enter.
- *
- * @return Iterator a PresenceStatus array containing "enterable" status
- * instances.
- */
- public Iterator<PresenceStatus> getSupportedStatusSet()
- {
- return ZeroconfStatusEnum.supportedStatusSet();
- }
-
- /**
- * Removes the specified contact from its current parent and places it
- * under <tt>newParent</tt>.
- *
- * @param contactToMove the <tt>Contact</tt> to move
- * @param newParent the <tt>ContactGroup</tt> where <tt>Contact</tt>
- * would be placed.
- */
- public void moveContactToGroup(Contact contactToMove,
- ContactGroup newParent)
- {
- ContactZeroconfImpl zeroconfContact
- = (ContactZeroconfImpl)contactToMove;
-
- ContactGroupZeroconfImpl parentZeroconfGroup
- = findContactParent(zeroconfContact);
-
- parentZeroconfGroup.removeContact(zeroconfContact);
-
- //if this is a volatile contact then we haven't really subscribed to
- //them so we'd need to do so here
- if(!zeroconfContact.isPersistent())
- {
- //first tell everyone that the volatile contact was removed
- fireSubscriptionEvent(zeroconfContact
- , parentZeroconfGroup
- , SubscriptionEvent.SUBSCRIPTION_REMOVED);
-
- try
- {
- //now subscribe
- this.subscribe(newParent, contactToMove.getAddress());
-
- //now tell everyone that we've added the contact
- fireSubscriptionEvent(zeroconfContact
- , newParent
- , SubscriptionEvent.SUBSCRIPTION_CREATED);
- }
- catch (Exception ex)
- {
- logger.error("Failed to move contact "
- + zeroconfContact.getAddress()
- , ex);
- }
- }
- else
- {
- ( (ContactGroupZeroconfImpl) newParent)
- .addContact(zeroconfContact);
-
- fireSubscriptionMovedEvent(contactToMove
- , parentZeroconfGroup
- , newParent);
- }
- }
-
- /**
- * Requests the provider to enter into a status corresponding to the
- * specified paramters.
- *
- * @param status the PresenceStatus as returned by
- * getRequestableStatusSet
- * @param statusMessage the message that should be set as the reason to
- * enter that status
- * @throws IllegalArgumentException if the status requested is not a
- * valid PresenceStatus supported by this provider.
- * @throws IllegalStateException if the provider is not currently
- * registered.
- * @throws OperationFailedException with code NETWORK_FAILURE if
- * publishing the status fails due to a network error.
- */
- public void publishPresenceStatus(PresenceStatus status,
- String statusMessage)
- throws IllegalArgumentException,
- IllegalStateException,
- OperationFailedException
- {
- PresenceStatus oldPresenceStatus = this.presenceStatus;
- this.presenceStatus = status;
- this.statusMessage = statusMessage;
-
- //ICI: changer le statut du plugin Zeroconf!!
- parentProvider.getBonjourService().changeStatus(status);
-
- this.fireProviderStatusChangeEvent(oldPresenceStatus);
-
- }
-
- /**
- * Get the PresenceStatus for a particular contact.
- *
- * @param contactIdentifier the identifier of the contact whose status
- * we're interested in.
- * @return PresenceStatus the <tt>PresenceStatus</tt> of the specified
- * <tt>contact</tt>
- * @throws IllegalArgumentException if <tt>contact</tt> is not a contact
- * known to the underlying protocol provider
- * @throws IllegalStateException if the underlying protocol provider is
- * not registered/signed on a public service.
- * @throws OperationFailedException with code NETWORK_FAILURE if
- * retrieving the status fails due to errors experienced during
- * network communication
- */
- public PresenceStatus queryContactStatus(String contactIdentifier)
- throws IllegalArgumentException,
- IllegalStateException,
- OperationFailedException
- {
- return findContactByID(contactIdentifier).getPresenceStatus();
- }
-
- /**
- * Sets the presence status of <tt>contact</tt> to <tt>newStatus</tt>.
- *
- * @param contact the <tt>ContactZeroconfImpl</tt> whose status we'd like
- * to set.
- * @param newStatus the new status we'd like to set to <tt>contact</tt>.
- */
- public void changePresenceStatusForContact(ContactZeroconfImpl contact,
- PresenceStatus newStatus)
- {
- PresenceStatus oldStatus = contact.getPresenceStatus();
- contact.setPresenceStatus(newStatus);
-
- fireContactPresenceStatusChangeEvent(
- contact, findContactParent(contact), oldStatus);
- }
-
- /**
- * Sets the presence status of all <tt>contact</tt>s in our contact list
- * (except those that correspond to another provider registered with SC)
- * to <tt>newStatus</tt>.
- *
- * @param newStatus the new status we'd like to set to <tt>contact</tt>.
- * @param parent the group in which we'd have to update the status of all
- * direct and indirect child contacts.
- */
- protected void changePresenceStatusForAllContacts(ContactGroup parent,
- PresenceStatus newStatus)
- {
- //first set the status for contacts in this group
- Iterator<Contact> childContacts = parent.contacts();
-
- while(childContacts.hasNext())
- {
- ContactZeroconfImpl contact
- = (ContactZeroconfImpl)childContacts.next();
-
- if(findProviderForZeroconfUserID(contact.getAddress()) != null)
- {
- //this is a contact corresponding to another SIP Communicator
- //provider so we won't change it's status here.
- continue;
- }
- PresenceStatus oldStatus = contact.getPresenceStatus();
- contact.setPresenceStatus(newStatus);
-
- fireContactPresenceStatusChangeEvent(
- contact, parent, oldStatus);
- }
-
- //now call this method recursively for all subgroups
- Iterator<ContactGroup> subgroups = parent.subgroups();
-
- while(subgroups.hasNext())
- {
- ContactGroup subgroup = subgroups.next();
- changePresenceStatusForAllContacts(subgroup, newStatus);
- }
- }
-
- /**
- * Returns the group that is parent of the specified zeroconfGroup or null
- * if no parent was found.
- * @param zeroconfGroup the group whose parent we're looking for.
- * @return the ContactGroupZeroconfImpl instance that zeroconfGroup
- * belongs to or null if no parent was found.
- */
- public ContactGroupZeroconfImpl findGroupParent(
- ContactGroupZeroconfImpl zeroconfGroup)
- {
- return contactListRoot.findGroupParent(zeroconfGroup);
- }
-
- /**
- * Returns the group that is parent of the specified zeroconfContact or
- * null if no parent was found.
- * @param zeroconfContact the contact whose parent we're looking for.
- * @return the ContactGroupZeroconfImpl instance that zeroconfContact
- * belongs to or null if no parent was found.
- */
- public ContactGroupZeroconfImpl findContactParent(
- ContactZeroconfImpl zeroconfContact)
- {
- return (ContactGroupZeroconfImpl)zeroconfContact
- .getParentContactGroup();
- }
-
-
- /**
- * Removes the specified group from the server stored contact list.
- *
- * @param group the group to remove.
- *
- * @throws IllegalArgumentException if <tt>group</tt> was not found in this
- * protocol's contact list.
- */
- public void removeServerStoredContactGroup(ContactGroup group)
- throws IllegalArgumentException
- {
- ContactGroupZeroconfImpl zeroconfGroup
- = (ContactGroupZeroconfImpl)group;
-
- ContactGroupZeroconfImpl parent = findGroupParent(zeroconfGroup);
-
- if(parent == null){
- throw new IllegalArgumentException(
- "group " + group
- + " does not seem to belong to this protocol's contact list.");
- }
-
- parent.removeSubGroup(zeroconfGroup);
-
- this.fireServerStoredGroupEvent(
- zeroconfGroup, ServerStoredGroupEvent.GROUP_REMOVED_EVENT);
- }
-
- /**
- * Renames the specified group from the server stored contact list.
- *
- * @param group the group to rename.
- * @param newName the new name of the group.
- */
- public void renameServerStoredContactGroup(ContactGroup group,
- String newName)
- {
- ((ContactGroupZeroconfImpl)group).setGroupName(newName);
-
- this.fireServerStoredGroupEvent(
- group,
- ServerStoredGroupEvent.GROUP_RENAMED_EVENT);
- }
-
- /**
- * Handler for incoming authorization requests.
- *
- * @param handler an instance of an AuthorizationHandler for
- * authorization requests coming from other users requesting
- * permission add us to their contact list.
- */
- public void setAuthorizationHandler(AuthorizationHandler handler)
- {
- this.authorizationHandler = handler;
- }
-
- /**
- * Persistently adds a subscription for the presence status of the
- * contact corresponding to the specified contactIdentifier and indicates
- * that it should be added to the specified group of the server stored
- * contact list.
- *
- * @param parent the parent group of the server stored contact list
- * where the contact should be added. <p>
- * @param contactIdentifier the contact whose status updates we are
- * subscribing for.
- * @throws IllegalArgumentException if <tt>contact</tt> or
- * <tt>parent</tt> are not a contact known to the underlying protocol
- * provider.
- * @throws IllegalStateException if the underlying protocol provider is
- * not registered/signed on a public service.
- * @throws OperationFailedException with code NETWORK_FAILURE if
- * subscribing fails due to errors experienced during network
- * communication
- */
- public void subscribe(ContactGroup parent, String contactIdentifier)
- throws IllegalArgumentException,
- IllegalStateException,
- OperationFailedException
- {
- /* ContactZeroconfImpl contact = new ContactZeroconfImpl(
- contactIdentifier,
- parentProvider,
- null, null, null, 0);
-
- ((ContactGroupZeroconfImpl)parent).addContact(contact);
-
- fireSubscriptionEvent(contact,
- parent,
- SubscriptionEvent.SUBSCRIPTION_CREATED);
- //if the newly added contact corresponds to another provider - set their
- //status accordingly
- ProtocolProviderServiceZeroconfImpl gibProvider
- = findProviderForZeroconfUserID(contactIdentifier);
- if(gibProvider != null)
- {
- OperationSetPersistentPresence opSetPresence
- = (OperationSetPersistentPresence)gibProvider.getOperationSet(
- OperationSetPersistentPresence.class);
-
- changePresenceStatusForContact(
- contact
- , (ZeroconfStatusEnum)opSetPresence.getPresenceStatus());
- }
- else
- {
- //otherwise - since we are not a real protocol, we set the contact
- //presence status ourselves
- changePresenceStatusForContact(contact, getPresenceStatus());
- }
-
- //notify presence listeners for the status change.
- fireContactPresenceStatusChangeEvent(contact
- , parent
- , ZeroconfStatusEnum.OFFLINE);
- */}
-
-
-
- /**
- * Adds a subscription for the presence status of the contact
- * corresponding to the specified contactIdentifier.
- *
- * @param contactIdentifier the identifier of the contact whose status
- * updates we are subscribing for. <p>
- * @throws IllegalArgumentException if <tt>contact</tt> is not a contact
- * known to the underlying protocol provider
- * @throws IllegalStateException if the underlying protocol provider is
- * not registered/signed on a public service.
- * @throws OperationFailedException with code NETWORK_FAILURE if
- * subscribing fails due to errors experienced during network
- * communication
- */
- public void subscribe(String contactIdentifier)
- throws IllegalArgumentException,
- IllegalStateException,
- OperationFailedException
- {
- subscribe(contactListRoot, contactIdentifier);
- }
-
- /**
- * Removes a subscription for the presence status of the specified
- * contact.
- *
- * @param contact the contact whose status updates we are unsubscribing
- * from.
- * @throws IllegalArgumentException if <tt>contact</tt> is not a contact
- * known to the underlying protocol provider
- * @throws IllegalStateException if the underlying protocol provider is
- * not registered/signed on a public service.
- * @throws OperationFailedException with code NETWORK_FAILURE if
- * unsubscribing fails due to errors experienced during network
- * communication
- */
- public void unsubscribe(Contact contact)
- throws IllegalArgumentException,
- IllegalStateException,
- OperationFailedException
- {
- String name = contact.getAddress();
-
- ContactGroupZeroconfImpl parentGroup
- = (ContactGroupZeroconfImpl)((ContactZeroconfImpl)contact)
- .getParentContactGroup();
-
- //parentGroup.removeContact((ContactZeroconfImpl)contact);
-
- BonjourService service =
- ((ProtocolProviderServiceZeroconfImpl)contact.getProtocolProvider())
- .getBonjourService();
- //TODO: better check with IP
- service.removeContact(name,null);
-
- fireSubscriptionEvent(contact,
- ((ContactZeroconfImpl)contact).getParentContactGroup()
- , SubscriptionEvent.SUBSCRIPTION_REMOVED);
- }
-
- /**
- * Creates and returns a unresolved contact from the specified
- * <tt>address</tt> and <tt>persistentData</tt>. The method will not try
- * to establish a network connection and resolve the newly created Contact
- * against the server. The protocol provider may will later try and resolve
- * the contact. When this happens the corresponding event would notify
- * interested subscription listeners.
- *
- * @param address an identifier of the contact that we'll be creating.
- * @param persistentData a String returned Contact's getPersistentData()
- * method during a previous run and that has been persistently stored
- * locally.
- * @return the unresolved <tt>Contact</tt> created from the specified
- * <tt>address</tt> and <tt>persistentData</tt>
- */
- public Contact createUnresolvedContact(String address,
- String persistentData)
- {
- return createUnresolvedContact(address
- , persistentData
- , getServerStoredContactListRoot());
- }
-
- /**
- * Creates and returns a unresolved contact from the specified
- * <tt>address</tt> and <tt>persistentData</tt>. The method will not try
- * to establish a network connection and resolve the newly created Contact
- * against the server. The protocol provider may will later try and resolve
- * the contact. When this happens the corresponding event would notify
- * interested subscription listeners.
- *
- * @param address an identifier of the contact that we'll be creating.
- * @param persistentData a String returned Contact's getPersistentData()
- * method during a previous run and that has been persistently stored
- * locally.
- * @param parent the group where the unresolved contact is
- * supposed to belong to.
- *
- * @return the unresolved <tt>Contact</tt> created from the specified
- * <tt>address</tt> and <tt>persistentData</tt>
- */
- public Contact createUnresolvedContact(String address,
- String persistentData,
- ContactGroup parent)
- {
- return null;
- }
-
- /**
- * Looks for a zeroconf protocol provider registered for a user id matching
- * <tt>zeroconfUserID</tt>.
- *
- * @param zeroconfUserID the ID of the Zeroconf user whose corresponding
- * protocol provider we'd like to find.
- * @return ProtocolProviderServiceZeroconfImpl a zeroconf protocol
- * provider registered for a user with id <tt>zeroconfUserID</tt> or null
- * if there is no such protocol provider.
- */
- public ProtocolProviderServiceZeroconfImpl
- findProviderForZeroconfUserID(String zeroconfUserID)
- {
- BundleContext bc = ZeroconfActivator.getBundleContext();
-
- String osgiQuery = "(&" +
- "(" + ProtocolProviderFactory.PROTOCOL +
- "=" + ProtocolNames.ZEROCONF + ")" +
- "(" + ProtocolProviderFactory.USER_ID +
- "=" + zeroconfUserID + "))";
-
- ServiceReference[] refs = null;
- try
- {
- refs = bc.getServiceReferences(
- ProtocolProviderService.class.getName(),
- osgiQuery);
- }
- catch (InvalidSyntaxException ex)
- {
- logger.error("Failed to execute the following osgi query: "
- + osgiQuery
- , ex);
- }
-
- if(refs != null && refs.length > 0)
- {
- return (ProtocolProviderServiceZeroconfImpl)bc.getService(refs[0]);
- }
-
- return null;
- }
-
- /**
- * Creates and returns a unresolved contact group from the specified
- * <tt>address</tt> and <tt>persistentData</tt>. The method will not try
- * to establish a network connection and resolve the newly created
- * <tt>ContactGroup</tt> against the server or the contact itself. The
- * protocol provider will later resolve the contact group. When this happens
- * the corresponding event would notify interested subscription listeners.
- *
- * @param groupUID an identifier, returned by ContactGroup's getGroupUID,
- * that the protocol provider may use in order to create the group.
- * @param persistentData a String returned ContactGroups's
- * getPersistentData() method during a previous run and that has been
- * persistently stored locally.
- * @param parentGroup the group under which the new group is to be created
- * or null if this is group directly underneath the root.
- * @return the unresolved <tt>ContactGroup</tt> created from the specified
- * <tt>uid</tt> and <tt>persistentData</tt>
- */
- public ContactGroup createUnresolvedContactGroup(String groupUID,
- String persistentData, ContactGroup parentGroup)
- {
- ContactGroupZeroconfImpl newGroup
- = new ContactGroupZeroconfImpl(
- ContactGroupZeroconfImpl.createNameFromUID(groupUID)
- , parentProvider);
- newGroup.setResolved(false);
-
- //if parent is null then we're adding under root.
- if(parentGroup == null)
- parentGroup = getServerStoredContactListRoot();
-
- ((ContactGroupZeroconfImpl)parentGroup).addSubgroup(newGroup);
-
- this.fireServerStoredGroupEvent(
- newGroup, ServerStoredGroupEvent.GROUP_CREATED_EVENT);
-
- return newGroup;
- }
-
- private class UnregistrationListener
- implements RegistrationStateChangeListener
- {
- /**
- * The method is called by a ProtocolProvider implementation whenver
- * a change in the registration state of the corresponding provider had
- * occurred. The method is particularly interested in events stating
- * that the zeroconf provider has unregistered so that it would fire
- * status change events for all contacts in our buddy list.
- *
- * @param evt ProviderStatusChangeEvent the event describing the status
- * change.
- */
- public void registrationStateChanged(RegistrationStateChangeEvent evt)
- {
-
- if (logger.isDebugEnabled())
- logger.debug("ZEROCONF : The Zeroconf provider changed state from: "
- + evt.getOldState()
- + " to: " + evt.getNewState());
-
- //send event notifications saying that all our buddies are
- //offline. The Zeroconf protocol does not implement top level buddies
- //nor subgroups for top level groups so a simple nested loop
- //would be enough.
- Iterator<ContactGroup> groupsIter
- = getServerStoredContactListRoot().subgroups();
- while (groupsIter.hasNext())
- {
- ContactGroup group = groupsIter.next();
- Iterator<Contact> contactsIter = group.contacts();
-
- while (contactsIter.hasNext())
- {
- ContactZeroconfImpl contact
- = (ContactZeroconfImpl) contactsIter.next();
-
- PresenceStatus oldContactStatus
- = contact.getPresenceStatus();
-
- /* We set contacts to OFFLINE and send an event so that external listeners
- * can be aware that the contacts are reachable anymore. Dunno if that's
- * a good idea. Can be erased if not. Contacts clean is directly done by the
- * contact status change handler.
- */
- if (!oldContactStatus.isOnline())
- {
- //contact.setPresenceStatus(ZeroconfStatusEnum.OFFLINE);
- fireContactPresenceStatusChangeEvent(
- contact
- , contact.getParentContactGroup()
- , oldContactStatus);
- }
- }
- }
- }
- }
-
- /**
- * Returns the volatile group or null if this group has not yet been
- * created.
- *
- * @return a volatile group existing in our contact list or <tt>null</tt>
- * if such a group has not yet been created.
- */
- public ContactGroupZeroconfImpl getNonPersistentGroup()
- {
- for (int i = 0;
- i < getServerStoredContactListRoot().countSubgroups();
- i++)
- {
- ContactGroupZeroconfImpl gr =
- (ContactGroupZeroconfImpl)getServerStoredContactListRoot()
- .getGroup(i);
-
- if(!gr.isPersistent())
- return gr;
- }
-
- return null;
- }
-
-
- /**
- * Creates a non persistent contact for the specified address. This would
- * also create (if necessary) a group for volatile contacts that would not
- * be added to the server stored contact list. This method would have no
- * effect on the server stored contact list.
- * @return the newly created volatile contact.
- * @param bonjourService BonjourService responsible for the chat with this contact
- * @param name Display name of the contact
- * @param ip IP address of the contact
- * @param port Port declared by the contact for direct chat
- * @param contactAddress the address of the volatile contact we'd like to
- * create.
- */
- public ContactZeroconfImpl createVolatileContact(String contactAddress,
- BonjourService bonjourService,
- String name,
- InetAddress ip,
- int port)
- {
- //First create the new volatile contact;
- ContactZeroconfImpl newVolatileContact
- = new ContactZeroconfImpl(contactAddress,
- this.parentProvider, bonjourService, name, ip, port);
- newVolatileContact.setPersistent(false);
-
-
- //Check whether a volatile group already exists and if not create
- //one
- ContactGroupZeroconfImpl theVolatileGroup = getNonPersistentGroup();
-
-
- //if the parent volatile group is null then we create it
- if (theVolatileGroup == null)
- {
- theVolatileGroup = new ContactGroupZeroconfImpl(
- "Bonjour"
- , parentProvider);
- theVolatileGroup.setResolved(false);
- theVolatileGroup.setPersistent(false);
-
- this.contactListRoot.addSubgroup(theVolatileGroup);
-
- fireServerStoredGroupEvent(theVolatileGroup
- , ServerStoredGroupEvent.GROUP_CREATED_EVENT);
- }
-
- //now add the volatile contact instide it
- theVolatileGroup.addContact(newVolatileContact);
- fireSubscriptionEvent(newVolatileContact
- , theVolatileGroup
- , SubscriptionEvent.SUBSCRIPTION_CREATED);
-
- return newVolatileContact;
- }
-
- public Contact getLocalContact()
- {
- return null;
- }
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/zeroconf/OperationSetTypingNotificationsZeroconfImpl.java b/src/net/java/sip/communicator/impl/protocol/zeroconf/OperationSetTypingNotificationsZeroconfImpl.java
deleted file mode 100644
index db397b8..0000000
--- a/src/net/java/sip/communicator/impl/protocol/zeroconf/OperationSetTypingNotificationsZeroconfImpl.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright @ 2015 Atlassian Pty Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.zeroconf;
-
-import net.java.sip.communicator.service.protocol.*;
-
-/**
- * Implements typing notifications for the Zeroconf protocol. The operation
- * set would simply mirror all outgoing typing notifications and make them
- * appear as incoming events generated by the contact that we are currently
- * writing a message to.
- *
- * @author Christian Vincenot
- * @author Maxime Catelin
- * @author Jonathan Martin
- */
-public class OperationSetTypingNotificationsZeroconfImpl
- extends AbstractOperationSetTypingNotifications<ProtocolProviderServiceZeroconfImpl>
-{
-
- /**
- * Creates a new instance of this operation set and keeps the parent
- * provider as a reference.
- *
- * @param provider a ref to the <tt>ProtocolProviderServiceImpl</tt>
- * that created us and that we'll use for retrieving the underlying aim
- * connection.
- */
- OperationSetTypingNotificationsZeroconfImpl(
- ProtocolProviderServiceZeroconfImpl provider)
- {
- super(provider);
- }
-
- /**
- * Sends a notification to <tt>notifiedContatct</tt> that we have entered
- * <tt>typingState</tt>.
- *
- * @param notifiedContact the <tt>Contact</tt> to notify
- * @param typingState the typing state that we have entered.
- *
- * @throws java.lang.IllegalStateException if the underlying stack is
- * not registered and initialized.
- * @throws java.lang.IllegalArgumentException if <tt>notifiedContact</tt> is
- * not an instance belonging to the underlying implementation.
- */
- public void sendTypingNotification(Contact notifiedContact, int typingState)
- throws IllegalStateException, IllegalArgumentException
- {
- if( !(notifiedContact instanceof ContactZeroconfImpl) )
- throw new IllegalArgumentException(
- "The specified contact is not a Zeroconf contact."
- + notifiedContact);
-
- ContactZeroconfImpl to = (ContactZeroconfImpl)notifiedContact;
-
- ClientThread thread = to.getClientThread();
- if (thread == null) return;/*throw new IllegalStateException(
- "No communication channel opened to chat with this contact");*/
-
- if (typingState != STATE_TYPING)
- return;
-
- MessageZeroconfImpl message =
- new MessageZeroconfImpl("",null, MessageZeroconfImpl.TYPING);
- thread.sendMessage(message);
- }
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/zeroconf/ProtocolIconZeroconfImpl.java b/src/net/java/sip/communicator/impl/protocol/zeroconf/ProtocolIconZeroconfImpl.java
deleted file mode 100644
index 4c6ce07..0000000
--- a/src/net/java/sip/communicator/impl/protocol/zeroconf/ProtocolIconZeroconfImpl.java
+++ /dev/null
@@ -1,189 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright @ 2015 Atlassian Pty Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.zeroconf;
-
-import java.io.*;
-import java.util.*;
-
-import net.java.sip.communicator.service.protocol.*;
-import net.java.sip.communicator.util.*;
-
-import org.jitsi.service.resources.*;
-import org.osgi.framework.*;
-
-/**
- * Represents the Zeroconf protocol icon. Implements the <tt>ProtocolIcon</tt>
- * interface in order to provide a Zeroconf logo image in two different sizes.
- *
- * @author Christian Vincenot
- * @author Jonathan Martin
- */
-public class ProtocolIconZeroconfImpl
- implements ProtocolIcon
-{
- private static Logger logger
- = Logger.getLogger(ProtocolIconZeroconfImpl.class);
-
- private static ResourceManagementService resourcesService;
-
- /**
- * A hash table containing the protocol icon in different sizes.
- */
- private static Hashtable<String, byte[]> iconsTable
- = new Hashtable<String, byte[]>();
- static
- {
- iconsTable.put(ProtocolIcon.ICON_SIZE_16x16,
- getImageInBytes("service.protocol.zeroconf.ZEROCONF_16x16"));
-
- iconsTable.put(ProtocolIcon.ICON_SIZE_32x32,
- getImageInBytes("service.protocol.zeroconf.ZEROCONF_32x32"));
-
- iconsTable.put(ProtocolIcon.ICON_SIZE_48x48,
- getImageInBytes("service.protocol.zeroconf.ZEROCONF_48x48"));
-
- iconsTable.put(ProtocolIcon.ICON_SIZE_64x64,
- getImageInBytes("service.protocol.zeroconf.ZEROCONF_64x64"));
- }
-
- /**
- * A hash table containing the protocol icon in different sizes.
- */
- private static Hashtable<String, String> iconPathsTable
- = new Hashtable<String, String>();
- static
- {
- iconPathsTable.put(ProtocolIcon.ICON_SIZE_16x16,
- getResources().getImagePath(
- "service.protocol.zeroconf.ZEROCONF_16x16"));
-
- iconPathsTable.put(ProtocolIcon.ICON_SIZE_32x32,
- getResources().getImagePath(
- "service.protocol.zeroconf.ZEROCONF_32x32"));
-
- iconPathsTable.put(ProtocolIcon.ICON_SIZE_48x48,
- getResources().getImagePath(
- "service.protocol.zeroconf.ZEROCONF_48x48"));
-
- iconPathsTable.put(ProtocolIcon.ICON_SIZE_64x64,
- getResources().getImagePath(
- "service.protocol.zeroconf.ZEROCONF_64x64"));
- }
-
- /**
- * Implements the <tt>ProtocolIcon.getSupportedSizes()</tt> method. Returns
- * an iterator to a set containing the supported icon sizes.
- * @return an iterator to a set containing the supported icon sizes
- */
- public Iterator<String> getSupportedSizes()
- {
- return iconsTable.keySet().iterator();
- }
-
- /**
- * Returns TRUE if a icon with the given size is supported, FALSE-otherwise.
- * @param iconSize Icon size
- * @return True if this size is supported, false otherwise
- */
- public boolean isSizeSupported(String iconSize)
- {
- return iconsTable.containsKey(iconSize);
- }
-
- /**
- * Returns the icon image in the given size.
- * @param iconSize the icon size; one of ICON_SIZE_XXX constants
- * @return Icon image
- */
- public byte[] getIcon(String iconSize)
- {
- return iconsTable.get(iconSize);
- }
-
- /**
- * Returns a path to the icon with the given size.
- * @param iconSize the size of the icon we're looking for
- * @return the path to the icon with the given size
- */
- public String getIconPath(String iconSize)
- {
- return iconPathsTable.get(iconSize);
- }
-
- /**
- * Returns the icon image used to represent the protocol connecting state.
- * @return the icon image used to represent the protocol connecting state
- */
- public byte[] getConnectingIcon()
- {
- return getImageInBytes("zeroconfOnlineIcon");
- }
-
- /**
- * Returns the byte representation of the image corresponding to the given
- * identifier.
- *
- * @param imageID the identifier of the image
- * @return the byte representation of the image corresponding to the given
- * identifier.
- */
- public static byte[] getImageInBytes(String imageID)
- {
- InputStream in = getResources().
- getImageInputStream(imageID);
-
- if (in == null)
- return null;
- byte[] image = null;
- try
- {
- image = new byte[in.available()];
-
- in.read(image);
- }
- catch (IOException e)
- {
- logger.error("Failed to load image:" + imageID, e);
- }
-
- return image;
- }
-
- /**
- * Returns the <tt>ResourceManagementService</tt>.
- *
- * @return the <tt>ResourceManagementService</tt>
- */
- public static ResourceManagementService getResources()
- {
- if (resourcesService == null)
- {
- ServiceReference serviceReference = ZeroconfActivator.bundleContext
- .getServiceReference(ResourceManagementService.class.getName());
-
- if(serviceReference == null)
- return null;
-
- resourcesService
- = (ResourceManagementService)ZeroconfActivator.bundleContext
- .getService(serviceReference);
- }
-
- return resourcesService;
- }
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/zeroconf/ProtocolProviderFactoryZeroconfImpl.java b/src/net/java/sip/communicator/impl/protocol/zeroconf/ProtocolProviderFactoryZeroconfImpl.java
deleted file mode 100644
index e68033f..0000000
--- a/src/net/java/sip/communicator/impl/protocol/zeroconf/ProtocolProviderFactoryZeroconfImpl.java
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright @ 2015 Atlassian Pty Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.zeroconf;
-
-import java.util.*;
-
-import net.java.sip.communicator.service.protocol.*;
-
-import org.osgi.framework.*;
-
-/**
- * The Zeroconf protocol provider factory creates instances of the Zeroconf
- * protocol provider service. One Service instance corresponds to one account.
- *
- *
- * @author Christian Vincenot
- * @author Maxime Catelin
- */
-public class ProtocolProviderFactoryZeroconfImpl
- extends ProtocolProviderFactory
-{
-
- /**
- * Creates an instance of the ProtocolProviderFactoryZeroconfImpl.
- */
- public ProtocolProviderFactoryZeroconfImpl()
- {
- super(ZeroconfActivator.getBundleContext(), ProtocolNames.ZEROCONF);
- }
-
- /**
- * Initializaed and creates an account corresponding to the specified
- * accountProperties and registers the resulting ProtocolProvider in the
- * <tt>context</tt> BundleContext parameter.
- *
- * @param userIDStr tha/a user identifier uniquely representing the newly
- * created account within the protocol namespace.
- * @param accountProperties a set of protocol (or implementation)
- * specific properties defining the new account.
- * @return the AccountID of the newly created account.
- */
- @Override
- public AccountID installAccount( String userIDStr,
- Map<String, String> accountProperties)
- {
- BundleContext context
- = ZeroconfActivator.getBundleContext();
- if (context == null)
- throw new NullPointerException(
- "The specified BundleContext was null");
-
- if (userIDStr == null)
- throw new NullPointerException(
- "The specified AccountID was null");
-
- if (accountProperties == null)
- throw new NullPointerException(
- "The specified property map was null");
-
- accountProperties.put(USER_ID, userIDStr);
-
- AccountID accountID =
- new ZeroconfAccountID(userIDStr, accountProperties);
-
- //make sure we haven't seen this account id before.
- if (registeredAccounts.containsKey(accountID))
- throw new IllegalStateException(
- "An account for id " + userIDStr + " was already installed!");
-
- //first store the account and only then load it as the load generates
- //an osgi event, the osgi event triggers (through the UI) a call to the
- //ProtocolProviderService.register() method and it needs to access
- //the configuration service and check for a stored password.
- this.storeAccount(accountID, false);
-
- accountID = loadAccount(accountProperties);
-
- return accountID;
- }
-
- @Override
- protected AccountID createAccountID(String userID, Map<String, String> accountProperties)
- {
- return new ZeroconfAccountID(userID, accountProperties);
- }
-
- @Override
- protected ProtocolProviderService createService(String userID,
- AccountID accountID)
- {
- ProtocolProviderServiceZeroconfImpl service =
- new ProtocolProviderServiceZeroconfImpl();
-
- service.initialize(userID, accountID);
- return service;
- }
-
- @Override
- public void modifyAccount( ProtocolProviderService protocolProvider,
- Map<String, String> accountProperties)
- throws NullPointerException
- {
- // TODO Auto-generated method stub
- }
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/zeroconf/ProtocolProviderServiceZeroconfImpl.java b/src/net/java/sip/communicator/impl/protocol/zeroconf/ProtocolProviderServiceZeroconfImpl.java
deleted file mode 100644
index 7fe916f..0000000
--- a/src/net/java/sip/communicator/impl/protocol/zeroconf/ProtocolProviderServiceZeroconfImpl.java
+++ /dev/null
@@ -1,302 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright @ 2015 Atlassian Pty Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.zeroconf;
-
-import net.java.sip.communicator.service.protocol.*;
-import net.java.sip.communicator.service.protocol.event.*;
-import net.java.sip.communicator.util.*;
-
-/**
- * An implementation of the protocol provider service over the Zeroconf protocol
- *
- * @author Christian Vincenot
- * @author Maxime Catelin
- */
-public class ProtocolProviderServiceZeroconfImpl
- extends AbstractProtocolProviderService
-{
- /**
- * The logger for this class.
- */
- private static final Logger logger =
- Logger.getLogger(ProtocolProviderServiceZeroconfImpl.class);
-
- /**
- * We use this to lock access to initialization.
- */
- private final Object initializationLock = new Object();
-
- /**
- * The id of the account that this protocol provider represents.
- */
- private AccountID accountID = null;
-
- /**
- * Indicates whether or not the provider is initialized and ready for use.
- */
- private boolean isInitialized = false;
-
- /**
- * The logo corresponding to the zeroconf protocol.
- */
- private final ProtocolIconZeroconfImpl zeroconfIcon
- = new ProtocolIconZeroconfImpl();
-
- /**
- * The registration state that we are currently in. Note that in a real
- * world protocol implementation this field won't exist and the registration
- * state would be retrieved from the protocol stack.
- */
- private RegistrationState currentRegistrationState
- = RegistrationState.UNREGISTERED;
-
- /**
- * The BonjourService corresponding to this ProtocolProviderService
- */
-
- private BonjourService bonjourService;
-
- /**
- * The default constructor for the Zeroconf protocol provider.
- */
- public ProtocolProviderServiceZeroconfImpl()
- {
- if (logger.isTraceEnabled())
- logger.trace("Creating a zeroconf provider.");
- }
-
- /**
- * Returns the AccountID that uniquely identifies the account represented
- * by this instance of the ProtocolProviderService.
- *
- * @return the id of the account represented by this provider.
- */
- public AccountID getAccountID()
- {
- return accountID;
- }
-
- /**
- * Returns the Bonjour Service that handles the Bonjour protocol stack.
- *
- *@return the Bonjour Service linked with this Protocol Provider
- */
- public BonjourService getBonjourService()
- {
- return bonjourService;
- }
-
- /**
- * Initializes the service implementation, and puts it in a sate where it
- * could interoperate with other services. It is strongly recomended that
- * properties in this Map be mapped to property names as specified by
- * <tt>AccountProperties</tt>.
- *
- * @param userID the user id of the zeroconf account we're currently
- * initializing
- * @param accountID the identifier of the account that this protocol
- * provider represents.
- *
- * @see net.java.sip.communicator.service.protocol.AccountID
- */
- protected void initialize(String userID,
- AccountID accountID)
- {
- synchronized(initializationLock)
- {
- this.accountID = accountID;
-
-
- //initialize the presence operationset
- OperationSetPersistentPresenceZeroconfImpl persistentPresence =
- new OperationSetPersistentPresenceZeroconfImpl(this);
-
- addSupportedOperationSet(
- OperationSetPersistentPresence.class,
- persistentPresence);
- //register it once again for those that simply need presence and
- //won't be smart enough to check for a persistent presence
- //alternative
- addSupportedOperationSet(
- OperationSetPresence.class,
- persistentPresence);
-
- //initialize the IM operation set
- addSupportedOperationSet(
- OperationSetBasicInstantMessaging.class,
- new OperationSetBasicInstantMessagingZeroconfImpl(
- this,
- persistentPresence));
-
- //initialize the typing notifications operation set
- addSupportedOperationSet(
- OperationSetTypingNotifications.class,
- new OperationSetTypingNotificationsZeroconfImpl(this));
-
- isInitialized = true;
- }
- }
-
- /**
- * Returns the short name of the protocol that the implementation of this
- * provider is based upon (like SIP, Jabber, ICQ/AIM, or others for
- * example).
- *
- * @return a String containing the short name of the protocol this
- * service is implementing (most often that would be a name in
- * ProtocolNames).
- */
- public String getProtocolName()
- {
- return ProtocolNames.ZEROCONF;
- }
-
- /**
- * Returns the state of the registration of this protocol provider with
- * the corresponding registration service.
- *
- * @return ProviderRegistrationState
- */
- public RegistrationState getRegistrationState()
- {
- return currentRegistrationState;
- }
-
- /**
- * Starts the registration process.
- *
- * @param authority the security authority that will be used for
- * resolving any security challenges that may be returned during the
- * registration or at any moment while wer're registered.
- * @throws OperationFailedException with the corresponding code it the
- * registration fails for some reason (e.g. a networking error or an
- * implementation problem).
- */
- public void register(SecurityAuthority authority)
- throws OperationFailedException
- {
- //we don't need a password here since there's no server in
- //zeroconf.
-
- RegistrationState oldState = currentRegistrationState;
- currentRegistrationState = RegistrationState.REGISTERED;
-
-
- //ICI : creer le service Zeroconf !!
- if (logger.isInfoEnabled())
- logger.info("ZEROCONF: Starting the service");
- this.bonjourService = new BonjourService(5298, this);
-
- //bonjourService.changeStatus(ZeroconfStatusEnum.ONLINE);
-
- fireRegistrationStateChanged(
- oldState
- , currentRegistrationState
- , RegistrationStateChangeEvent.REASON_USER_REQUEST
- , null);
- }
-
- /**
- * Makes the service implementation close all open sockets and release
- * any resources that it might have taken and prepare for
- * shutdown/garbage collection.
- */
- public void shutdown()
- {
- if(!isInitialized)
- {
- return;
- }
- if (logger.isTraceEnabled())
- logger.trace("Killing the Zeroconf Protocol Provider.");
-
- if(isRegistered())
- {
- try
- {
- //do the unregistration
- unregister();
- }
- catch (OperationFailedException ex)
- {
- //we're shutting down so we need to silence the exception here
- logger.error(
- "Failed to properly unregister before shutting down. "
- + getAccountID()
- , ex);
- }
- }
-
- isInitialized = false;
- }
-
- /**
- * Ends the registration of this protocol provider with the current
- * registration service.
- *
- * @throws OperationFailedException with the corresponding code it the
- * registration fails for some reason (e.g. a networking error or an
- * implementation problem).
- */
- public void unregister()
- throws OperationFailedException
- {
- RegistrationState oldState = currentRegistrationState;
- currentRegistrationState = RegistrationState.UNREGISTERED;
-
- if(bonjourService != null)
- bonjourService.shutdown();
-
- fireRegistrationStateChanged(
- oldState
- , currentRegistrationState
- , RegistrationStateChangeEvent.REASON_USER_REQUEST
- , null);
- }
-
- /*
- * (non-Javadoc)
- *
- * @see net.java.sip.communicator.service.protocol.ProtocolProviderService#
- * isSignallingTransportSecure()
- */
- public boolean isSignalingTransportSecure()
- {
- return false;
- }
-
- /**
- * Returns the "transport" protocol of this instance used to carry the
- * control channel for the current protocol service.
- *
- * @return The "transport" protocol of this instance: TCP.
- */
- public TransportProtocol getTransportProtocol()
- {
- return TransportProtocol.TCP;
- }
-
- /**
- * Returns the zeroconf protocol icon.
- * @return the zeroconf protocol icon
- */
- public ProtocolIcon getProtocolIcon()
- {
- return zeroconfIcon;
- }
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/zeroconf/ZeroconfAccountID.java b/src/net/java/sip/communicator/impl/protocol/zeroconf/ZeroconfAccountID.java
deleted file mode 100644
index 64e22c7..0000000
--- a/src/net/java/sip/communicator/impl/protocol/zeroconf/ZeroconfAccountID.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright @ 2015 Atlassian Pty Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.zeroconf;
-
-import java.util.*;
-
-import net.java.sip.communicator.service.protocol.*;
-
-/**
- * The Zeroconf implementation of a sip-communicator AccountID
- *
- * @author Christian Vincenot
- */
-public class ZeroconfAccountID
- extends AccountID
-{
- /* Firstname, lastname, mail address */
- private String first = null;
- private String last = null;
- private String mail = null;
-
- private boolean rememberContacts = false;
-
- /**
- * Creates a zeroconf account id from the specified id and account
- * properties.
- * @param userID id identifying this account
- * @param accountProperties any other properties necessary for the account.
- */
- ZeroconfAccountID(String userID, Map<String, String> accountProperties)
- {
- super(userID,
- accountProperties,
- ProtocolNames.ZEROCONF,
- "zeroconf.org");
-
- first = accountProperties.get("first");
- last = accountProperties.get("last");
- mail = accountProperties.get("mail");
-
- rememberContacts =
- new Boolean(accountProperties.get("rememberContacts"))
- .booleanValue();
- }
-
- /**
- * Returns a String representing the firstname of this user.
- * @return String representing the firstname of this user.
- */
- public String getFirst()
- {
- return first;
- }
-
- /**
- * Returns a String representing the lastname of this user.
- * @return String representing the lastname of this user.
- */
- public String getLast()
- {
- return last;
- }
-
- /**
- * Returns a String representing the mail address of this user.
- * @return String representing the mail address of this user.
- */
- public String getMail()
- {
- return mail;
- }
-
- /**
- * Returns a boolean indicating if we store the contacts we meet or not.
- * @return boolean indicating if we store the contacts we meet or not.
- */
- public boolean isRememberContacts()
- {
- return rememberContacts;
- }
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/zeroconf/ZeroconfActivator.java b/src/net/java/sip/communicator/impl/protocol/zeroconf/ZeroconfActivator.java
deleted file mode 100644
index 2544bab..0000000
--- a/src/net/java/sip/communicator/impl/protocol/zeroconf/ZeroconfActivator.java
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright @ 2015 Atlassian Pty Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.zeroconf;
-
-import java.util.*;
-
-import net.java.sip.communicator.service.protocol.*;
-import net.java.sip.communicator.util.*;
-
-import org.osgi.framework.*;
-
-/**
- * Loads the Zeroconf provider factory and registers its services in the OSGI
- * bundle context.
- *
- * @author Christian Vincenot
- * @author Maxime Catelin
- */
-public class ZeroconfActivator
- implements BundleActivator
-{
- private static final Logger logger
- = Logger.getLogger(ZeroconfActivator.class);
-
- /**
- * A reference to the registration of our Zeroconf protocol provider
- * factory.
- */
- private ServiceRegistration zeroconfPpFactoryServReg = null;
-
- /**
- * A reference to the Zeroconf protocol provider factory.
- */
- private static ProtocolProviderFactoryZeroconfImpl
- zeroconfProviderFactory = null;
-
- /**
- * The currently valid bundle context.
- */
- static BundleContext bundleContext = null;
-
-
- /**
- * Called when this bundle is started. In here we'll export the
- * zeroconf ProtocolProviderFactory implementation so that it could be
- * possible to register accounts with it in SIP Communicator.
- *
- * @param context The execution context of the bundle being started.
- * @throws Exception If this method throws an exception, this bundle is
- * marked as stopped and the Framework will remove this bundle's
- * listeners, unregister all services registered by this bundle, and
- * release all services used by this bundle.
- */
- public void start(BundleContext context)
- throws Exception
- {
-// logger.setLevelAll();
-
- bundleContext = context;
-
- Hashtable<String, String> hashtable = new Hashtable<String, String>();
- hashtable.put(ProtocolProviderFactory.PROTOCOL, "Zeroconf");
-
- zeroconfProviderFactory = new ProtocolProviderFactoryZeroconfImpl();
-
- //register the zeroconf provider factory.
- zeroconfPpFactoryServReg = context.registerService(
- ProtocolProviderFactory.class.getName(),
- zeroconfProviderFactory,
- hashtable);
-
- if (logger.isInfoEnabled())
- logger.info("Zeroconf protocol implementation [STARTED].");
- }
-
- /**
- * Returns a reference to the bundle context that we were started with.
- * @return a reference to the BundleContext instance that we were started
- * witn.
- */
- public static BundleContext getBundleContext()
- {
- return bundleContext;
- }
-
- /**
- * Retrurns a reference to the protocol provider factory that we have
- * registered.
- * @return a reference to the <tt>ProtocolProviderFactoryJabberImpl</tt>
- * instance that we have registered from this package.
- */
- public static ProtocolProviderFactoryZeroconfImpl getProtocolProviderFactory()
- {
- return zeroconfProviderFactory;
- }
-
-
- /**
- * Called when this bundle is stopped so the Framework can perform the
- * bundle-specific activities necessary to stop the bundle.
- *
- * @param context The execution context of the bundle being stopped.
- * @throws Exception If this method throws an exception, the bundle is
- * still marked as stopped, and the Framework will remove the bundle's
- * listeners, unregister all services registered by the bundle, and
- * release all services used by the bundle.
- */
- public void stop(BundleContext context)
- throws Exception
- {
- zeroconfProviderFactory.stop();
- zeroconfPpFactoryServReg.unregister();
-
- if (logger.isInfoEnabled())
- logger.info("Zeroconf protocol implementation [STOPPED].");
- }
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/zeroconf/ZeroconfStatusEnum.java b/src/net/java/sip/communicator/impl/protocol/zeroconf/ZeroconfStatusEnum.java
deleted file mode 100644
index 3fe2745..0000000
--- a/src/net/java/sip/communicator/impl/protocol/zeroconf/ZeroconfStatusEnum.java
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright @ 2015 Atlassian Pty Ltd
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.zeroconf;
-
-import java.util.*;
-
-import net.java.sip.communicator.service.protocol.*;
-
-/**
- * An implementation of <tt>PresenceStatus</tt> that enumerates all states that
- * a Zeroconf contact can fall into.
- *
- * @author Christian Vincenot
- * @author Jonathan Martin
- */
-public class ZeroconfStatusEnum
- extends PresenceStatus
-{
-
- /**
- * Indicates an Offline status or status with 0 connectivity.
- */
- public static final ZeroconfStatusEnum OFFLINE
- = new ZeroconfStatusEnum(
- 0,
- "Offline",
- ProtocolIconZeroconfImpl.getImageInBytes(
- "service.protocol.zeroconf.OFFLINE_STATUS_ICON"));
-
- /**
- * The DND status. Indicates that the user has connectivity but prefers
- * not to be contacted.
- */
- public static final ZeroconfStatusEnum DO_NOT_DISTURB
- = new ZeroconfStatusEnum(
- 30,
- "Do Not Disturb",//, "Do Not Disturb",
- ProtocolIconZeroconfImpl.getImageInBytes(
- "service.protocol.zeroconf.DND_STATUS_ICON"));
-
- /**
- * The Invisible status. Indicates that the user has connectivity even
- * though it may appear otherwise to others, to whom she would appear to be
- * offline.
- */
- public static final ZeroconfStatusEnum INVISIBLE
- = new ZeroconfStatusEnum(
- 45,
- "Invisible",
- ProtocolIconZeroconfImpl.getImageInBytes(
- "service.protocol.zeroconf.INVISIBLE_STATUS_ICON"));
-
- /**
- * The Online status. Indicate that the user is able and willing to
- * communicate.
- */
- public static final ZeroconfStatusEnum ONLINE
- = new ZeroconfStatusEnum(
- 65,
- "Available",//, "Online"
- ProtocolIconZeroconfImpl.getImageInBytes(
- "service.protocol.zeroconf.ONLINE_STATUS_ICON"));
-
-
- /**
- * Initialize the list of supported status states.
- */
- private static List<PresenceStatus> supportedStatusSet = new LinkedList<PresenceStatus>();
- static
- {
- supportedStatusSet.add(OFFLINE);
- supportedStatusSet.add(DO_NOT_DISTURB);
-
- /* INVISIBLE STATUS could be supported by unregistering JmDNS and
- * accepting unknown contacts' messages */
- //supportedStatusSet.add(INVISIBLE);
-
- supportedStatusSet.add(ONLINE);
- }
-
- /**
- * Creates an instance of <tt>ZeroconfPresneceStatus</tt> with the
- * specified parameters.
- * @param status the connectivity level of the new presence status instance
- * @param statusName the name of the presence status.
- * @param statusIcon the icon associated with this status
- */
- private ZeroconfStatusEnum(int status,
- String statusName,
- byte[] statusIcon)
- {
- super(status, statusName, statusIcon);
- }
-
- /**
- * Returns an iterator over all status instances supproted by the zeroconf
- * provider.
- * @return an <tt>Iterator</tt> over all status instances supported by the
- * zeroconf provider.
- */
- static Iterator<PresenceStatus> supportedStatusSet()
- {
- return supportedStatusSet.iterator();
- }
-
- /**
- * @param status String representation of the status
- * @return ZeroconfStatusEnum corresponding the supplied String value
- */
- static ZeroconfStatusEnum statusOf(String status)
- {
- Iterator<PresenceStatus> statusIter = supportedStatusSet();
- while (statusIter.hasNext())
- {
- ZeroconfStatusEnum state = (ZeroconfStatusEnum)statusIter.next();
- if (state.statusName.equalsIgnoreCase(status))
- return state;
- }
- return null;
- }
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/DNSCache.java b/src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/DNSCache.java
deleted file mode 100644
index 0baaff4..0000000
--- a/src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/DNSCache.java
+++ /dev/null
@@ -1,294 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright 2003-2005 Arthur van Hoff Rick Blair
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.zeroconf.jmdns;
-
-import java.util.*;
-
-import net.java.sip.communicator.util.*;
-
-/**
- * A table of DNS entries. This is a hash table which
- * can handle multiple entries with the same name.
- * <p/>
- * Storing multiple entries with the same name is implemented using a
- * linked list of <code>CacheNode</code>'s.
- * <p/>
- * The current implementation of the API of DNSCache does expose the
- * cache nodes to clients. Clients must explicitly deal with the nodes
- * when iterating over entries in the cache. Here's how to iterate over
- * all entries in the cache:
- * <pre>
- * for (Iterator i=dnscache.iterator(); i.hasNext(); )
- * {
- * for ( DNSCache.CacheNode n = (DNSCache.CacheNode) i.next();
- * n != null;
- * n.next())
- * {
- * DNSEntry entry = n.getValue();
- * ...do something with entry...
- * }
- * }
- * </pre>
- * <p/>
- * And here's how to iterate over all entries having a given name:
- * <pre>
- * for ( DNSCache.CacheNode n = (DNSCache.CacheNode) dnscache.find(name);
- * n != null;
- * n.next())
- * {
- * DNSEntry entry = n.getValue();
- * ...do something with entry...
- * }
- * </pre>
- *
- * @version %I%, %G%
- * @author Arthur van Hoff, Werner Randelshofer, Rick Blair
- */
-class DNSCache
-{
- private static Logger logger = Logger.getLogger(DNSCache.class.toString());
- // Implementation note:
- // We might completely hide the existence of CacheNode's in a future version
- // of DNSCache. But this will require to implement two (inner) classes for
- // the iterators that will be returned by method <code>iterator()</code> and
- // method <code>find(name)</code>.
- // Since DNSCache is not a public class, it does not seem worth the effort
- // to clean its API up that much.
-
- // [PJYF Oct 15 2004] This should implements Collections
- // that would be amuch cleaner implementation
-
- /**
- * The number of DNSEntry's in the cache.
- */
- private int size;
-
- /**
- * The hashtable used internally to store the entries of the cache.
- * Keys are instances of String. The String contains an unqualified service
- * name.
- * Values are linked lists of CacheNode instances.
- */
- private HashMap<String, CacheNode> hashtable;
-
- /**
- * Cache nodes are used to implement storage of multiple DNSEntry's of the
- * same name in the cache.
- */
- public static class CacheNode
- {
- private DNSEntry value;
- private CacheNode next;
-
- public CacheNode(DNSEntry value)
- {
- this.value = value;
-// String SLevel = System.getProperty("jmdns.debug");
-// if (SLevel == null)
-// SLevel = "INFO";
-// logger.setLevel(Level.parse(SLevel));
- }
-
- public CacheNode next()
- {
- return next;
- }
-
- public DNSEntry getValue()
- {
- return value;
- }
- }
-
-
- /**
- * Create a table with a given initial size.
- * @param size initial size.
- */
- public DNSCache(final int size)
- {
- hashtable = new HashMap<String, CacheNode>(size);
-
-// String SLevel = System.getProperty("jmdns.debug");
-// if (SLevel == null) SLevel = "INFO";
-// logger.setLevel(Level.parse(SLevel));
- }
-
- /**
- * Clears the cache.
- */
- public synchronized void clear()
- {
- hashtable.clear();
- size = 0;
- }
-
- /**
- * Adds an entry to the table.
- * @param entry added to the table.
- */
- public synchronized void add(final DNSEntry entry)
- {
- //logger.log("DNSCache.add("+entry.getName()+")");
- CacheNode newValue = new CacheNode(entry);
- CacheNode node = hashtable.get(entry.getName());
- if (node == null)
- {
- hashtable.put(entry.getName(), newValue);
- }
- else
- {
- newValue.next = node.next;
- node.next = newValue;
- }
- size++;
- }
-
- /**
- * Remove a specific entry from the table.
- * @param entry removed from table.
- * @return Returns true if the entry was found.
- */
- public synchronized boolean remove(DNSEntry entry)
- {
- CacheNode node = hashtable.get(entry.getName());
- if (node != null)
- {
- if (node.value == entry)
- {
- if (node.next == null)
- {
- hashtable.remove(entry.getName());
- }
- else
- {
- hashtable.put(entry.getName(), node.next);
- }
- size--;
- return true;
- }
-
- CacheNode previous = node;
- node = node.next;
- while (node != null)
- {
- if (node.value == entry)
- {
- previous.next = node.next;
- size--;
- return true;
- }
- previous = node;
- node = node.next;
- }
- ;
- }
- return false;
- }
-
- /**
- * Get a matching DNS entry from the table (using equals).
- * @param entry to be found in table.
- * @return Returns the entry that was found.
- */
- public synchronized DNSEntry get(DNSEntry entry)
- {
- for (CacheNode node = find(entry.getName()); node != null; node = node.next)
- {
- if (node.value.equals(entry))
- {
- return node.value;
- }
- }
- return null;
- }
-
- /**
- * Get a matching DNS entry from the table.
- * @param name
- * @param type
- * @param clazz
- * @return Return the entry if found, null otherwise.
- */
- public synchronized DNSEntry get(String name, int type, int clazz)
- {
- for (CacheNode node = find(name); node != null; node = node.next)
- {
- if (node.value.type == type && node.value.clazz == clazz)
- {
- return node.value;
- }
- }
- return null;
- }
-
- /**
- * Iterates over all cache nodes.
- * The iterator returns instances of DNSCache.CacheNode.
- * Each instance returned is the first node of a linked list.
- * To retrieve all entries, one must iterate over this linked list. See
- * code snippets in the header of the class.
- * @return Returns iterator with instances of DNSCache.CacheNode.
- */
- public Iterator<DNSCache.CacheNode> iterator()
- {
- return Collections.unmodifiableCollection(hashtable.values()).iterator();
- }
-
- /**
- * Iterate only over items with matching name.
- * If an instance is returned, it is the first node of a linked list.
- * To retrieve all entries, one must iterate over this linked list.
- * @param name to be found.
- * @return Returns an instance of DNSCache.CacheNode or null.
- */
- public synchronized CacheNode find(String name)
- {
- return hashtable.get(name);
- }
-
- /**
- * List all entries for debugging.
- */
- public synchronized void print()
- {
- for (Iterator<CacheNode> i = iterator(); i.hasNext();)
- {
- for (CacheNode n = i.next(); n != null; n = n.next)
- {
- if (logger.isInfoEnabled())
- logger.info(n.value.toString());
- }
- }
- }
-
- @Override
- public synchronized String toString()
- {
- StringBuffer aLog = new StringBuffer();
- aLog.append("\t---- cache ----");
- for (Iterator<CacheNode> i = iterator(); i.hasNext();)
- {
- for (CacheNode n = i.next(); n != null; n = n.next)
- {
- aLog.append("\n\t\t" + n.value);
- }
- }
- return aLog.toString();
- }
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/DNSConstants.java b/src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/DNSConstants.java
deleted file mode 100644
index 8792c8d..0000000
--- a/src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/DNSConstants.java
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright 2003-2005 Arthur van Hoff, Rick Blair
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.zeroconf.jmdns;
-
-/**
- * DNS constants.
- *
- * @version %I%, %G%
- * @author Arthur van Hoff, Jeff Sonstein,
- * Werner Randelshofer, Pierre Frisch, Rick Blair
- */
-public final class DNSConstants
-{
-
- // changed to final class - jeffs
- final static String MDNS_GROUP = "224.0.0.251";
- final static String MDNS_GROUP_IPV6 = "FF02::FB";
- final static int MDNS_PORT = 5353;
- final static int DNS_PORT = 53;
- // default one hour TTL
- final static int DNS_TTL = 60 * 60;
- // two hour TTL (draft-cheshire-dnsext-multicastdns.txt ch 13)
- // final static int DNS_TTL = 120 * 60;
-
- final static int MAX_MSG_TYPICAL = 1460;
- final static int MAX_MSG_ABSOLUTE = 8972;
-
- final static int FLAGS_QR_MASK = 0x8000; // Query response mask
- final static int FLAGS_QR_QUERY = 0x0000; // Query
- final static int FLAGS_QR_RESPONSE = 0x8000;// Response
-
- public final static int FLAGS_AA = 0x0400; // Authorative answer
- final static int FLAGS_TC = 0x0200; // Truncated
- final static int FLAGS_RD = 0x0100; // Recursion desired
- public final static int FLAGS_RA = 0x8000; // Recursion available
-
- final static int FLAGS_Z = 0x0040; // Zero
- final static int FLAGS_AD = 0x0020; // Authentic data
- final static int FLAGS_CD = 0x0010; // Checking disabled
-
- // Final Static Internet
- public final static int CLASS_IN = 1;
- // CSNET
- final static int CLASS_CS = 2;
- // CHAOS
- final static int CLASS_CH = 3;
- // Hesiod
- final static int CLASS_HS = 4;
- // Used in DNS UPDATE [RFC 2136]
- final static int CLASS_NONE = 254;
- // Not a DNS class, but a DNS query class, meaning "all classes"
- final static int CLASS_ANY = 255;
- // Multicast DNS uses the bottom 15 bits to identify the record class...
- final static int CLASS_MASK = 0x7FFF;
- // ... and the top bit indicates that all other cached records are now invalid
- public final static int CLASS_UNIQUE = 0x8000;
-
- final static int TYPE_IGNORE = 0; // This is a hack to stop further processing
- public final static int TYPE_A = 1; // Address
- final static int TYPE_NS = 2; // Name Server
- final static int TYPE_MD = 3; // Mail Destination
- final static int TYPE_MF = 4; // Mail Forwarder
- final static int TYPE_CNAME = 5; // Canonical Name
- final static int TYPE_SOA = 6; // Start of Authority
- final static int TYPE_MB = 7; // Mailbox
- final static int TYPE_MG = 8; // Mail Group
- final static int TYPE_MR = 9; // Mail Rename
- final static int TYPE_NULL = 10; // NULL RR
- final static int TYPE_WKS = 11; // Well-known-service
- final static int TYPE_PTR = 12; // Domain Name pofinal static inter
- final static int TYPE_HINFO = 13; // Host information
- final static int TYPE_MINFO = 14; // Mailbox information
- final static int TYPE_MX = 15; // Mail exchanger
- public final static int TYPE_TXT = 16;// Arbitrary text string
- final static int TYPE_RP = 17; // for Responsible Person [RFC1183]
- final static int TYPE_AFSDB = 18; // for AFS Data Base location [RFC1183]
- final static int TYPE_X25 = 19; // for X.25 PSDN address [RFC1183]
- final static int TYPE_ISDN = 20; // for ISDN address [RFC1183]
- final static int TYPE_RT = 21; // for Route Through [RFC1183]
- final static int TYPE_NSAP = 22; // for NSAP address, NSAP style A record [RFC1706]
- final static int TYPE_NSAP_PTR = 23;//
- final static int TYPE_SIG = 24; // for security signature [RFC2931]
- final static int TYPE_KEY = 25; // for security key [RFC2535]
- final static int TYPE_PX = 26; // X.400 mail mapping information [RFC2163]
- final static int TYPE_GPOS = 27; // Geographical Position [RFC1712]
- final static int TYPE_AAAA = 28; // IP6 Address [Thomson]
- final static int TYPE_LOC = 29; // Location Information [Vixie]
- final static int TYPE_NXT = 30; // Next Domain - OBSOLETE [RFC2535, RFC3755]
- final static int TYPE_EID = 31; // Endpoint Identifier [Patton]
- final static int TYPE_NIMLOC = 32; // Nimrod Locator [Patton]
- public final static int TYPE_SRV = 33;// Server Selection [RFC2782]
- final static int TYPE_ATMA = 34; // ATM Address [Dobrowski]
- final static int TYPE_NAPTR = 35; // Naming Authority Pointer [RFC2168, RFC2915]
- final static int TYPE_KX = 36; // Key Exchanger [RFC2230]
- final static int TYPE_CERT = 37; // CERT [RFC2538]
- final static int TYPE_A6 = 38; // A6 [RFC2874]
- final static int TYPE_DNAME = 39; // DNAME [RFC2672]
- final static int TYPE_SINK = 40; // SINK [Eastlake]
- final static int TYPE_OPT = 41; // OPT [RFC2671]
- final static int TYPE_APL = 42; // APL [RFC3123]
- final static int TYPE_DS = 43; // Delegation Signer [RFC3658]
- final static int TYPE_SSHFP = 44; // SSH Key Fingerprint [RFC-ietf-secsh-dns-05.txt]
- final static int TYPE_RRSIG = 46; // RRSIG [RFC3755]
- final static int TYPE_NSEC = 47; // NSEC [RFC3755]
- final static int TYPE_DNSKEY = 48; // DNSKEY [RFC3755]
- final static int TYPE_UINFO = 100; // [IANA-Reserved]
- final static int TYPE_UID = 101; // [IANA-Reserved]
- final static int TYPE_GID = 102; // [IANA-Reserved]
- final static int TYPE_UNSPEC = 103; // [IANA-Reserved]
- final static int TYPE_TKEY = 249; // Transaction Key [RFC2930]
- final static int TYPE_TSIG = 250; // Transaction Signature [RFC2845]
- final static int TYPE_IXFR = 251; // Incremental transfer [RFC1995]
- final static int TYPE_AXFR = 252; // Transfer of an entire zone [RFC1035]
- final static int TYPE_MAILA = 253; // Mailbox-related records (MB, MG or MR) [RFC1035]
- final static int TYPE_MAILB = 254; // Mail agent RRs (Obsolete - see MX) [RFC1035]
- final static int TYPE_ANY = 255; // Request for all records [RFC1035]
-
- //Time Intervals for various functions
-
- //milliseconds before send shared query
- final static int SHARED_QUERY_TIME = 20;
- //milliseconds between query loops.
- final static int QUERY_WAIT_INTERVAL = 225;
- //milliseconds between probe loops.
- final static int PROBE_WAIT_INTERVAL = 250;
- //minimal wait interval for response.
- final static int RESPONSE_MIN_WAIT_INTERVAL = 20;
- //maximal wait interval for response
- final static int RESPONSE_MAX_WAIT_INTERVAL = 115;
- //milliseconds to wait after conflict.
- final static int PROBE_CONFLICT_INTERVAL = 1000;
- //After x tries go 1 time a sec. on probes.
- final static int PROBE_THROTTLE_COUNT = 10;
- //We only increment the throttle count, if
- // the previous increment is inside this interval.
- final static int PROBE_THROTTLE_COUNT_INTERVAL = 5000;
- //milliseconds between Announce loops.
- final static int ANNOUNCE_WAIT_INTERVAL = 1000;
- //milliseconds between cache cleanups.
- final static int RECORD_REAPER_INTERVAL = 10000;
-
- final static int KNOWN_ANSWER_TTL = 120;
- // 50% of the TTL in milliseconds
- final static int ANNOUNCED_RENEWAL_TTL_INTERVAL = DNS_TTL * 500;
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/DNSEntry.java b/src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/DNSEntry.java
deleted file mode 100644
index 7132756..0000000
--- a/src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/DNSEntry.java
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright 2003-2005 Arthur van Hoff Rick Blair
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.zeroconf.jmdns;
-
-import java.util.logging.*;
-
-/**
- * DNS entry with a name, type, and class. This is the base
- * class for questions and records.
- *
- * @version %I%, %G%
- * @author Arthur van Hoff, Pierre Frisch, Rick Blair
- * @author Christian Vincenot
- */
-public class DNSEntry
-{
- private static Logger logger = Logger.getLogger(DNSEntry.class.toString());
- String key;
- String name;
- int type;
- int clazz;
- boolean unique;
-
- /**
- * Create an entry.
- */
- DNSEntry(String name, int type, int clazz)
- {
- this.key = name.toLowerCase();
- this.name = name;
- this.type = type;
- this.clazz = clazz & DNSConstants.CLASS_MASK;
- this.unique = (clazz & DNSConstants.CLASS_UNIQUE) != 0;
-
- String SLevel = System.getProperty("jmdns.debug");
- if (SLevel == null) SLevel = "INFO";
- logger.setLevel(Level.parse(SLevel));
- }
-
- /**
- * Check if two entries have exactly the same name, type, and class.
- */
- @Override
- public boolean equals(Object obj)
- {
- if (obj instanceof DNSEntry)
- {
- DNSEntry other = (DNSEntry) obj;
- return name.equals(other.name) &&
- type == other.type &&
- clazz == other.clazz;
- }
- return false;
- }
-
- public String getName()
- {
- return name;
- }
-
- public int getType()
- {
- return type;
- }
-
- public int getClazz()
- {
- return clazz;
- }
-
-
- public boolean isUnique()
- {
- return unique;
- }
-
- /**
- * Overriden, to return a value which is consistent with the value returned
- * by equals(Object).
- */
- @Override
- public int hashCode()
- {
- return name.hashCode() + type + clazz;
- }
-
- /**
- * Get a string given a clazz.
- */
- static String getClazz(int clazz)
- {
- switch (clazz & DNSConstants.CLASS_MASK)
- {
- case DNSConstants.CLASS_IN:
- return "in";
- case DNSConstants.CLASS_CS:
- return "cs";
- case DNSConstants.CLASS_CH:
- return "ch";
- case DNSConstants.CLASS_HS:
- return "hs";
- case DNSConstants.CLASS_NONE:
- return "none";
- case DNSConstants.CLASS_ANY:
- return "any";
- default:
- return "?";
- }
- }
-
- /**
- * Get a string given a type.
- */
- static String getType(int type)
- {
- switch (type)
- {
- case DNSConstants.TYPE_A:
- return "a";
- case DNSConstants.TYPE_AAAA:
- return "aaaa";
- case DNSConstants.TYPE_NS:
- return "ns";
- case DNSConstants.TYPE_MD:
- return "md";
- case DNSConstants.TYPE_MF:
- return "mf";
- case DNSConstants.TYPE_CNAME:
- return "cname";
- case DNSConstants.TYPE_SOA:
- return "soa";
- case DNSConstants.TYPE_MB:
- return "mb";
- case DNSConstants.TYPE_MG:
- return "mg";
- case DNSConstants.TYPE_MR:
- return "mr";
- case DNSConstants.TYPE_NULL:
- return "null";
- case DNSConstants.TYPE_WKS:
- return "wks";
- case DNSConstants.TYPE_PTR:
- return "ptr";
- case DNSConstants.TYPE_HINFO:
- return "hinfo";
- case DNSConstants.TYPE_MINFO:
- return "minfo";
- case DNSConstants.TYPE_MX:
- return "mx";
- case DNSConstants.TYPE_TXT:
- return "txt";
- case DNSConstants.TYPE_SRV:
- return "srv";
- case DNSConstants.TYPE_ANY:
- return "any";
- default:
- return "?";
- }
- }
-
- public String toString(String hdr, String other)
- {
- return hdr + "[" + getType(type) + "," +
- getClazz(clazz) + (unique ? "-unique," : ",") +
- name + ((other != null) ? "," +
- other + "]" : "]");
- }
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/DNSIncoming.java b/src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/DNSIncoming.java
deleted file mode 100644
index 3dcedc4..0000000
--- a/src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/DNSIncoming.java
+++ /dev/null
@@ -1,524 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright 2003-2005 Arthur van Hoff Rick Blair
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.zeroconf.jmdns;
-
-import java.io.*;
-import java.net.*;
-import java.util.*;
-import java.util.logging.*;
-
-/**
- * Parse an incoming DNS message into its components.
- *
- * @version %I%, %G%
- * @author Arthur van Hoff, Werner Randelshofer, Pierre Frisch, Daniel Bobbert
- */
-final class DNSIncoming
-{
- private static Logger logger = Logger.getLogger(DNSIncoming.class.toString());
- // Implementation note: This vector should be immutable.
- // If a client of DNSIncoming changes the contents of this vector,
- // we get undesired results. To fix this, we have to migrate to
- // the Collections API of Java 1.2. i.e we replace Vector by List.
- // final static Vector EMPTY = new Vector();
-
- private DatagramPacket packet;
- private int off;
- private int len;
- private byte data[];
-
- int id;
- private int flags;
- private int numQuestions;
- int numAnswers;
- private int numAuthorities;
- private int numAdditionals;
- private long receivedTime;
-
- List<DNSEntry> questions;
- List<DNSRecord> answers;
-
- /**
- * Parse a message from a datagram packet.
- */
- DNSIncoming(DatagramPacket packet) throws IOException
- {
- String SLevel = System.getProperty("jmdns.debug");
- if (SLevel == null) SLevel = "INFO";
- logger.setLevel(Level.parse(SLevel));
-
- this.packet = packet;
- this.data = packet.getData();
- this.len = packet.getLength();
- this.off = packet.getOffset();
- this.questions = new LinkedList<DNSEntry>();
- this.answers = new LinkedList<DNSRecord>();
- this.receivedTime = System.currentTimeMillis();
-
- try
- {
- id = readUnsignedShort();
- flags = readUnsignedShort();
- numQuestions = readUnsignedShort();
- numAnswers = readUnsignedShort();
- numAuthorities = readUnsignedShort();
- numAdditionals = readUnsignedShort();
-
- // parse questions
- if (numQuestions > 0)
- {
- questions =
- Collections.synchronizedList(
- new ArrayList<DNSEntry>(numQuestions));
- for (int i = 0; i < numQuestions; i++)
- {
- DNSQuestion question =
- new DNSQuestion(
- readName(),
- readUnsignedShort(),
- readUnsignedShort());
-
- questions.add(question);
- }
- }
-
- // parse answers
- int n = numAnswers + numAuthorities + numAdditionals;
- if (n > 0)
- {
- //System.out.println("JMDNS received "+n+" answers!");
- answers = Collections.synchronizedList(
- new ArrayList<DNSRecord>(n));
- for (int i = 0; i < n; i++)
- {
- String domain = readName();
- int type = readUnsignedShort();
- int clazz = readUnsignedShort();
- int ttl = readInt();
- int len = readUnsignedShort();
- int end = off + len;
- DNSRecord rec = null;
-
- switch (type)
- {
- case DNSConstants.TYPE_A: // IPv4
- case DNSConstants.TYPE_AAAA: // IPv6 FIXME [PJYF Oct 14 2004] This has not been tested
- rec = new DNSRecord.Address(
- domain, type, clazz, ttl, readBytes(off, len));
- break;
- case DNSConstants.TYPE_CNAME:
- case DNSConstants.TYPE_PTR:
- rec = new DNSRecord.Pointer(
- domain, type, clazz, ttl, readName());
- break;
- case DNSConstants.TYPE_TXT:
- rec = new DNSRecord.Text(
- domain, type, clazz, ttl, readBytes(off, len));
- break;
- case DNSConstants.TYPE_SRV:
- //System.out.println("JMDNS: One is a SRV field!!");
- rec = new DNSRecord.Service( domain,
- type,
- clazz,
- ttl,
- readUnsignedShort(),
- readUnsignedShort(),
- readUnsignedShort(),
- readName());
- break;
- case DNSConstants.TYPE_HINFO:
- // Maybe we should do something with those
- break;
- default :
- logger.finer("DNSIncoming() unknown type:" + type);
- break;
- }
-
- if (rec != null)
- {
- // Add a record, if we were able to create one.
- answers.add(rec);
- }
- else
- {
- // Addjust the numbers for the skipped record
- if (answers.size() < numAnswers)
- {
- numAnswers--;
- }
- else
- {
- if (answers.size() < numAnswers + numAuthorities)
- {
- numAuthorities--;
- }
- else
- {
- if (answers.size() < numAnswers +
- numAuthorities +
- numAdditionals)
- {
- numAdditionals--;
- }
- }
- }
- }
- off = end;
- }
- }
- }
- catch (IOException e)
- {
- logger.log(Level.WARNING,
- "DNSIncoming() dump " + print(true) + "\n exception ", e);
- throw e;
- }
- }
-
- /**
- * Check if the message is a query.
- */
- boolean isQuery()
- {
- return (flags & DNSConstants.FLAGS_QR_MASK) ==
- DNSConstants.FLAGS_QR_QUERY;
- }
-
- /**
- * Check if the message is truncated.
- */
- boolean isTruncated()
- {
- return (flags & DNSConstants.FLAGS_TC) != 0;
- }
-
- /**
- * Check if the message is a response.
- */
- boolean isResponse()
- {
- return (flags & DNSConstants.FLAGS_QR_MASK) ==
- DNSConstants.FLAGS_QR_RESPONSE;
- }
-
- private int get(int off) throws IOException
- {
- if ((off < 0) || (off >= len))
- {
- throw new IOException("parser error: offset=" + off);
- }
- return data[off] & 0xFF;
- }
-
- private int readUnsignedShort() throws IOException
- {
- return (get(off++) << 8) + get(off++);
- }
-
- private int readInt() throws IOException
- {
- return (readUnsignedShort() << 16) + readUnsignedShort();
- }
-
- private byte[] readBytes(int off, int len) throws IOException
- {
- byte bytes[] = new byte[len];
- System.arraycopy(data, off, bytes, 0, len);
- return bytes;
- }
-
- private void readUTF(StringBuffer buf, int off, int len) throws IOException
- {
- for (int end = off + len; off < end;)
- {
- int ch = get(off++);
- switch (ch >> 4)
- {
- case 0:
- case 1:
- case 2:
- case 3:
- case 4:
- case 5:
- case 6:
- case 7:
- // 0xxxxxxx
- break;
- case 12:
- case 13:
- // 110x xxxx 10xx xxxx
- ch = ((ch & 0x1F) << 6) | (get(off++) & 0x3F);
- break;
- case 14:
- // 1110 xxxx 10xx xxxx 10xx xxxx
- ch = ((ch & 0x0f) << 12) |
- ((get(off++) & 0x3F) << 6) |
- (get(off++) & 0x3F);
- break;
- default:
- // 10xx xxxx, 1111 xxxx
- ch = ((ch & 0x3F) << 4) | (get(off++) & 0x0f);
- break;
- }
- buf.append((char) ch);
- }
- }
-
- private String readName() throws IOException
- {
- StringBuffer buf = new StringBuffer();
- int off = this.off;
- int next = -1;
- int first = off;
-
- while (true)
- {
- int len = get(off++);
- if (len == 0)
- {
- break;
- }
- switch (len & 0xC0)
- {
- case 0x00:
- //buf.append("[" + off + "]");
- readUTF(buf, off, len);
- off += len;
- buf.append('.');
- break;
- case 0xC0:
- //buf.append("<" + (off - 1) + ">");
- if (next < 0)
- {
- next = off + 1;
- }
- off = ((len & 0x3F) << 8) | get(off++);
- if (off >= first)
- {
- throw new IOException(
- "bad domain name: possible circular name detected");
- }
- first = off;
- break;
- default:
- throw new IOException(
- "bad domain name: '" + buf + "' at " + off);
- }
- }
- this.off = (next >= 0) ? next : off;
- return buf.toString();
- }
-
- /**
- * Debugging.
- */
- String print(boolean dump)
- {
- StringBuffer buf = new StringBuffer();
- buf.append(toString() + "\n");
- for (Iterator<DNSEntry> iterator = questions.iterator();
- iterator.hasNext();)
- {
- buf.append(" ques:" + iterator.next() + "\n");
- }
- int count = 0;
- for (Iterator<DNSRecord> iterator = answers.iterator();
- iterator.hasNext();
- count++)
- {
- if (count < numAnswers)
- {
- buf.append(" answ:");
- }
- else
- {
- if (count < numAnswers + numAuthorities)
- {
- buf.append(" auth:");
- }
- else
- {
- buf.append(" addi:");
- }
- }
- buf.append(iterator.next() + "\n");
- }
- if (dump)
- {
- for (int off = 0, len = packet.getLength(); off < len; off += 32)
- {
- int n = Math.min(32, len - off);
- if (off < 10)
- {
- buf.append(' ');
- }
- if (off < 100)
- {
- buf.append(' ');
- }
- buf.append(off);
- buf.append(':');
- for (int i = 0; i < n; i++)
- {
- if ((i % 8) == 0)
- {
- buf.append(' ');
- }
- buf.append(Integer.toHexString((data[off + i] & 0xF0) >> 4));
- buf.append(Integer.toHexString((data[off + i] & 0x0F) >> 0));
- }
- buf.append("\n");
- buf.append(" ");
- for (int i = 0; i < n; i++)
- {
- if ((i % 8) == 0)
- {
- buf.append(' ');
- }
- buf.append(' ');
- int ch = data[off + i] & 0xFF;
- buf.append(((ch > ' ') && (ch < 127)) ? (char) ch : '.');
- }
- buf.append("\n");
-
- // limit message size
- if (off + 32 >= 256)
- {
- buf.append("....\n");
- break;
- }
- }
- }
- return buf.toString();
- }
-
- @Override
- public String toString()
- {
- StringBuffer buf = new StringBuffer();
- buf.append(isQuery() ? "dns[query," : "dns[response,");
- if (packet.getAddress() != null)
- {
- buf.append(packet.getAddress().getHostAddress());
- }
- buf.append(':');
- buf.append(packet.getPort());
- buf.append(",len=");
- buf.append(packet.getLength());
- buf.append(",id=0x");
- buf.append(Integer.toHexString(id));
- if (flags != 0)
- {
- buf.append(",flags=0x");
- buf.append(Integer.toHexString(flags));
- if ((flags & DNSConstants.FLAGS_QR_RESPONSE) != 0)
- {
- buf.append(":r");
- }
- if ((flags & DNSConstants.FLAGS_AA) != 0)
- {
- buf.append(":aa");
- }
- if ((flags & DNSConstants.FLAGS_TC) != 0)
- {
- buf.append(":tc");
- }
- }
- if (numQuestions > 0)
- {
- buf.append(",questions=");
- buf.append(numQuestions);
- }
- if (numAnswers > 0)
- {
- buf.append(",answers=");
- buf.append(numAnswers);
- }
- if (numAuthorities > 0)
- {
- buf.append(",authorities=");
- buf.append(numAuthorities);
- }
- if (numAdditionals > 0)
- {
- buf.append(",additionals=");
- buf.append(numAdditionals);
- }
- buf.append("]");
- return buf.toString();
- }
-
- /**
- * Appends answers to this Incoming.
- *
- * @throws IllegalArgumentException If not a query or if Truncated.
- */
- void append(DNSIncoming that)
- {
- if (this.isQuery() && this.isTruncated() && that.isQuery())
- {
- if (that.numQuestions > 0) {
- if (Collections.EMPTY_LIST.equals(this.questions))
- this.questions =
- Collections.synchronizedList(
- new ArrayList<DNSEntry>(that.numQuestions));
-
- this.questions.addAll(that.questions);
- this.numQuestions += that.numQuestions;
- }
-
- if (Collections.EMPTY_LIST.equals(answers))
- {
- answers = Collections.synchronizedList(
- new ArrayList<DNSRecord>());
- }
-
- if (that.numAnswers > 0)
- {
- this.answers.addAll(this.numAnswers,
- that.answers.subList(0, that.numAnswers));
- this.numAnswers += that.numAnswers;
- }
- if (that.numAuthorities > 0)
- {
- this.answers.addAll(this.numAnswers + this.numAuthorities,
- that.answers.subList(
- that.numAnswers,
- that.numAnswers + that.numAuthorities));
- this.numAuthorities += that.numAuthorities;
- }
- if (that.numAdditionals > 0)
- {
- this.answers.addAll(
- that.answers.subList(
- that.numAnswers + that.numAuthorities,
- that.numAnswers + that.numAuthorities + that.numAdditionals));
- this.numAdditionals += that.numAdditionals;
- }
- }
- else
- {
- throw new IllegalArgumentException();
- }
- }
-
- int elapseSinceArrival()
- {
- return (int) (System.currentTimeMillis() - receivedTime);
- }
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/DNSListener.java b/src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/DNSListener.java
deleted file mode 100644
index d317953..0000000
--- a/src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/DNSListener.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright 2003-2005 Arthur van Hoff Rick Blair
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.zeroconf.jmdns;
-
-// REMIND: Listener should follow Java idiom for listener or have a different
-// name.
-
-/**
- * DNSListener.
- * Listener for record updates.
- *
- * @author Werner Randelshofer, Rick Blair
- * @version 1.0 May 22, 2004 Created.
- */
-public interface DNSListener
-{
- /**
- * Update a DNS record.
- * @param jmdns
- * @param now
- * @param record
- */
- public void updateRecord(JmDNS jmdns, long now, DNSRecord record);
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/DNSOutgoing.java b/src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/DNSOutgoing.java
deleted file mode 100644
index 4d099b8..0000000
--- a/src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/DNSOutgoing.java
+++ /dev/null
@@ -1,405 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright 2003-2005 Arthur van Hoff Rick Blair
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.zeroconf.jmdns;
-
-import java.io.*;
-import java.util.*;
-import java.util.logging.*;
-
-/**
- * An outgoing DNS message.
- *
- * @version %I%, %G%
- * @author Arthur van Hoff, Rick Blair, Werner Randelshofer
- */
-final class DNSOutgoing
-{
- private static Logger logger =
- Logger.getLogger(DNSOutgoing.class.toString());
-
- int id;
- int flags;
- private boolean multicast;
- private int numQuestions;
- private int numAnswers;
- private int numAuthorities;
- private int numAdditionals;
- private Hashtable<String, Integer> names;
-
- byte data[];
- int off;
- int len;
-
- /**
- * Create an outgoing multicast query or response.
- */
- DNSOutgoing(int flags)
- {
- this(flags, true);
-
- }
-
- /**
- * Create an outgoing query or response.
- */
- DNSOutgoing(int flags, boolean multicast)
- {
- String SLevel = System.getProperty("jmdns.debug");
- if (SLevel == null) SLevel = "INFO";
- logger.setLevel(Level.parse(SLevel));
-
- this.flags = flags;
- this.multicast = multicast;
- names = new Hashtable<String, Integer>();
- data = new byte[DNSConstants.MAX_MSG_TYPICAL];
- off = 12;
- }
-
- /**
- * Add a question to the message.
- */
- void addQuestion(DNSQuestion rec) throws IOException
- {
- if (numAnswers > 0 || numAuthorities > 0 || numAdditionals > 0)
- {
- throw new IllegalStateException("Questions must be added before answers");
- }
- numQuestions++;
- writeQuestion(rec);
- }
-
- /**
- * Add an answer if it is not suppressed.
- */
- void addAnswer(DNSIncoming in, DNSRecord rec) throws IOException
- {
- if (numAuthorities > 0 || numAdditionals > 0)
- {
- throw new IllegalStateException(
- "Answers must be added before authorities and additionals");
- }
- if (!rec.suppressedBy(in))
- {
- addAnswer(rec, 0);
- }
- }
-
- /**
- * Add an additional answer to the record. Omit if there is no room.
- */
- void addAdditionalAnswer(DNSIncoming in, DNSRecord rec) throws IOException
- {
- if ((off < DNSConstants.MAX_MSG_TYPICAL - 200) && !rec.suppressedBy(in))
- {
- writeRecord(rec, 0);
- numAdditionals++;
- }
- }
-
- /**
- * Add an answer to the message.
- */
- void addAnswer(DNSRecord rec, long now) throws IOException
- {
- if (numAuthorities > 0 || numAdditionals > 0)
- {
- throw new IllegalStateException(
- "Questions must be added before answers");
- }
- if (rec != null)
- {
- if ((now == 0) || !rec.isExpired(now))
- {
- writeRecord(rec, now);
- numAnswers++;
- }
- }
- }
-
- private LinkedList<DNSRecord> authorativeAnswers = new LinkedList<DNSRecord>();
-
- /**
- * Add an authorative answer to the message.
- */
- void addAuthorativeAnswer(DNSRecord rec) throws IOException
- {
- if (numAdditionals > 0)
- {
- throw new IllegalStateException(
- "Authorative answers must be added before additional answers");
- }
- authorativeAnswers.add(rec);
- writeRecord(rec, 0);
- numAuthorities++;
-
- // VERIFY:
-
- }
-
- void writeByte(int value) throws IOException
- {
- if (off >= data.length)
- {
- throw new IOException("buffer full");
- }
- data[off++] = (byte) value;
- }
-
- void writeBytes(String str, int off, int len) throws IOException
- {
- for (int i = 0; i < len; i++)
- {
- writeByte(str.charAt(off + i));
- }
- }
-
- void writeBytes(byte data[]) throws IOException
- {
- if (data != null)
- {
- writeBytes(data, 0, data.length);
- }
- }
-
- void writeBytes(byte data[], int off, int len) throws IOException
- {
- for (int i = 0; i < len; i++)
- {
- writeByte(data[off + i]);
- }
- }
-
- void writeShort(int value) throws IOException
- {
- writeByte(value >> 8);
- writeByte(value);
- }
-
- void writeInt(int value) throws IOException
- {
- writeShort(value >> 16);
- writeShort(value);
- }
-
- void writeUTF(String str, int off, int len) throws IOException
- {
- // compute utf length
- int utflen = 0;
- for (int i = 0; i < len; i++)
- {
- int ch = str.charAt(off + i);
- if ((ch >= 0x0001) && (ch <= 0x007F))
- {
- utflen += 1;
- }
- else
- {
- if (ch > 0x07FF)
- {
- utflen += 3;
- }
- else
- {
- utflen += 2;
- }
- }
- }
- // write utf length
- writeByte(utflen);
- // write utf data
- for (int i = 0; i < len; i++)
- {
- int ch = str.charAt(off + i);
- if ((ch >= 0x0001) && (ch <= 0x007F))
- {
- writeByte(ch);
- }
- else
- {
- if (ch > 0x07FF)
- {
- writeByte(0xE0 | ((ch >> 12) & 0x0F));
- writeByte(0x80 | ((ch >> 6) & 0x3F));
- writeByte(0x80 | ((ch >> 0) & 0x3F));
- }
- else
- {
- writeByte(0xC0 | ((ch >> 6) & 0x1F));
- writeByte(0x80 | ((ch >> 0) & 0x3F));
- }
- }
- }
- }
-
- void writeName(String name) throws IOException
- {
- while (true)
- {
- int n = name.indexOf('.');
- if (n < 0)
- {
- n = name.length();
- }
- if (n <= 0)
- {
- writeByte(0);
- return;
- }
- Integer offset = names.get(name);
- if (offset != null)
- {
- int val = offset.intValue();
-
- if (val > off)
- {
- logger.log(Level.WARNING,
- "DNSOutgoing writeName failed val=" + val + " name=" + name);
- }
-
- writeByte((val >> 8) | 0xC0);
- writeByte(val);
- return;
- }
- names.put(name, off);
- writeUTF(name, 0, n);
- name = name.substring(n);
- if (name.startsWith("."))
- {
- name = name.substring(1);
- }
- }
- }
-
- void writeQuestion(DNSQuestion question) throws IOException
- {
- writeName(question.name);
- writeShort(question.type);
- writeShort(question.clazz);
- }
-
- void writeRecord(DNSRecord rec, long now) throws IOException
- {
- int save = off;
- try
- {
- writeName(rec.name);
- writeShort(rec.type);
- writeShort(rec.clazz |
- ((rec.unique && multicast) ? DNSConstants.CLASS_UNIQUE : 0));
- writeInt((now == 0) ? rec.ttl : rec.getRemainingTTL(now));
- writeShort(0);
- int start = off;
- rec.write(this);
- int len = off - start;
- data[start - 2] = (byte) (len >> 8);
- data[start - 1] = (byte) (len & 0xFF);
- }
- catch (IOException e)
- {
- off = save;
- throw e;
- }
- }
-
- /**
- * Finish the message before sending it off.
- */
- void finish() throws IOException
- {
- int save = off;
- off = 0;
-
- writeShort(multicast ? 0 : id);
- writeShort(flags);
- writeShort(numQuestions);
- writeShort(numAnswers);
- writeShort(numAuthorities);
- writeShort(numAdditionals);
- off = save;
- }
-
- boolean isQuery()
- {
- return (flags & DNSConstants.FLAGS_QR_MASK) ==
- DNSConstants.FLAGS_QR_QUERY;
- }
-
- public boolean isEmpty()
- {
- return numQuestions == 0 && numAuthorities == 0
- && numAdditionals == 0 && numAnswers == 0;
- }
-
-
- @Override
- public String toString()
- {
- StringBuffer buf = new StringBuffer();
- buf.append(isQuery() ? "dns[query," : "dns[response,");
- //buf.append(packet.getAddress().getHostAddress());
- buf.append(':');
- //buf.append(packet.getPort());
- //buf.append(",len=");
- //buf.append(packet.getLength());
- buf.append(",id=0x");
- buf.append(Integer.toHexString(id));
- if (flags != 0)
- {
- buf.append(",flags=0x");
- buf.append(Integer.toHexString(flags));
- if ((flags & DNSConstants.FLAGS_QR_RESPONSE) != 0)
- {
- buf.append(":r");
- }
- if ((flags & DNSConstants.FLAGS_AA) != 0)
- {
- buf.append(":aa");
- }
- if ((flags & DNSConstants.FLAGS_TC) != 0)
- {
- buf.append(":tc");
- }
- }
- if (numQuestions > 0)
- {
- buf.append(",questions=");
- buf.append(numQuestions);
- }
- if (numAnswers > 0)
- {
- buf.append(",answers=");
- buf.append(numAnswers);
- }
- if (numAuthorities > 0)
- {
- buf.append(",authorities=");
- buf.append(numAuthorities);
- }
- if (numAdditionals > 0)
- {
- buf.append(",additionals=");
- buf.append(numAdditionals);
- }
- buf.append(",\nnames=" + names);
- buf.append(",\nauthorativeAnswers=" + authorativeAnswers);
-
- buf.append("]");
- return buf.toString();
- }
-
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/DNSQuestion.java b/src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/DNSQuestion.java
deleted file mode 100644
index f6abaa7..0000000
--- a/src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/DNSQuestion.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright 2003-2005 Arthur van Hoff Rick Blair
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.zeroconf.jmdns;
-
-import java.util.logging.*;
-
-/**
- * A DNS question.
- *
- * @version %I%, %G%
- * @author Arthur van Hoff
- */
-public final class DNSQuestion
- extends DNSEntry
-{
- private static Logger logger =
- Logger.getLogger(DNSQuestion.class.toString());
-
- /**
- * Create a question.
- * @param name
- * @param type
- * @param clazz
- */
- public DNSQuestion(String name, int type, int clazz)
- {
- super(name, type, clazz);
-
- String SLevel = System.getProperty("jmdns.debug");
- if (SLevel == null) SLevel = "INFO";
- logger.setLevel(Level.parse(SLevel));
- }
-
- /**
- * Check if this question is answered by a given DNS record.
- */
- boolean answeredBy(DNSRecord rec)
- {
- return (clazz == rec.clazz) &&
- ((type == rec.type) ||
- (type == DNSConstants.TYPE_ANY)) &&
- name.equals(rec.name);
- }
-
- /**
- * For debugging only.
- */
- @Override
- public String toString()
- {
- return toString("question", null);
- }
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/DNSRecord.java b/src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/DNSRecord.java
deleted file mode 100644
index 673bbc4..0000000
--- a/src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/DNSRecord.java
+++ /dev/null
@@ -1,796 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright 2003-2005 Arthur van Hoff Rick Blair
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.zeroconf.jmdns;
-
-import java.io.*;
-import java.net.*;
-import java.util.logging.*;
-
-/**
- * DNS record
- *
- * @version %I%, %G%
- * @author Arthur van Hoff, Rick Blair, Werner Randelshofer, Pierre Frisch
- */
-public abstract class DNSRecord extends DNSEntry
-{
- private static Logger logger =
- Logger.getLogger(DNSRecord.class.toString());
- int ttl;
- private long created;
-
- /**
- * Create a DNSRecord with a name, type, clazz, and ttl.
- */
- DNSRecord(String name, int type, int clazz, int ttl)
- {
- super(name, type, clazz);
- this.ttl = ttl;
- this.created = System.currentTimeMillis();
-
- String SLevel = System.getProperty("jmdns.debug");
- if (SLevel == null) SLevel = "INFO";
- logger.setLevel(Level.parse(SLevel));
- }
-
- /**
- * True if this record is the same as some other record.
- * @param other obj to be compared to.
- */
- @Override
- public boolean equals(Object other)
- {
- return (other instanceof DNSRecord) && sameAs((DNSRecord) other);
- }
-
- /**
- * True if this record is the same as some other record.
- */
- boolean sameAs(DNSRecord other)
- {
- return super.equals(other) && sameValue(other);
- }
-
- /**
- * True if this record has the same value as some other record.
- */
- abstract boolean sameValue(DNSRecord other);
-
- /**
- * True if this record has the same type as some other record.
- */
- boolean sameType(DNSRecord other)
- {
- return type == other.type;
- }
-
- /**
- * Handles a query represented by this record.
- *
- * @return Returns true if a conflict with one of the services registered
- * with JmDNS or with the hostname occured.
- */
- abstract boolean handleQuery(JmDNS dns, long expirationTime);
-
- /**
- * Handles a responserepresented by this record.
- *
- * @return Returns true if a conflict with one of the services registered
- * with JmDNS or with the hostname occured.
- */
- abstract boolean handleResponse(JmDNS dns);
-
- /**
- * Adds this as an answer to the provided outgoing datagram.
- */
- abstract DNSOutgoing addAnswer(JmDNS dns, DNSIncoming in, InetAddress addr,
- int port, DNSOutgoing out)
- throws IOException;
-
- /**
- * True if this record is suppressed by the answers in a message.
- */
- boolean suppressedBy(DNSIncoming msg)
- {
- try
- {
- for (int i = msg.numAnswers; i-- > 0;)
- {
- if (suppressedBy(msg.answers.get(i)))
- {
- return true;
- }
- }
- return false;
- }
- catch (ArrayIndexOutOfBoundsException e)
- {
- logger.log(Level.WARNING,
- "suppressedBy() message " + msg + " exception ", e);
- // msg.print(true);
- return false;
- }
- }
-
- /**
- * True if this record would be supressed by an answer.
- * This is the case if this record would not have a
- * significantly longer TTL.
- */
- boolean suppressedBy(DNSRecord other)
- {
- if (sameAs(other) && (other.ttl > ttl / 2))
- {
- return true;
- }
- return false;
- }
-
- /**
- * Get the expiration time of this record.
- */
- long getExpirationTime(int percent)
- {
- return created + (percent * ttl * 10L);
- }
-
- /**
- * Get the remaining TTL for this record.
- */
- int getRemainingTTL(long now)
- {
- return (int) Math.max(0, (getExpirationTime(100) - now) / 1000);
- }
-
- /**
- * Check if the record is expired.
- */
- boolean isExpired(long now)
- {
- return getExpirationTime(100) <= now;
- }
-
- /**
- * Check if the record is stale, ie it has outlived
- * more than half of its TTL.
- */
- boolean isStale(long now)
- {
- return getExpirationTime(50) <= now;
- }
-
- /**
- * Reset the TTL of a record. This avoids having to
- * update the entire record in the cache.
- */
- void resetTTL(DNSRecord other)
- {
- created = other.created;
- ttl = other.ttl;
- }
-
- /**
- * Write this record into an outgoing message.
- */
- abstract void write(DNSOutgoing out) throws IOException;
-
- /**
- * Address record.
- */
- static class Address extends DNSRecord
- {
- private static Logger logger =
- Logger.getLogger(Address.class.toString());
- InetAddress addr;
-
- Address(String name, int type, int clazz, int ttl, InetAddress addr)
- {
- super(name, type, clazz, ttl);
- this.addr = addr;
-
- String SLevel = System.getProperty("jmdns.debug");
- if (SLevel == null) SLevel = "INFO";
- logger.setLevel(Level.parse(SLevel));
- }
-
- Address(String name, int type, int clazz, int ttl, byte[] rawAddress)
- {
- super(name, type, clazz, ttl);
- try
- {
- this.addr = InetAddress.getByAddress(rawAddress);
- }
- catch (UnknownHostException exception)
- {
- logger.log(Level.WARNING, "Address() exception ", exception);
- }
- }
-
- @Override
- void write(DNSOutgoing out) throws IOException
- {
- if (addr != null)
- {
- byte[] buffer = addr.getAddress();
- if (DNSConstants.TYPE_A == type)
- {
- // If we have a type A records we should
- // answer with a IPv4 address
- if (addr instanceof Inet4Address)
- {
- // All is good
- }
- else
- {
- // Get the last four bytes
- byte[] tempbuffer = buffer;
- buffer = new byte[4];
- System.arraycopy(tempbuffer, 12, buffer, 0, 4);
- }
- }
- else
- {
- // If we have a type AAAA records we should
- // answer with a IPv6 address
- if (addr instanceof Inet4Address)
- {
- byte[] tempbuffer = buffer;
- buffer = new byte[16];
- for (int i = 0; i < 16; i++)
- {
- if (i < 11)
- {
- buffer[i] = tempbuffer[i - 12];
- }
- else
- {
- buffer[i] = 0;
- }
- }
- }
- }
- int length = buffer.length;
- out.writeBytes(buffer, 0, length);
- }
- }
-
- boolean same(DNSRecord other)
- {
- return ((sameName(other)) && ((sameValue(other))));
- }
-
- boolean sameName(DNSRecord other)
- {
- return name.equalsIgnoreCase(((Address) other).name);
- }
-
- @Override
- boolean sameValue(DNSRecord other)
- {
- return addr.equals(((Address) other).getAddress());
- }
-
- InetAddress getAddress()
- {
- return addr;
- }
-
- /**
- * Creates a byte array representation of this record.
- * This is needed for tie-break tests according to
- * draft-cheshire-dnsext-multicastdns-04.txt chapter 9.2.
- */
- private byte[] toByteArray()
- {
- try
- {
- ByteArrayOutputStream bout = new ByteArrayOutputStream();
- DataOutputStream dout = new DataOutputStream(bout);
- dout.write(name.getBytes("UTF8"));
- dout.writeShort(type);
- dout.writeShort(clazz);
- //dout.writeInt(len);
- byte[] buffer = addr.getAddress();
- for (int i = 0; i < buffer.length; i++)
- {
- dout.writeByte(buffer[i]);
- }
- dout.close();
- return bout.toByteArray();
- }
- catch (IOException e)
- {
- throw new InternalError();
- }
- }
-
- /**
- * Does a lexicographic comparison of the byte array representation
- * of this record and that record.
- * This is needed for tie-break tests according to
- * draft-cheshire-dnsext-multicastdns-04.txt chapter 9.2.
- */
- private int lexCompare(DNSRecord.Address that)
- {
- byte[] thisBytes = this.toByteArray();
- byte[] thatBytes = that.toByteArray();
- for ( int i = 0, n = Math.min(thisBytes.length, thatBytes.length);
- i < n;
- i++)
- {
- if (thisBytes[i] > thatBytes[i])
- {
- return 1;
- }
- else
- {
- if (thisBytes[i] < thatBytes[i])
- {
- return -1;
- }
- }
- }
- return thisBytes.length - thatBytes.length;
- }
-
- /**
- * Does the necessary actions, when this as a query.
- */
- @Override
- boolean handleQuery(JmDNS dns, long expirationTime)
- {
- DNSRecord.Address dnsAddress =
- dns.getLocalHost().getDNSAddressRecord(this);
- if (dnsAddress != null)
- {
- if (dnsAddress.sameType(this) &&
- dnsAddress.sameName(this) &&
- (!dnsAddress.sameValue(this)))
- {
- logger.finer(
- "handleQuery() Conflicting probe detected. dns state " +
- dns.getState() +
- " lex compare " + lexCompare(dnsAddress));
- // Tie-breaker test
- if (dns.getState().isProbing() && lexCompare(dnsAddress) >= 0)
- {
- // We lost the tie-break. We have to choose a different name.
- dns.getLocalHost().incrementHostName();
- dns.getCache().clear();
- for (ServiceInfo info : dns.services.values())
- info.revertState();
- }
- dns.revertState();
- return true;
- }
- }
- return false;
- }
-
- /**
- * Does the necessary actions, when this as a response.
- */
- @Override
- boolean handleResponse(JmDNS dns)
- {
- DNSRecord.Address dnsAddress =
- dns.getLocalHost().getDNSAddressRecord(this);
- if (dnsAddress != null)
- {
- if (dnsAddress.sameType(this) &&
- dnsAddress.sameName(this) &&
- (!dnsAddress.sameValue(this)))
- {
- logger.finer("handleResponse() Denial detected");
-
- if (dns.getState().isProbing())
- {
- dns.getLocalHost().incrementHostName();
- dns.getCache().clear();
- for (ServiceInfo info : dns.services.values())
- info.revertState();
- }
- dns.revertState();
- return true;
- }
- }
- return false;
- }
-
- @Override
- DNSOutgoing addAnswer(JmDNS dns,
- DNSIncoming in,
- InetAddress addr,
- int port,
- DNSOutgoing out)
- throws IOException
- {
- return out;
- }
-
- @Override
- public String toString()
- {
- return toString(" address '" +
- (addr != null ? addr.getHostAddress() : "null") + "'");
- }
-
- }
-
- /**
- * Pointer record.
- */
- static class Pointer extends DNSRecord
- {
- private static Logger logger =
- Logger.getLogger(Pointer.class.toString());
- String alias;
-
- Pointer(String name, int type, int clazz, int ttl, String alias)
- {
- super(name, type, clazz, ttl);
- this.alias = alias;
-
- String SLevel = System.getProperty("jmdns.debug");
- if (SLevel == null) SLevel = "INFO";
- logger.setLevel(Level.parse(SLevel));
- }
-
- @Override
- void write(DNSOutgoing out) throws IOException
- {
- out.writeName(alias);
- }
-
- @Override
- boolean sameValue(DNSRecord other)
- {
- return alias.equals(((Pointer) other).alias);
- }
-
- @Override
- boolean handleQuery(JmDNS dns, long expirationTime)
- {
- // Nothing to do (?)
- // I think there is no possibility
- // for conflicts for this record type?
- return false;
- }
-
- @Override
- boolean handleResponse(JmDNS dns)
- {
- // Nothing to do (?)
- // I think there is no possibility for conflicts for this record type?
- return false;
- }
-
- String getAlias()
- {
- return alias;
- }
-
- @Override
- DNSOutgoing addAnswer(JmDNS dns,
- DNSIncoming in,
- InetAddress addr,
- int port,
- DNSOutgoing out)
- throws IOException
- {
- return out;
- }
-
- @Override
- public String toString()
- {
- return toString(alias);
- }
- }
-
- static class Text extends DNSRecord
- {
- private static Logger logger =
- Logger.getLogger(Text.class.toString());
- byte text[];
-
- Text(String name, int type, int clazz, int ttl, byte text[])
- {
- super(name, type, clazz, ttl);
- this.text = text;
-
- String SLevel = System.getProperty("jmdns.debug");
- if (SLevel == null) SLevel = "INFO";
- logger.setLevel(Level.parse(SLevel));
- }
-
- @Override
- void write(DNSOutgoing out) throws IOException
- {
- out.writeBytes(text, 0, text.length);
- }
-
- @Override
- boolean sameValue(DNSRecord other)
- {
- Text txt = (Text) other;
- if (txt.text.length != text.length)
- {
- return false;
- }
- for (int i = text.length; i-- > 0;)
- {
- if (txt.text[i] != text[i])
- {
- return false;
- }
- }
- return true;
- }
-
- @Override
- boolean handleQuery(JmDNS dns, long expirationTime)
- {
- // Nothing to do (?)
- // I think there is no possibility for conflicts for this record type?
- return false;
- }
-
- @Override
- boolean handleResponse(JmDNS dns)
- {
- // Nothing to do (?)
- // Shouldn't we care if we get a conflict at this level?
- /*
- ServiceInfo info = (ServiceInfo) dns.services.get(name.toLowerCase());
- if (info != null)
- {
- if (! Arrays.equals(text,info.text))
- {
- info.revertState();
- return true;
- }
- }
- */
- return false;
- }
-
- @Override
- DNSOutgoing addAnswer(JmDNS dns,
- DNSIncoming in,
- InetAddress addr,
- int port,
- DNSOutgoing out)
- throws IOException
- {
- return out;
- }
-
- @Override
- public String toString()
- {
- return toString((text.length > 10) ?
- new String(text, 0, 7) + "..." :
- new String(text));
- }
- }
-
- /**
- * Service record.
- */
- static class Service extends DNSRecord
- {
- private static Logger logger =
- Logger.getLogger(Service.class.toString());
- int priority;
- int weight;
- int port;
- String server;
-
- Service(String name,
- int type,
- int clazz,
- int ttl,
- int priority,
- int weight,
- int port,
- String server)
- {
- super(name, type, clazz, ttl);
- this.priority = priority;
- this.weight = weight;
- this.port = port;
- this.server = server;
-
- String SLevel = System.getProperty("jmdns.debug");
- if (SLevel == null) SLevel = "INFO";
- logger.setLevel(Level.parse(SLevel));
- }
-
- @Override
- void write(DNSOutgoing out) throws IOException
- {
- out.writeShort(priority);
- out.writeShort(weight);
- out.writeShort(port);
- out.writeName(server);
- }
-
- private byte[] toByteArray()
- {
- try
- {
- ByteArrayOutputStream bout = new ByteArrayOutputStream();
- DataOutputStream dout = new DataOutputStream(bout);
- dout.write(name.getBytes("UTF8"));
- dout.writeShort(type);
- dout.writeShort(clazz);
- //dout.writeInt(len);
- dout.writeShort(priority);
- dout.writeShort(weight);
- dout.writeShort(port);
- dout.write(server.getBytes("UTF8"));
- dout.close();
- return bout.toByteArray();
- }
- catch (IOException e)
- {
- throw new InternalError();
- }
- }
-
- private int lexCompare(DNSRecord.Service that)
- {
- byte[] thisBytes = this.toByteArray();
- byte[] thatBytes = that.toByteArray();
- for (int i = 0, n = Math.min(thisBytes.length, thatBytes.length);
- i < n;
- i++)
- {
- if (thisBytes[i] > thatBytes[i])
- {
- return 1;
- }
- else
- {
- if (thisBytes[i] < thatBytes[i])
- {
- return -1;
- }
- }
- }
- return thisBytes.length - thatBytes.length;
- }
-
- @Override
- boolean sameValue(DNSRecord other)
- {
- Service s = (Service) other;
- return (priority == s.priority) &&
- (weight == s.weight) &&
- (port == s.port) &&
- server.equals(s.server);
- }
-
- @Override
- boolean handleQuery(JmDNS dns, long expirationTime)
- {
- ServiceInfo info = dns.services.get(name.toLowerCase());
- if (info != null &&
- (port != info.port ||
- !server.equalsIgnoreCase(dns.getLocalHost().getName())))
- {
- logger.finer("handleQuery() Conflicting probe detected");
-
- // Tie breaker test
- if (info.getState().isProbing() &&
- lexCompare(new DNSRecord.Service(
- info.getQualifiedName(),
- DNSConstants.TYPE_SRV,
- DNSConstants.CLASS_IN | DNSConstants.CLASS_UNIQUE,
- DNSConstants.DNS_TTL,
- info.priority,
- info.weight,
- info.port,
- dns.getLocalHost().getName())) >= 0)
- {
- // We lost the tie break
- String oldName = info.getQualifiedName().toLowerCase();
- info.setName(dns.incrementName(info.getName()));
- dns.services.remove(oldName);
- dns.services.put(info.getQualifiedName().toLowerCase(), info);
- logger.finer(
- "handleQuery() Lost tie break: new unique name chosen:" + info.getName());
-
- }
- info.revertState();
- return true;
-
- }
- return false;
- }
-
- @Override
- boolean handleResponse(JmDNS dns)
- {
- ServiceInfo info = dns.services.get(name.toLowerCase());
- if (info != null &&
- (port != info.port || !server.equalsIgnoreCase(dns.getLocalHost().getName())))
- {
- logger.finer("handleResponse() Denial detected");
-
- if (info.getState().isProbing())
- {
- String oldName = info.getQualifiedName().toLowerCase();
- info.setName(dns.incrementName(info.getName()));
- dns.services.remove(oldName);
- dns.services.put(info.getQualifiedName().toLowerCase(), info);
- logger.finer(
- "handleResponse() New unique name chose:" + info.getName());
-
- }
- info.revertState();
- return true;
- }
- return false;
- }
-
- @Override
- DNSOutgoing addAnswer(JmDNS dns,
- DNSIncoming in,
- InetAddress addr,
- int port,
- DNSOutgoing out)
- throws IOException
- {
- ServiceInfo info = dns.services.get(name.toLowerCase());
- if (info != null)
- {
- if (this.port == info.port != server.equals(dns.getLocalHost().getName()))
- {
- return dns.addAnswer(in, addr, port, out,
- new DNSRecord.Service(
- info.getQualifiedName(),
- DNSConstants.TYPE_SRV,
- DNSConstants.CLASS_IN | DNSConstants.CLASS_UNIQUE,
- DNSConstants.DNS_TTL,
- info.priority,
- info.weight,
- info.port,
- dns.getLocalHost().getName()));
- }
- }
- return out;
- }
-
- @Override
- public String toString()
- {
- return toString(server + ":" + port);
- }
- }
-
- public String toString(String other)
- {
- return toString("record", ttl + "/" +
- getRemainingTTL(System.currentTimeMillis())
-// + "," + other
- );
- }
-}
-
diff --git a/src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/DNSState.java b/src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/DNSState.java
deleted file mode 100644
index 5016050..0000000
--- a/src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/DNSState.java
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright 2003-2005 Arthur van Hoff Rick Blair
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.zeroconf.jmdns;
-
-import java.util.*;
-import java.util.logging.*;
-
-/**
- * DNSState defines the possible states for services registered with JmDNS.
- *
- * @author Werner Randelshofer, Rick Blair
- * @version 1.0 May 23, 2004 Created.
- */
-public class DNSState
- implements Comparable<DNSState>
-{
- private static Logger logger =
- Logger.getLogger(DNSState.class.toString());
-
- private final String name;
-
- /**
- * Ordinal of next state to be created.
- */
- private static int nextOrdinal = 0;
- /**
- * Assign an ordinal to this state.
- */
- private final int ordinal = nextOrdinal++;
- /**
- * Logical sequence of states.
- * The sequence is consistent with the ordinal of a state.
- * This is used for advancing through states.
- */
- private final static ArrayList<DNSState> sequence
- = new ArrayList<DNSState>();
-
- private DNSState(String name)
- {
- this.name = name;
- sequence.add(this);
-
- String SLevel = System.getProperty("jmdns.debug");
- if (SLevel == null) SLevel = "INFO";
- logger.setLevel(Level.parse(SLevel));
- }
-
- @Override
- public final String toString()
- {
- return name;
- }
-
- public static final DNSState PROBING_1 = new DNSState("probing 1");
- public static final DNSState PROBING_2 = new DNSState("probing 2");
- public static final DNSState PROBING_3 = new DNSState("probing 3");
- public static final DNSState ANNOUNCING_1 = new DNSState("announcing 1");
- public static final DNSState ANNOUNCING_2 = new DNSState("announcing 2");
- public static final DNSState ANNOUNCED = new DNSState("announced");
- public static final DNSState CANCELED = new DNSState("canceled");
-
- /**
- * Returns the next advanced state.
- * In general, this advances one step in the following sequence: PROBING_1,
- * PROBING_2, PROBING_3, ANNOUNCING_1, ANNOUNCING_2, ANNOUNCED.
- * Does not advance for ANNOUNCED and CANCELED state.
- * @return Returns the next advanced state.
- */
- public final DNSState advance()
- {
- return (isProbing() || isAnnouncing()) ?
- sequence.get(ordinal + 1) :
- this;
- }
-
- /**
- * Returns to the next reverted state.
- * All states except CANCELED revert to PROBING_1.
- * Status CANCELED does not revert.
- * @return Returns to the next reverted state.
- */
- public final DNSState revert()
- {
- return (this == CANCELED) ? this : PROBING_1;
- }
-
- /**
- * Returns true, if this is a probing state.
- * @return Returns true, if this is a probing state.
- */
- public boolean isProbing()
- {
- return compareTo(PROBING_1) >= 0 && compareTo(PROBING_3) <= 0;
- }
-
- /**
- * Returns true, if this is an announcing state.
- * @return Returns true, if this is an announcing state.
- */
- public boolean isAnnouncing()
- {
- return compareTo(ANNOUNCING_1) >= 0 && compareTo(ANNOUNCING_2) <= 0;
- }
-
- /**
- * Returns true, if this is an announced state.
- * @return Returns true, if this is an announced state.
- */
- public boolean isAnnounced()
- {
- return compareTo(ANNOUNCED) == 0;
- }
-
- /**
- * Compares two states.
- * The states compare as follows:
- * PROBING_1 &lt; PROBING_2 &lt; PROBING_3 &lt; ANNOUNCING_1 &lt;
- * ANNOUNCING_2 &lt; RESPONDING &lt; ANNOUNCED &lt; CANCELED.
- */
- public int compareTo(DNSState state)
- {
- return ordinal - state.ordinal;
- }
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/HostInfo.java b/src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/HostInfo.java
deleted file mode 100644
index 644afc9..0000000
--- a/src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/HostInfo.java
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright 2003-2005 Arthur van Hoff Rick Blair
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.zeroconf.jmdns;
-
-import java.net.*;
-import java.util.logging.*;
-
-
-/**
- * HostInfo information on the local host to be able to cope with change of addresses.
- *
- * @version %I%, %G%
- * @author Pierre Frisch, Werner Randelshofer
- */
-class HostInfo
-{
- private static Logger logger = Logger.getLogger(HostInfo.class.toString());
- protected String name;
- protected InetAddress address;
- protected NetworkInterface interfaze;
- /**
- * This is used to create a unique name for the host name.
- */
- private int hostNameCount;
-
- public HostInfo(InetAddress address, String name)
- {
- super();
-
- String SLevel = System.getProperty("jmdns.debug");
- if (SLevel == null) SLevel = "INFO";
- logger.setLevel(Level.parse(SLevel));
-
- this.address = address;
- this.name = name;
- if (address != null)
- {
- try
- {
- interfaze = NetworkInterface.getByInetAddress(address);
- }
- catch (Exception exception)
- {
- // FIXME Shouldn't we take an action here?
- logger.log(Level.WARNING,
- "LocalHostInfo() exception ", exception);
- }
- }
- }
-
- public String getName()
- {
- return name;
- }
-
- public InetAddress getAddress()
- {
- return address;
- }
-
- public NetworkInterface getInterface()
- {
- return interfaze;
- }
-
- synchronized String incrementHostName()
- {
- hostNameCount++;
- int plocal = name.indexOf(".local.");
- int punder = name.lastIndexOf("-");
- name = name.substring(0, (punder == -1 ? plocal : punder)) + "-" +
- hostNameCount + ".local.";
- return name;
- }
-
- boolean shouldIgnorePacket(DatagramPacket packet)
- {
- boolean result = false;
- if (getAddress() != null)
- {
- InetAddress from = packet.getAddress();
- if (from != null)
- {
- if (from.isLinkLocalAddress() &&
- (!getAddress().isLinkLocalAddress()))
- {
- // Ignore linklocal packets on regular interfaces, unless this is
- // also a linklocal interface. This is to avoid duplicates. This is
- // a terrible hack caused by the lack of an API to get the address
- // of the interface on which the packet was received.
- result = true;
- }
- if (from.isLoopbackAddress() &&
- (!getAddress().isLoopbackAddress()))
- {
- // Ignore loopback packets on a regular interface unless this is
- // also a loopback interface.
- result = true;
- }
- }
- }
- return result;
- }
-
- DNSRecord.Address getDNSAddressRecord(DNSRecord.Address address)
- {
- return (DNSConstants.TYPE_AAAA == address.type ?
- getDNS6AddressRecord() :
- getDNS4AddressRecord());
- }
-
- DNSRecord.Address getDNS4AddressRecord()
- {
- if ((getAddress() != null) &&
- ((getAddress() instanceof Inet4Address) ||
- ((getAddress() instanceof Inet6Address) &&
- (((Inet6Address) getAddress()).isIPv4CompatibleAddress()))))
- {
- return new DNSRecord.Address(getName(),
- DNSConstants.TYPE_A,
- DNSConstants.CLASS_IN,
- DNSConstants.DNS_TTL, getAddress());
- }
- return null;
- }
-
- DNSRecord.Address getDNS6AddressRecord()
- {
- if ((getAddress() != null) && (getAddress() instanceof Inet6Address))
- {
- return new DNSRecord.Address(
- getName(),
- DNSConstants.TYPE_AAAA,
- DNSConstants.CLASS_IN,
- DNSConstants.DNS_TTL,
- getAddress());
- }
- return null;
- }
-
- @Override
- public String toString()
- {
- StringBuffer buf = new StringBuffer();
- buf.append("local host info[");
- buf.append(getName() != null ? getName() : "no name");
- buf.append(", ");
- buf.append(getInterface() != null ?
- getInterface().getDisplayName() :
- "???");
- buf.append(":");
- buf.append(getAddress() != null ?
- getAddress().getHostAddress() :
- "no address");
- buf.append("]");
- return buf.toString();
- }
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/JmDNS.java b/src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/JmDNS.java
deleted file mode 100644
index 96420ba..0000000
--- a/src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/JmDNS.java
+++ /dev/null
@@ -1,3048 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright 2003-2005 Arthur van Hoff Rick Blair
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.zeroconf.jmdns;
-
-import java.io.*;
-import java.net.*;
-import java.util.*;
-
-import net.java.sip.communicator.util.*;
-
-// REMIND: multiple IP addresses
-
-/**
- * mDNS implementation in Java.
- *
- * @version %I%, %G%
- * @author Arthur van Hoff, Rick Blair, Jeff Sonstein,
- * Werner Randelshofer, Pierre Frisch, Scott Lewis
- * @author Christian Vincenot
- */
-public class JmDNS
-{
- private static final Logger logger
- = Logger.getLogger(JmDNS.class);
-
- /**
- * The version of JmDNS.
- */
- public static String VERSION = "2.0";
-
- /**
- * This is the multicast group, we are listening to for
- * multicast DNS messages.
- */
- private InetAddress group;
- /**
- * This is our multicast socket.
- */
- private MulticastSocket socket;
-
- /**
- * Used to fix live lock problem on unregester.
- */
-
- protected boolean closed = false;
-
- /**
- * Holds instances of JmDNS.DNSListener.
- * Must by a synchronized collection, because it is updated from
- * concurrent threads.
- */
- private List<DNSListener> listeners;
- /**
- * Holds instances of ServiceListener's.
- * Keys are Strings holding a fully qualified service type.
- * Values are LinkedList's of ServiceListener's.
- */
- private Map<String, List<ServiceListener>> serviceListeners;
- /**
- * Holds instances of ServiceTypeListener's.
- */
- private List<ServiceTypeListener> typeListeners;
-
-
- /**
- * Cache for DNSEntry's.
- */
- private DNSCache cache;
-
- /**
- * This hashtable holds the services that have been registered.
- * Keys are instances of String which hold an all lower-case version of the
- * fully qualified service name.
- * Values are instances of ServiceInfo.
- */
- Map<String, ServiceInfo> services;
-
- /**
- * This hashtable holds the service types that have been registered or
- * that have been received in an incoming datagram.
- * Keys are instances of String which hold an all lower-case version of the
- * fully qualified service type.
- * Values hold the fully qualified service type.
- */
- Map<String, String> serviceTypes;
-
- /**
- * Handle on the local host
- */
- HostInfo localHost;
-
- private Thread incomingListener = null;
-
- /**
- * Throttle count.
- * This is used to count the overall number of probes sent by JmDNS.
- * When the last throttle increment happened .
- */
- private int throttle;
- /**
- * Last throttle increment.
- */
- private long lastThrottleIncrement;
-
- /**
- * The timer is used to dispatch all outgoing messages of JmDNS.
- * It is also used to dispatch maintenance tasks for the DNS cache.
- */
- private Timer timer;
-
- /**
- * The source for random values.
- * This is used to introduce random delays in responses. This reduces the
- * potential for collisions on the network.
- */
- private final static Random random = new Random();
-
- /**
- * This lock is used to coordinate processing of incoming and outgoing
- * messages. This is needed, because the Rendezvous Conformance Test
- * does not forgive race conditions.
- */
- private Object ioLock = new Object();
-
- /**
- * If an incoming package which needs an answer is truncated, we store it
- * here. We add more incoming DNSRecords to it, until the JmDNS.Responder
- * timer picks it up.
- * Remind: This does not work well with multiple planned answers for packages
- * that came in from different clients.
- */
- private DNSIncoming plannedAnswer;
-
- // State machine
- /**
- * The state of JmDNS.
- * <p/>
- * For proper handling of concurrency, this variable must be
- * changed only using methods advanceState(), revertState() and cancel().
- */
- private DNSState state = DNSState.PROBING_1;
-
- /**
- * Timer task associated to the host name.
- * This is used to prevent from having multiple tasks associated to the host
- * name at the same time.
- */
- TimerTask task;
-
- /**
- * This hashtable is used to maintain a list of service types being collected
- * by this JmDNS instance.
- * The key of the hashtable is a service type name, the value is an instance
- * of JmDNS.ServiceCollector.
- *
- * @see #list
- */
- private HashMap<String, ServiceCollector> serviceCollectors = new HashMap<String, ServiceCollector>();
-
- /**
- * Create an instance of JmDNS.
- * @throws java.io.IOException
- */
- public JmDNS()
- throws IOException
- {
- //String SLevel = System.getProperty("jmdns.debug");
-
- if (logger.isDebugEnabled())
- logger.debug("JmDNS instance created");
- try
- {
- InetAddress addr = InetAddress.getLocalHost();
- // [PJYF Oct 14 2004] Why do we disallow the loopback address?
- init(addr.isLoopbackAddress() ? null : addr, addr.getHostName());
- }
- catch (IOException exc)
- {
- logger.error("Failed to get a reference to localhost", exc);
- init(null, "computer");
- }
- }
-
- /**
- * Create an instance of JmDNS and bind it to a
- * specific network interface given its IP-address.
- * @param addr
- * @throws java.io.IOException
- */
- public JmDNS(InetAddress addr)
- throws IOException
- {
- try
- {
- init(addr, addr.getHostName());
- }
- catch (IOException e)
- {
- init(null, "computer");
- }
- }
-
- /**
- * Initialize everything.
- *
- * @param address The interface to which JmDNS binds to.
- * @param name The host name of the interface.
- */
- private void init(InetAddress address, String name) throws IOException
- {
- // A host name with "." is illegal.
- // so strip off everything and append .local.
- int idx = name.indexOf(".");
- if (idx > 0)
- {
- name = name.substring(0, idx);
- }
- name += ".local.";
- // localHost to IP address binding
- localHost = new HostInfo(address, name);
-
- cache = new DNSCache(100);
-
- listeners = Collections.synchronizedList(new ArrayList<DNSListener>());
- serviceListeners = new HashMap<String, List<ServiceListener>>();
- typeListeners = new ArrayList<ServiceTypeListener>();
-
- services = new Hashtable<String, ServiceInfo>(20);
- serviceTypes = new Hashtable<String, String>(20);
-
- // REMIND: If I could pass in a name for the Timer thread,
- // I would pass 'JmDNS.Timer'.
- timer = new Timer();
- new RecordReaper().start();
-
- incomingListener = new Thread(
- new SocketListener(), "JmDNS.SocketListener");
- incomingListener.setDaemon(true);
- // Bind to multicast socket
- openMulticastSocket(localHost);
- start(services.values());
- }
-
- private void start(Collection<ServiceInfo> serviceInfos)
- {
- state = DNSState.PROBING_1;
- incomingListener.start();
- new Prober().start();
- for (ServiceInfo serviceInfo : serviceInfos)
- {
- try
- {
- registerService(new ServiceInfo(serviceInfo));
- }
- catch (Exception exception)
- {
- logger.warn("start() Registration exception ", exception);
- }
- }
- }
-
- private void openMulticastSocket(HostInfo hostInfo) throws IOException
- {
- if (group == null)
- {
- group = InetAddress.getByName(DNSConstants.MDNS_GROUP);
- }
- if (socket != null)
- {
- this.closeMulticastSocket();
- }
- socket = new MulticastSocket(DNSConstants.MDNS_PORT);
- if ((hostInfo != null) && (localHost.getInterface() != null))
- {
- socket.setNetworkInterface(hostInfo.getInterface());
- }
- socket.setTimeToLive(255);
- socket.joinGroup(group);
- }
-
- private void closeMulticastSocket()
- {
- if (logger.isDebugEnabled())
- logger.debug("closeMulticastSocket()");
- if (socket != null)
- {
- // close socket
- try
- {
- socket.leaveGroup(group);
- socket.close();
- if (incomingListener != null)
- {
- incomingListener.join();
- }
- }
- catch (Exception exception)
- {
- logger.warn("closeMulticastSocket() Close socket exception ",
- exception);
- }
- socket = null;
- }
- }
-
- // State machine
- /**
- * Sets the state and notifies all objects that wait on JmDNS.
- */
- synchronized void advanceState()
- {
- state = state.advance();
- notifyAll();
- }
-
- /**
- * Sets the state and notifies all objects that wait on JmDNS.
- */
- synchronized void revertState()
- {
- state = state.revert();
- notifyAll();
- }
-
- /**
- * Sets the state and notifies all objects that wait on JmDNS.
- */
- synchronized void cancel()
- {
- state = DNSState.CANCELED;
- notifyAll();
- }
-
- /**
- * Returns the current state of this info.
- */
- DNSState getState()
- {
- return state;
- }
-
-
- /**
- * Return the DNSCache associated with the cache variable
- */
- DNSCache getCache()
- {
- return cache;
- }
-
- /**
- * Return the HostName associated with this JmDNS instance.
- * Note: May not be the same as what started. The host name is subject to
- * negotiation.
- * @return Return the HostName associated with this JmDNS instance.
- */
- public String getHostName()
- {
- return localHost.getName();
- }
-
- public HostInfo getLocalHost()
- {
- return localHost;
- }
-
- /**
- * Return the address of the interface to which this instance of JmDNS is
- * bound.
- * @return Return the address of the interface to which this instance
- * of JmDNS is bound.
- * @throws java.io.IOException
- */
- public InetAddress getInterface()
- throws IOException
- {
- return socket.getInterface();
- }
-
- /**
- * Get service information. If the information is not cached, the method
- * will block until updated information is received.
- * <p/>
- * Usage note: Do not call this method from the AWT event dispatcher thread.
- * You will make the user interface unresponsive.
- *
- * @param type fully qualified service type,
- * such as <code>_http._tcp.local.</code> .
- * @param name unqualified service name, such as <code>foobar</code> .
- * @return null if the service information cannot be obtained
- */
- public ServiceInfo getServiceInfo(String type, String name)
- {
- return getServiceInfo(type, name, 3 * 1000);
- }
-
- /**
- * Get service information. If the information is not cached, the method
- * will block for the given timeout until updated information is received.
- * <p/>
- * Usage note: If you call this method from the AWT event dispatcher thread,
- * use a small timeout, or you will make the user interface unresponsive.
- *
- * @param type full qualified service type,
- * such as <code>_http._tcp.local.</code> .
- * @param name unqualified service name, such as <code>foobar</code> .
- * @param timeout timeout in milliseconds
- * @return null if the service information cannot be obtained
- */
- public ServiceInfo getServiceInfo(String type, String name, int timeout)
- {
- ServiceInfo info = new ServiceInfo(type, name);
- new ServiceInfoResolver(info).start();
-
- try
- {
- long end = System.currentTimeMillis() + timeout;
- long delay;
- synchronized (info)
- {
- while (!info.hasData() &&
- (delay = end - System.currentTimeMillis()) > 0)
- {
- info.wait(delay);
- }
- }
- }
- catch (InterruptedException e)
- {
- // empty
- }
-
- return (info.hasData()) ? info : null;
- }
-
- /**
- * Request service information. The information about the service is
- * requested and the ServiceListener.resolveService method is called as soon
- * as it is available.
- * <p/>
- * Usage note: Do not call this method from the AWT event dispatcher thread.
- * You will make the user interface unresponsive.
- *
- * @param type full qualified service type,
- * such as <code>_http._tcp.local.</code> .
- * @param name unqualified service name, such as <code>foobar</code> .
- */
- public void requestServiceInfo(String type, String name)
- {
- requestServiceInfo(type, name, 3 * 1000);
- }
-
- /**
- * Request service information. The information about the service
- * is requested and the ServiceListener.resolveService method is
- * called as soon as it is available.
- *
- * @param type full qualified service type,
- * such as <code>_http._tcp.local.</code> .
- * @param name unqualified service name, such as <code>foobar</code> .
- * @param timeout timeout in milliseconds
- */
- public void requestServiceInfo(String type, String name, int timeout)
- {
- registerServiceType(type);
- ServiceInfo info = new ServiceInfo(type, name);
- new ServiceInfoResolver(info).start();
-
- try
- {
- long end = System.currentTimeMillis() + timeout;
- long delay;
- synchronized (info)
- {
- while (!info.hasData() &&
- (delay = end - System.currentTimeMillis()) > 0)
- {
- info.wait(delay);
- }
- }
- }
- catch (InterruptedException e)
- {
- // empty
- }
- }
-
- void handleServiceResolved(ServiceInfo info)
- {
- List<ServiceListener> list = serviceListeners.get(info.type.toLowerCase());
- if (list != null)
- {
- ServiceEvent event =
- new ServiceEvent(this, info.type, info.getName(), info);
- // Iterate on a copy in case listeners will modify it
- List<ServiceListener> listCopy
- = new ArrayList<ServiceListener> (list);
- for (ServiceListener serviceListener : listCopy)
- serviceListener.serviceResolved(event);
- }
- }
-
- /**
- * Listen for service types.
- *
- * @param listener listener for service types
- * @throws java.io.IOException
- */
- public void addServiceTypeListener(ServiceTypeListener listener)
- throws IOException
- {
- synchronized (this)
- {
- typeListeners.remove(listener);
- typeListeners.add(listener);
- }
-
- // report cached service types
- for (String serviceType : serviceTypes.values())
- {
- listener.serviceTypeAdded(
- new ServiceEvent(this, serviceType, null, null));
- }
-
- new TypeResolver().start();
- }
-
- /**
- * Remove listener for service types.
- *
- * @param listener listener for service types
- */
- public void removeServiceTypeListener(ServiceTypeListener listener)
- {
- synchronized (this)
- {
- typeListeners.remove(listener);
- }
- }
-
- /**
- * Listen for services of a given type. The type has to be a fully
- * qualified type name such as <code>_http._tcp.local.</code>.
- *
- * @param type full qualified service type,
- * such as <code>_http._tcp.local.</code>.
- * @param listener listener for service updates
- */
- public void addServiceListener(String type, ServiceListener listener)
- {
- String lotype = type.toLowerCase();
- removeServiceListener(lotype, listener);
- List<ServiceListener> list = null;
- synchronized (this)
- {
- list = serviceListeners.get(lotype);
- if (list == null)
- {
- list = Collections.synchronizedList(new LinkedList<ServiceListener>());
- serviceListeners.put(lotype, list);
- }
- list.add(listener);
- }
-
- // report cached service types
- for (Iterator<DNSCache.CacheNode> i = cache.iterator(); i.hasNext();)
- {
- for (DNSCache.CacheNode n = i.next(); n != null; n = n.next())
- {
- DNSRecord rec = (DNSRecord) n.getValue();
- if (rec.type == DNSConstants.TYPE_SRV)
- {
- if (rec.name.endsWith(type))
- {
- listener.serviceAdded(
- new ServiceEvent(
- this,
- type,
- toUnqualifiedName(type, rec.name),
- null));
- }
- }
- }
- }
- new ServiceResolver(type).start();
- }
-
- /**
- * Remove listener for services of a given type.
- *
- * @param type of listener to be removed
- * @param listener listener for service updates
- */
- public void removeServiceListener(String type, ServiceListener listener)
- {
- type = type.toLowerCase();
- List<ServiceListener> list = serviceListeners.get(type);
- if (list != null)
- {
- synchronized (this)
- {
- list.remove(listener);
- if (list.size() == 0)
- {
- serviceListeners.remove(type);
- }
- }
- }
- }
-
- /**
- * Register a service. The service is registered
- * for access by other jmdns clients.
- * The name of the service may be changed to make it unique.
- * @param info of service
- * @throws java.io.IOException
- */
- public void registerService(ServiceInfo info) throws IOException
- {
- registerServiceType(info.type);
-
- // bind the service to this address
- info.server = localHost.getName();
- info.addr = localHost.getAddress();
-
- synchronized (this)
- {
- makeServiceNameUnique(info);
- services.put(info.getQualifiedName().toLowerCase(), info);
- }
-
- new /*Service*/Prober().start();
- try
- {
- synchronized (info)
- {
- while (info.getState().compareTo(DNSState.ANNOUNCED) < 0)
- {
- info.wait();
- }
- }
- }
- catch (InterruptedException e)
- {
- logger.error(e.getMessage(), e);
- }
- if (logger.isDebugEnabled())
- logger.debug("registerService() JmDNS registered service as " + info);
- }
-
- /**
- * Unregister a service. The service should have been registered.
- * @param info of service
- */
- public void unregisterService(ServiceInfo info)
- {
- synchronized (this)
- {
- services.remove(info.getQualifiedName().toLowerCase());
- }
- info.cancel();
-
- // Note: We use this lock object to synchronize on it.
- // Synchronizing on another object (e.g. the ServiceInfo) does
- // not make sense, because the sole purpose of the lock is to
- // wait until the canceler has finished. If we synchronized on
- // the ServiceInfo or on the Canceler, we would block all
- // accesses to synchronized methods on that object. This is not
- // what we want!
- Object lock = new Object();
- new Canceler(info, lock).start();
-
- // Remind: We get a deadlock here, if the Canceler does not run!
- try
- {
- synchronized (lock)
- {
- lock.wait();
- }
- }
- catch (InterruptedException e)
- {
- // empty
- }
- }
-
- /**
- * Unregister all services.
- */
- public void unregisterAllServices()
- {
- if (logger.isDebugEnabled())
- logger.debug("unregisterAllServices()");
- if (services.size() == 0)
- {
- return;
- }
-
- Collection<ServiceInfo> list;
- synchronized (this)
- {
- list = new LinkedList<ServiceInfo>(services.values());
- services.clear();
- }
- for (Iterator<ServiceInfo> iterator = list.iterator(); iterator.hasNext();)
- {
- iterator.next().cancel();
- }
-
-
- Object lock = new Object();
- new Canceler(list, lock).start();
- // Remind: We get a livelock here, if the Canceler does not run!
- try
- {
- synchronized (lock)
- {
- if (!closed)
- {
- lock.wait();
- }
- }
- }
- catch (InterruptedException e)
- {
- // empty
- }
- }
-
- /**
- * Register a service type. If this service type was not already known,
- * all service listeners will be notified of the new service type.
- * Service types are automatically registered as they are discovered.
- * @param type of service
- */
- public void registerServiceType(String type)
- {
- String name = type.toLowerCase();
- if (serviceTypes.get(name) == null)
- {
- if ((type.indexOf("._mdns._udp.") < 0) &&
- !type.endsWith(".in-addr.arpa."))
- {
- Collection<ServiceTypeListener> list;
- synchronized (this)
- {
- serviceTypes.put(name, type);
- list = new LinkedList<ServiceTypeListener>(typeListeners);
- }
- for (ServiceTypeListener listener : list)
- listener
- .serviceTypeAdded(
- new ServiceEvent(this, type, null, null));
- }
- }
- }
-
- /**
- * Generate a possibly unique name for a service using the information we
- * have in the cache.
- *
- * @return returns true, if the name of the service info had to be changed.
- */
- private boolean makeServiceNameUnique(ServiceInfo info)
- {
- String originalQualifiedName = info.getQualifiedName();
- long now = System.currentTimeMillis();
-
- boolean collision;
- do
- {
- collision = false;
-
- // Check for collision in cache
- for (DNSCache.CacheNode j = cache.find(
- info.getQualifiedName().toLowerCase());
- j != null;
- j = j.next())
- {
- DNSRecord a = (DNSRecord) j.getValue();
- if ((a.type == DNSConstants.TYPE_SRV) && !a.isExpired(now))
- {
- DNSRecord.Service s = (DNSRecord.Service) a;
- if (s.port != info.port || !s.server.equals(localHost.getName()))
- {
- if (logger.isDebugEnabled())
- logger.debug("makeServiceNameUnique() " +
- "JmDNS.makeServiceNameUnique srv collision:" +
- a + " s.server=" + s.server + " " +
- localHost.getName() + " equals:" +
- (s.server.equals(localHost.getName())));
- info.setName(incrementName(info.getName()));
- collision = true;
- break;
- }
- }
- }
-
- // Check for collision with other service infos published by JmDNS
- Object selfService =
- services.get(info.getQualifiedName().toLowerCase());
- if (selfService != null && selfService != info)
- {
- info.setName(incrementName(info.getName()));
- collision = true;
- }
- }
- while (collision);
-
- return !(originalQualifiedName.equals(info.getQualifiedName()));
- }
-
- String incrementName(String name)
- {
- try
- {
- int l = name.lastIndexOf('(');
- int r = name.lastIndexOf(')');
- if ((l >= 0) && (l < r))
- {
- name = name.substring(0, l) + "(" +
- (Integer.parseInt(name.substring(l + 1, r)) + 1) + ")";
- }
- else
- {
- name += " (2)";
- }
- }
- catch (NumberFormatException e)
- {
- name += " (2)";
- }
- return name;
- }
-
- /**
- * Add a listener for a question. The listener will receive updates
- * of answers to the question as they arrive, or from the cache if they
- * are already available.
- * @param listener to be added
- * @param question - which the listener is responsible for.
- */
- public void addListener(DNSListener listener, DNSQuestion question)
- {
- long now = System.currentTimeMillis();
-
- // add the new listener
- synchronized (this)
- {
- listeners.add(listener);
- }
-
- // report existing matched records
- if (question != null)
- {
- for (DNSCache.CacheNode i = cache.find(question.name);
- i != null;
- i = i.next())
- {
- DNSRecord c = (DNSRecord) i.getValue();
- if (question.answeredBy(c) && !c.isExpired(now))
- {
- listener.updateRecord(this, now, c);
- }
- }
- }
- }
-
- /**
- * Remove a listener from all outstanding questions.
- * The listener will no longer receive any updates.
- */
- void removeListener(DNSListener listener)
- {
- synchronized (this)
- {
- listeners.remove(listener);
- }
- }
-
-
- // Remind: Method updateRecord should receive a better name.
- /**
- * Notify all listeners that a record was updated.
- */
- void updateRecord(long now, DNSRecord rec)
- {
- // We do not want to block the entire DNS
- // while we are updating the record for each listener (service info)
- List<DNSListener> listenerList = null;
- synchronized (this)
- {
- listenerList = new ArrayList<DNSListener>(listeners);
- }
-
- //System.out.println("OUT OF MUTEX!!!!!");
-
- for (DNSListener listener : listenerList)
- listener.updateRecord(this, now, rec);
-
- if (rec.type == DNSConstants.TYPE_PTR ||
- rec.type == DNSConstants.TYPE_SRV)
- {
- List<ServiceListener> serviceListenerList = null;
- synchronized (this)
- {
- serviceListenerList = serviceListeners.get(rec.name.toLowerCase());
- // Iterate on a copy in case listeners will modify it
- if (serviceListenerList != null)
- {
- serviceListenerList = new ArrayList<ServiceListener>(serviceListenerList);
- }
- }
- if (serviceListenerList != null)
- {
- boolean expired = rec.isExpired(now);
- String type = rec.getName();
- String name = ((DNSRecord.Pointer) rec).getAlias();
- // DNSRecord old = (DNSRecord)services.get(name.toLowerCase());
- if (!expired)
- {
- // new record
- ServiceEvent event =
- new ServiceEvent(
- this,
- type,
- toUnqualifiedName(type, name),
- null);
- for (Iterator<ServiceListener> iterator = serviceListenerList.iterator();
- iterator.hasNext();)
- {
- iterator.next().serviceAdded(event);
- }
- }
- else
- {
- // expire record
- ServiceEvent event =
- new ServiceEvent(
- this,
- type,
- toUnqualifiedName(type, name),
- null);
- for (Iterator<ServiceListener> iterator = serviceListenerList.iterator();
- iterator.hasNext();)
- {
- iterator.next().serviceRemoved(event);
- }
- }
- }
- }
- }
-
- /**
- * Handle an incoming response. Cache answers, and pass them on to
- * the appropriate questions.
- */
- private void handleResponse(DNSIncoming msg)
- throws IOException
- {
- long now = System.currentTimeMillis();
-
- boolean hostConflictDetected = false;
- boolean serviceConflictDetected = false;
-
- if (logger.isTraceEnabled())
- logger.trace("JMDNS/handleResponse received " +
- msg.answers.size()+ " messages");
- for (DNSRecord rec : msg.answers)
- {
- if (logger.isTraceEnabled())
- logger.trace("PRINT: "+ rec);
- //cache.add(rec);
- }
-
- for (DNSRecord rec : msg.answers)
- {
- boolean isInformative = false;
- boolean expired = rec.isExpired(now);
-
- if (logger.isTraceEnabled())
- logger.trace("JMDNS received : " + rec + " expired: "+expired);
-
- // update the cache
- DNSRecord c = (DNSRecord) cache.get(rec);
- if (c != null)
- {
- if (logger.isTraceEnabled())
- logger.trace("JMDNS has found "+rec+" in cache");
- if (expired)
- {
- isInformative = true;
- cache.remove(c);
- }
- else
- {
- /* Special case for SIP Communicator.
- * We want to be informed if a cache entry is modified
- */
-// if ((c.isUnique()
-// && c.getType() == DNSConstants.TYPE_TXT
-// && ((c.getClazz() & DNSConstants.CLASS_IN) != 0)))
-// isInformative = true;
-// c.resetTTL(rec);
-// rec = c;
- if (logger.isTraceEnabled())
- logger.trace(
- new Boolean(c.isUnique()).toString() +
- c.getType()+c.getClazz() + "/" +
- DNSConstants.TYPE_TXT + " "+DNSConstants.CLASS_IN);
-
- if ((rec.isUnique()
- && ((rec.getType() & DNSConstants.TYPE_TXT) != 0)
- && ((rec.getClazz() & DNSConstants.CLASS_IN) != 0)))
- {
- if (logger.isTraceEnabled())
- logger.trace("UPDATING CACHE !! ");
- isInformative = true;
- cache.remove(c);
- cache.add(rec);
- }
- else
- {
- c.resetTTL(rec);
- rec = c;
- }
- }
- }
- else
- {
- if (!expired)
- {
- isInformative = true;
- if (logger.isTraceEnabled())
- logger.trace("Adding "+rec+" to the cache");
- cache.add(rec);
- }
- }
- switch (rec.type)
- {
- case DNSConstants.TYPE_PTR:
- // handle _mdns._udp records
- if (rec.getName().indexOf("._mdns._udp.") >= 0)
- {
- if (!expired &&
- rec.name.startsWith("_services._mdns._udp."))
- {
- isInformative = true;
- registerServiceType(((DNSRecord.Pointer)rec).alias);
- }
- continue;
- }
- registerServiceType(rec.name);
- break;
- }
-
-
- if ((rec.getType() == DNSConstants.TYPE_A) ||
- (rec.getType() == DNSConstants.TYPE_AAAA))
- {
- hostConflictDetected |= rec.handleResponse(this);
- }
- else
- {
- serviceConflictDetected |= rec.handleResponse(this);
- }
-
- // notify the listeners
- if (isInformative)
- {
- updateRecord(now, rec);
- }
-
-
- }
-
- if (hostConflictDetected || serviceConflictDetected)
- {
- new Prober().start();
- }
- }
-
- /**
- * Handle an incoming query. See if we can answer any part of it
- * given our service infos.
- */
- private void handleQuery(DNSIncoming in, InetAddress addr, int port)
- throws IOException
- {
- // Track known answers
- boolean hostConflictDetected = false;
- boolean serviceConflictDetected = false;
- long expirationTime = System.currentTimeMillis() +
- DNSConstants.KNOWN_ANSWER_TTL;
- for (DNSRecord answer : in.answers)
- {
- if ((answer.getType() == DNSConstants.TYPE_A) ||
- (answer.getType() == DNSConstants.TYPE_AAAA))
- {
- hostConflictDetected |=
- answer.handleQuery(this, expirationTime);
- }
- else
- {
- serviceConflictDetected |=
- answer.handleQuery(this, expirationTime);
- }
- }
-
- if (plannedAnswer != null)
- {
- plannedAnswer.append(in);
- }
- else
- {
- if (in.isTruncated())
- {
- plannedAnswer = in;
- }
-
- new Responder(in, addr, port).start();
- }
-
- if (hostConflictDetected || serviceConflictDetected)
- {
- new Prober().start();
- }
- }
-
- /**
- * Add an answer to a question. Deal with the case when the
- * outgoing packet overflows
- */
- DNSOutgoing addAnswer(DNSIncoming in,
- InetAddress addr,
- int port,
- DNSOutgoing out,
- DNSRecord rec)
- throws IOException
- {
- if (out == null)
- {
- out = new DNSOutgoing(
- DNSConstants.FLAGS_QR_RESPONSE | DNSConstants.FLAGS_AA);
- }
- try
- {
- out.addAnswer(in, rec);
- }
- catch (IOException e)
- {
- out.flags |= DNSConstants.FLAGS_TC;
- out.id = in.id;
- out.finish();
- send(out);
-
- out = new DNSOutgoing(
- DNSConstants.FLAGS_QR_RESPONSE | DNSConstants.FLAGS_AA);
- out.addAnswer(in, rec);
- }
- return out;
- }
-
-
- /**
- * Send an outgoing multicast DNS message.
- */
- private void send(DNSOutgoing out) throws IOException
- {
- out.finish();
- if (!out.isEmpty())
- {
- DatagramPacket packet =
- new DatagramPacket(
- out.data, out.off, group, DNSConstants.MDNS_PORT);
-
- try
- {
- DNSIncoming msg = new DNSIncoming(packet);
- if (logger.isTraceEnabled())
- logger.trace("send() JmDNS out:" + msg.print(true));
- }
- catch (IOException exc)
- {
- logger.error(
- "send(DNSOutgoing) - JmDNS can not parse what it sends!!!",
- exc);
- }
- socket.send(packet);
- }
- }
-
- /**
- * Listen for multicast packets.
- */
- class SocketListener implements Runnable
- {
- public void run()
- {
- try
- {
- byte buf[] = new byte[DNSConstants.MAX_MSG_ABSOLUTE];
- DatagramPacket packet = new DatagramPacket(buf, buf.length);
- while (state != DNSState.CANCELED)
- {
- packet.setLength(buf.length);
- socket.receive(packet);
- if (state == DNSState.CANCELED)
- {
- break;
- }
- try
- {
- if (localHost.shouldIgnorePacket(packet))
- {
- continue;
- }
-
- DNSIncoming msg = new DNSIncoming(packet);
- if (logger.isTraceEnabled())
- logger.trace("SocketListener.run() JmDNS in:" +
- msg.print(true));
-
- synchronized (ioLock)
- {
- if (msg.isQuery())
- {
- if (packet.getPort() != DNSConstants.MDNS_PORT)
- {
- handleQuery(msg,
- packet.getAddress(),
- packet.getPort());
- }
- handleQuery(msg, group, DNSConstants.MDNS_PORT);
- }
- else
- {
- handleResponse(msg);
- }
- }
- }
- catch (IOException e)
- {
- logger.warn( "run() exception ", e);
- }
- }
- }
- catch (IOException e)
- {
- if (state != DNSState.CANCELED)
- {
- logger.warn( "run() exception ", e);
- recover();
- }
- }
- }
- }
-
-
- /**
- * Periodicaly removes expired entries from the cache.
- */
- private class RecordReaper extends TimerTask
- {
- public void start()
- {
- timer.schedule( this,
- DNSConstants.RECORD_REAPER_INTERVAL,
- DNSConstants.RECORD_REAPER_INTERVAL);
- }
-
- @Override
- public void run()
- {
- synchronized (JmDNS.this)
- {
- if (state == DNSState.CANCELED)
- {
- return;
- }
- if (logger.isTraceEnabled())
- logger.trace("run() JmDNS reaping cache");
-
- // Remove expired answers from the cache
- // -------------------------------------
- // To prevent race conditions, we defensively copy all cache
- // entries into a list.
- List<DNSEntry> list = new ArrayList<DNSEntry>();
- synchronized (cache)
- {
- for (Iterator<DNSCache.CacheNode> i = cache.iterator();
- i.hasNext();)
- {
- for (DNSCache.CacheNode n = i.next();
- n != null;
- n = n.next())
- {
- list.add(n.getValue());
- }
- }
- }
- // Now, we remove them.
- long now = System.currentTimeMillis();
- for (Iterator<DNSEntry> i = list.iterator(); i.hasNext();)
- {
- DNSRecord c = (DNSRecord)i.next();
- if (c.isExpired(now))
- {
- updateRecord(now, c);
- cache.remove(c);
- }
- }
- }
- }
- }
-
-
- /**
- * The Prober sends three consecutive probes for all service infos
- * that needs probing as well as for the host name.
- * The state of each service info of the host name is advanced,
- * when a probe has been sent for it.
- * When the prober has run three times, it launches an Announcer.
- * <p/>
- * If a conflict during probes occurs, the affected service
- * infos (and affected host name) are taken away from the prober.
- * This eventually causes the prober tho cancel itself.
- */
- private class Prober extends TimerTask
- {
- /**
- * The state of the prober.
- */
- DNSState taskState = DNSState.PROBING_1;
-
- public Prober()
- {
- // Associate the host name to this, if it needs probing
- if (state == DNSState.PROBING_1)
- {
- task = this;
- }
- // Associate services to this, if they need probing
- synchronized (JmDNS.this)
- {
- for (Iterator<ServiceInfo> iterator = services.values().iterator();
- iterator.hasNext();)
- {
- ServiceInfo info = iterator.next();
- if (info.getState() == DNSState.PROBING_1)
- {
- info.task = this;
- }
- }
- }
- }
-
-
- public void start()
- {
- long now = System.currentTimeMillis();
- if (now - lastThrottleIncrement <
- DNSConstants.PROBE_THROTTLE_COUNT_INTERVAL)
- {
- throttle++;
- }
- else
- {
- throttle = 1;
- }
- lastThrottleIncrement = now;
-
- if (state == DNSState.ANNOUNCED &&
- throttle < DNSConstants.PROBE_THROTTLE_COUNT)
- {
- timer.schedule(this,
- random.nextInt(1 + DNSConstants.PROBE_WAIT_INTERVAL),
- DNSConstants.PROBE_WAIT_INTERVAL);
- }
- else
- {
- timer.schedule(this,
- DNSConstants.PROBE_CONFLICT_INTERVAL,
- DNSConstants.PROBE_CONFLICT_INTERVAL);
- }
- }
-
- @Override
- public boolean cancel()
- {
- // Remove association from host name to this
- if (task == this)
- {
- task = null;
- }
-
- // Remove associations from services to this
- synchronized (JmDNS.this)
- {
- for (Iterator<ServiceInfo> i = services.values().iterator();
- i.hasNext();)
- {
- ServiceInfo info = i.next();
- if (info.task == this)
- {
- info.task = null;
- }
- }
- }
-
- return super.cancel();
- }
-
- @Override
- public void run()
- {
- synchronized (ioLock)
- {
- DNSOutgoing out = null;
- try
- {
- // send probes for JmDNS itself
- if (state == taskState && task == this)
- {
- if (out == null)
- {
- out = new DNSOutgoing(DNSConstants.FLAGS_QR_QUERY);
- }
- out.addQuestion(
- new DNSQuestion(
- localHost.getName(),
- DNSConstants.TYPE_ANY,
- DNSConstants.CLASS_IN));
- DNSRecord answer = localHost.getDNS4AddressRecord();
- if (answer != null)
- {
- out.addAuthorativeAnswer(answer);
- }
- answer = localHost.getDNS6AddressRecord();
- if (answer != null)
- {
- out.addAuthorativeAnswer(answer);
- }
- advanceState();
- }
- // send probes for services
- // Defensively copy the services into a local list,
- // to prevent race conditions with methods registerService
- // and unregisterService.
- List<ServiceInfo> list;
- synchronized (JmDNS.this)
- {
- list = new LinkedList<ServiceInfo>(services.values());
- }
- for (Iterator<ServiceInfo> i = list.iterator(); i.hasNext();)
- {
- ServiceInfo info = i.next();
-
- synchronized (info)
- {
- if (info.getState() == taskState &&
- info.task == this)
- {
- info.advanceState();
- if (logger.isDebugEnabled())
- logger.debug("run() JmDNS probing " +
- info.getQualifiedName() + " state " +
- info.getState());
-
- if (out == null)
- {
- out = new DNSOutgoing(
- DNSConstants.FLAGS_QR_QUERY);
- out.addQuestion(
- new DNSQuestion(
- info.getQualifiedName(),
- DNSConstants.TYPE_ANY,
- DNSConstants.CLASS_IN));
- }
- out.addAuthorativeAnswer(
- new DNSRecord.Service(
- info.getQualifiedName(),
- DNSConstants.TYPE_SRV,
- DNSConstants.CLASS_IN,
- DNSConstants.DNS_TTL,
- info.priority,
- info.weight,
- info.port,
- localHost.getName()));
- }
- }
- }
- if (out != null)
- {
- if (logger.isDebugEnabled())
- logger.debug("run() JmDNS probing #" + taskState);
- send(out);
- }
- else
- {
- // If we have nothing to send, another timer taskState
- // ahead of us has done the job for us. We can cancel.
- cancel();
- return;
- }
- }
- catch (Throwable e)
- {
- logger.warn( "run() exception ", e);
- recover();
- }
-
- taskState = taskState.advance();
- if (!taskState.isProbing())
- {
- cancel();
-
- new Announcer().start();
- }
- }
- }
-
- }
-
- /**
- * The Announcer sends an accumulated query of all announces, and advances
- * the state of all serviceInfos, for which it has sent an announce.
- * The Announcer also sends announcements and advances the state of JmDNS
- * itself.
- * <p/>
- * When the announcer has run two times, it finishes.
- */
- private class Announcer extends TimerTask
- {
- /**
- * The state of the announcer.
- */
- DNSState taskState = DNSState.ANNOUNCING_1;
-
- public Announcer()
- {
- // Associate host to this, if it needs announcing
- if (state == DNSState.ANNOUNCING_1)
- {
- task = this;
- }
- // Associate services to this, if they need announcing
- synchronized (JmDNS.this)
- {
- for (Iterator<ServiceInfo> s = services.values().iterator(); s.hasNext();)
- {
- ServiceInfo info = s.next();
- if (info.getState() == DNSState.ANNOUNCING_1)
- {
- info.task = this;
- }
- }
- }
- }
-
- public void start()
- {
- timer.schedule(this,
- DNSConstants.ANNOUNCE_WAIT_INTERVAL,
- DNSConstants.ANNOUNCE_WAIT_INTERVAL);
- }
-
- @Override
- public boolean cancel()
- {
- // Remove association from host to this
- if (task == this)
- {
- task = null;
- }
-
- // Remove associations from services to this
- synchronized (JmDNS.this)
- {
- for (Iterator<ServiceInfo> i = services.values().iterator();
- i.hasNext();)
- {
- ServiceInfo info = i.next();
- if (info.task == this)
- {
- info.task = null;
- }
- }
- }
-
- return super.cancel();
- }
-
- @Override
- public void run()
- {
- DNSOutgoing out = null;
- try
- {
- // send probes for JmDNS itself
- if (state == taskState)
- {
- if (out == null)
- {
- out = new DNSOutgoing(
- DNSConstants.FLAGS_QR_RESPONSE | DNSConstants.FLAGS_AA);
- }
- DNSRecord answer = localHost.getDNS4AddressRecord();
- if (answer != null)
- {
- out.addAnswer(answer, 0);
- }
- answer = localHost.getDNS6AddressRecord();
- if (answer != null)
- {
- out.addAnswer(answer, 0);
- }
- advanceState();
- }
- // send announces for services
- // Defensively copy the services into a local list,
- // to prevent race conditions with methods registerService
- // and unregisterService.
- List<ServiceInfo> list;
- synchronized (JmDNS.this)
- {
- list = new ArrayList<ServiceInfo>(services.values());
- }
- for (Iterator<ServiceInfo> i = list.iterator(); i.hasNext();)
- {
- ServiceInfo info = i.next();
- synchronized (info)
- {
- if (info.getState() == taskState && info.task == this)
- {
- info.advanceState();
- if (logger.isDebugEnabled())
- logger.debug("run() JmDNS announcing " +
- info.getQualifiedName() +
- " state " + info.getState());
-
- if (out == null)
- {
- out = new DNSOutgoing(
- DNSConstants.FLAGS_QR_RESPONSE |
- DNSConstants.FLAGS_AA);
- }
- out.addAnswer(
- new DNSRecord.Pointer(
- info.type,
- DNSConstants.TYPE_PTR,
- DNSConstants.CLASS_IN,
- DNSConstants.DNS_TTL,
- info.getQualifiedName()), 0);
- out.addAnswer(
- new DNSRecord.Service(
- info.getQualifiedName(),
- DNSConstants.TYPE_SRV,
- DNSConstants.CLASS_IN,
- DNSConstants.DNS_TTL,
- info.priority,
- info.weight,
- info.port,
- localHost.getName()), 0);
- out.addAnswer(
- new DNSRecord.Text(
- info.getQualifiedName(),
- DNSConstants.TYPE_TXT,
- DNSConstants.CLASS_IN,
- DNSConstants.DNS_TTL,
- info.text), 0);
- }
- }
- }
- if (out != null)
- {
- if (logger.isDebugEnabled())
- logger.debug("run() JmDNS announcing #" + taskState);
- send(out);
- }
- else
- {
- // If we have nothing to send, another timer taskState ahead
- // of us has done the job for us. We can cancel.
- cancel();
- }
- }
- catch (Throwable e)
- {
- logger.warn( "run() exception ", e);
- recover();
- }
-
- taskState = taskState.advance();
- if (!taskState.isAnnouncing())
- {
- cancel();
-
- new Renewer().start();
- }
- }
- }
-
- /**
- * The Renewer is there to send renewal announcment
- * when the record expire for ours infos.
- */
- private class Renewer extends TimerTask
- {
- /**
- * The state of the announcer.
- */
- DNSState taskState = DNSState.ANNOUNCED;
-
- public Renewer()
- {
- // Associate host to this, if it needs renewal
- if (state == DNSState.ANNOUNCED)
- {
- task = this;
- }
- // Associate services to this, if they need renewal
- synchronized (JmDNS.this)
- {
- for (Iterator<ServiceInfo> s = services.values().iterator(); s.hasNext();)
- {
- ServiceInfo info = s.next();
- if (info.getState() == DNSState.ANNOUNCED)
- {
- info.task = this;
- }
- }
- }
- }
-
- public void start()
- {
- timer.schedule(this,
- DNSConstants.ANNOUNCED_RENEWAL_TTL_INTERVAL,
- DNSConstants.ANNOUNCED_RENEWAL_TTL_INTERVAL);
- }
-
- @Override
- public boolean cancel()
- {
- // Remove association from host to this
- if (task == this)
- {
- task = null;
- }
-
- // Remove associations from services to this
- synchronized (JmDNS.this)
- {
- for (Iterator<ServiceInfo> i = services.values().iterator();
- i.hasNext();)
- {
- ServiceInfo info = i.next();
- if (info.task == this)
- {
- info.task = null;
- }
- }
- }
-
- return super.cancel();
- }
-
- @Override
- public void run()
- {
- DNSOutgoing out = null;
- try
- {
- // send probes for JmDNS itself
- if (state == taskState)
- {
- if (out == null)
- {
- out = new DNSOutgoing(
- DNSConstants.FLAGS_QR_RESPONSE | DNSConstants.FLAGS_AA);
- }
- DNSRecord answer = localHost.getDNS4AddressRecord();
- if (answer != null)
- {
- out.addAnswer(answer, 0);
- }
- answer = localHost.getDNS6AddressRecord();
- if (answer != null)
- {
- out.addAnswer(answer, 0);
- }
- advanceState();
- }
- // send announces for services
- // Defensively copy the services into a local list,
- // to prevent race conditions with methods registerService
- // and unregisterService.
- List<ServiceInfo> list;
- synchronized (JmDNS.this)
- {
- list = new ArrayList<ServiceInfo>(services.values());
- }
- for (Iterator<ServiceInfo> i = list.iterator(); i.hasNext();)
- {
- ServiceInfo info = i.next();
- synchronized (info)
- {
- if (info.getState() == taskState && info.task == this)
- {
- info.advanceState();
- if (logger.isDebugEnabled())
- logger.debug("run() JmDNS announced " +
- info.getQualifiedName() + " state " + info.getState());
-
- if (out == null)
- {
- out = new DNSOutgoing(
- DNSConstants.FLAGS_QR_RESPONSE |
- DNSConstants.FLAGS_AA);
- }
- out.addAnswer(
- new DNSRecord.Pointer(
- info.type,
- DNSConstants.TYPE_PTR,
- DNSConstants.CLASS_IN,
- DNSConstants.DNS_TTL,
- info.getQualifiedName()), 0);
- out.addAnswer(
- new DNSRecord.Service(
- info.getQualifiedName(),
- DNSConstants.TYPE_SRV,
- DNSConstants.CLASS_IN,
- DNSConstants.DNS_TTL,
- info.priority,
- info.weight,
- info.port,
- localHost.getName()), 0);
- out.addAnswer(
- new DNSRecord.Text(
- info.getQualifiedName(),
- DNSConstants.TYPE_TXT,
- DNSConstants.CLASS_IN,
- DNSConstants.DNS_TTL,
- info.text), 0);
- }
- }
- }
- if (out != null)
- {
- if (logger.isDebugEnabled())
- logger.debug("run() JmDNS announced");
- send(out);
- }
- else
- {
- // If we have nothing to send, another timer taskState ahead
- // of us has done the job for us. We can cancel.
- cancel();
- }
- }
- catch (Throwable e)
- {
- logger.warn( "run() exception ", e);
- recover();
- }
-
- taskState = taskState.advance();
- if (!taskState.isAnnounced())
- {
- cancel();
-
- }
- }
- }
-
- /**
- * The Responder sends a single answer for the specified service infos
- * and for the host name.
- */
- private class Responder extends TimerTask
- {
- private DNSIncoming in;
- private InetAddress addr;
- private int port;
-
- public Responder(DNSIncoming in, InetAddress addr, int port)
- {
- this.in = in;
- this.addr = addr;
- this.port = port;
- }
-
- public void start()
- {
- // According to draft-cheshire-dnsext-multicastdns.txt
- // chapter "8 Responding":
- // We respond immediately if we know for sure, that we are
- // the only one who can respond to the query.
- // In all other cases, we respond within 20-120 ms.
- //
- // According to draft-cheshire-dnsext-multicastdns.txt
- // chapter "7.2 Multi-Packet Known Answer Suppression":
- // We respond after 20-120 ms if the query is truncated.
-
- boolean iAmTheOnlyOne = true;
- for (DNSEntry entry : in.questions)
- {
- if (entry instanceof DNSQuestion)
- {
- DNSQuestion q = (DNSQuestion) entry;
- if (logger.isTraceEnabled())
- logger.trace("start() question=" + q);
- iAmTheOnlyOne &= (q.type == DNSConstants.TYPE_SRV
- || q.type == DNSConstants.TYPE_TXT
- || q.type == DNSConstants.TYPE_A
- || q.type == DNSConstants.TYPE_AAAA
- || localHost.getName().equalsIgnoreCase(q.name)
- || services.containsKey(q.name.toLowerCase()));
- if (!iAmTheOnlyOne)
- {
- break;
- }
- }
- }
- int delay = (iAmTheOnlyOne && !in.isTruncated()) ?
- 0 :
- DNSConstants.RESPONSE_MIN_WAIT_INTERVAL +
- random.nextInt(
- DNSConstants.RESPONSE_MAX_WAIT_INTERVAL -
- DNSConstants.RESPONSE_MIN_WAIT_INTERVAL + 1) -
- in.elapseSinceArrival();
- if (delay < 0)
- {
- delay = 0;
- }
- if (logger.isTraceEnabled())
- logger.trace("start() Responder chosen delay=" + delay);
- timer.schedule(this, delay);
- }
-
- @Override
- public void run()
- {
- synchronized (ioLock)
- {
- if (plannedAnswer == in)
- {
- plannedAnswer = null;
- }
-
- // We use these sets to prevent duplicate records
- // FIXME - This should be moved into DNSOutgoing
- HashSet<DNSQuestion> questions = new HashSet<DNSQuestion>();
- HashSet<DNSRecord> answers = new HashSet<DNSRecord>();
-
-
- if (state == DNSState.ANNOUNCED)
- {
- try
- {
- boolean isUnicast = (port != DNSConstants.MDNS_PORT);
-
-
- // Answer questions
- for (Iterator<DNSEntry> iterator = in.questions.iterator();
- iterator.hasNext();)
- {
- DNSEntry entry = iterator.next();
- if (entry instanceof DNSQuestion)
- {
- DNSQuestion q = (DNSQuestion) entry;
-
- // for unicast responses the question
- // must be included
- if (isUnicast)
- {
- //out.addQuestion(q);
- questions.add(q);
- }
-
- int type = q.type;
- if (type == DNSConstants.TYPE_ANY ||
- type == DNSConstants.TYPE_SRV)
- { // I ama not sure of why there is a special
- // case here [PJYF Oct 15 2004]
- if (localHost.getName().
- equalsIgnoreCase(q.getName()))
- {
- // type = DNSConstants.TYPE_A;
- DNSRecord answer =
- localHost.getDNS4AddressRecord();
- if (answer != null)
- {
- answers.add(answer);
- }
- answer = localHost.getDNS6AddressRecord();
- if (answer != null)
- {
- answers.add(answer);
- }
- type = DNSConstants.TYPE_IGNORE;
- }
- else
- {
- if (serviceTypes.containsKey(
- q.getName().toLowerCase()))
- {
- type = DNSConstants.TYPE_PTR;
- }
- }
- }
-
- switch (type)
- {
- case DNSConstants.TYPE_A:
- {
- // Answer a query for a domain name
- //out = addAnswer( in, addr, port, out, host );
- DNSRecord answer =
- localHost.getDNS4AddressRecord();
- if (answer != null)
- {
- answers.add(answer);
- }
- break;
- }
- case DNSConstants.TYPE_AAAA:
- {
- // Answer a query for a domain name
- DNSRecord answer =
- localHost.getDNS6AddressRecord();
- if (answer != null)
- {
- answers.add(answer);
- }
- break;
- }
- case DNSConstants.TYPE_PTR:
- {
- // Answer a query for services of a given type
-
- // find matching services
- for (Iterator<ServiceInfo> serviceIterator =
- services.values().iterator();
- serviceIterator.hasNext();)
- {
- ServiceInfo info = serviceIterator.next();
- if (info.getState() == DNSState.ANNOUNCED)
- {
- if (q.name.equalsIgnoreCase(info.type))
- {
- DNSRecord answer =
- localHost.getDNS4AddressRecord();
- if (answer != null)
- {
- answers.add(answer);
- }
- answer =
- localHost.getDNS6AddressRecord();
- if (answer != null)
- {
- answers.add(answer);
- }
- answers.add(
- new DNSRecord.Pointer(
- info.type,
- DNSConstants.TYPE_PTR,
- DNSConstants.CLASS_IN,
- DNSConstants.DNS_TTL,
- info.getQualifiedName()));
- answers.add(
- new DNSRecord.Service(
- info.getQualifiedName(),
- DNSConstants.TYPE_SRV,
- DNSConstants.CLASS_IN | DNSConstants.CLASS_UNIQUE,
- DNSConstants.DNS_TTL,
- info.priority,
- info.weight,
- info.port,
- localHost.getName()));
- answers.add(
- new DNSRecord.Text(
- info.getQualifiedName(),
- DNSConstants.TYPE_TXT,
- DNSConstants.CLASS_IN | DNSConstants.CLASS_UNIQUE,
- DNSConstants.DNS_TTL,
- info.text));
- }
- }
- }
- if (q.name.equalsIgnoreCase("_services._mdns._udp.local."))
- {
- for (Iterator<String> serviceTypeIterator = serviceTypes.values().iterator();
- serviceTypeIterator.hasNext();)
- {
- answers.add(
- new DNSRecord.Pointer(
- "_services._mdns._udp.local.",
- DNSConstants.TYPE_PTR,
- DNSConstants.CLASS_IN,
- DNSConstants.DNS_TTL,
- serviceTypeIterator.next()));
- }
- }
- break;
- }
- case DNSConstants.TYPE_SRV:
- case DNSConstants.TYPE_ANY:
- case DNSConstants.TYPE_TXT:
- {
- ServiceInfo info = services.get(q.name.toLowerCase());
- if (info != null &&
- info.getState() == DNSState.ANNOUNCED)
- {
- DNSRecord answer =
- localHost.getDNS4AddressRecord();
- if (answer != null)
- {
- answers.add(answer);
- }
- answer =
- localHost.getDNS6AddressRecord();
- if (answer != null)
- {
- answers.add(answer);
- }
- answers.add(
- new DNSRecord.Pointer(
- info.type,
- DNSConstants.TYPE_PTR,
- DNSConstants.CLASS_IN,
- DNSConstants.DNS_TTL,
- info.getQualifiedName()));
- answers.add(
- new DNSRecord.Service(
- info.getQualifiedName(),
- DNSConstants.TYPE_SRV,
- DNSConstants.CLASS_IN | DNSConstants.CLASS_UNIQUE,
- DNSConstants.DNS_TTL,
- info.priority,
- info.weight,
- info.port,
- localHost.getName()));
- answers.add(
- new DNSRecord.Text(
- info.getQualifiedName(),
- DNSConstants.TYPE_TXT,
- DNSConstants.CLASS_IN | DNSConstants.CLASS_UNIQUE,
- DNSConstants.DNS_TTL,
- info.text));
- }
- break;
- }
- default :
- {
- //System.out.println("JmDNSResponder.unhandled query:"+q);
- break;
- }
- }
- }
- }
-
-
- // remove known answers, if the ttl is at least half of
- // the correct value. (See Draft Cheshire chapter 7.1.).
- for (DNSRecord knownAnswer : in.answers)
- {
- if (knownAnswer.ttl > DNSConstants.DNS_TTL / 2 &&
- answers.remove(knownAnswer))
- {
- if (logger.isDebugEnabled())
- logger.debug(
- "JmDNS Responder Known Answer Removed");
- }
- }
-
-
- // responde if we have answers
- if (answers.size() != 0)
- {
- if (logger.isDebugEnabled())
- logger.debug("run() JmDNS responding");
- DNSOutgoing out = null;
- if (isUnicast)
- {
- out = new DNSOutgoing(
- DNSConstants.FLAGS_QR_RESPONSE
- | DNSConstants.FLAGS_AA,
- false);
- }
-
- for (Iterator<DNSQuestion> i = questions.iterator();
- i.hasNext();)
- {
- out.addQuestion(i.next());
- }
- for (Iterator<DNSRecord> i = answers.iterator();
- i.hasNext();)
- {
- out = addAnswer(in, addr, port, out, i.next());
- }
- send(out);
- }
- this.cancel();
- }
- catch (Throwable e)
- {
- logger.warn( "run() exception ", e);
- close();
- }
- }
- }
- }
- }
-
- /**
- * Helper class to resolve service types.
- * <p/>
- * The TypeResolver queries three times consecutively for service types, and then
- * removes itself from the timer.
- * <p/>
- * The TypeResolver will run only if JmDNS is in state ANNOUNCED.
- */
- private class TypeResolver extends TimerTask
- {
- public void start()
- {
- timer.schedule(this,
- DNSConstants.QUERY_WAIT_INTERVAL,
- DNSConstants.QUERY_WAIT_INTERVAL);
- }
-
- /**
- * Counts the number of queries that were sent.
- */
- int count = 0;
-
- @Override
- public void run()
- {
- try
- {
- if (state == DNSState.ANNOUNCED)
- {
- if (count++ < 3)
- {
- if (logger.isDebugEnabled())
- logger.debug("run() JmDNS querying type");
- DNSOutgoing out =
- new DNSOutgoing(DNSConstants.FLAGS_QR_QUERY);
- out.addQuestion(
- new DNSQuestion(
- "_services._mdns._udp.local.",
- DNSConstants.TYPE_PTR,
- DNSConstants.CLASS_IN));
- for (String serviceType : serviceTypes.values())
- {
- out.addAnswer(
- new DNSRecord.Pointer(
- "_services._mdns._udp.local.",
- DNSConstants.TYPE_PTR,
- DNSConstants.CLASS_IN,
- DNSConstants.DNS_TTL,
- serviceType), 0);
- }
- send(out);
- }
- else
- {
- // After three queries, we can quit.
- this.cancel();
- }
- }
- else
- {
- if (state == DNSState.CANCELED)
- {
- this.cancel();
- }
- }
- }
- catch (Throwable e)
- {
- logger.warn( "run() exception ", e);
- recover();
- }
- }
- }
-
- /**
- * The ServiceResolver queries three times consecutively for services of
- * a given type, and then removes itself from the timer.
- * <p/>
- * The ServiceResolver will run only if JmDNS is in state ANNOUNCED.
- * REMIND: Prevent having multiple service resolvers for the same type in the
- * timer queue.
- */
- private class ServiceResolver extends TimerTask
- {
- /**
- * Counts the number of queries being sent.
- */
- int count = 0;
- private String type;
-
- public ServiceResolver(String type)
- {
- this.type = type;
- }
-
- public void start()
- {
- timer.schedule(this,
- DNSConstants.QUERY_WAIT_INTERVAL,
- DNSConstants.QUERY_WAIT_INTERVAL);
- }
-
- @Override
- public void run()
- {
- try
- {
- if (state == DNSState.ANNOUNCED)
- {
- if (count++ < 3)
- {
- if (logger.isDebugEnabled())
- logger.debug("run() JmDNS querying service");
- long now = System.currentTimeMillis();
- DNSOutgoing out =
- new DNSOutgoing(DNSConstants.FLAGS_QR_QUERY);
- out.addQuestion(
- new DNSQuestion(
- type,
- DNSConstants.TYPE_PTR,
- DNSConstants.CLASS_IN));
- for (Iterator<ServiceInfo> s = services.values().iterator(); s.hasNext();)
- {
- final ServiceInfo info = s.next();
- try
- {
- out.addAnswer(
- new DNSRecord.Pointer(
- info.type,
- DNSConstants.TYPE_PTR,
- DNSConstants.CLASS_IN,
- DNSConstants.DNS_TTL,
- info.getQualifiedName()), now);
- }
- catch (IOException ee)
- {
- break;
- }
- }
- send(out);
- }
- else
- {
- // After three queries, we can quit.
- this.cancel();
- }
- }
- else
- {
- if (state == DNSState.CANCELED)
- {
- this.cancel();
- }
- }
- }
- catch (Throwable e)
- {
- logger.warn( "run() exception ", e);
- recover();
- }
- }
- }
-
- /**
- * The ServiceInfoResolver queries up to three times consecutively for
- * a service info, and then removes itself from the timer.
- * <p/>
- * The ServiceInfoResolver will run only if JmDNS is in state ANNOUNCED.
- * REMIND: Prevent having multiple service resolvers for the same info in the
- * timer queue.
- */
- private class ServiceInfoResolver extends TimerTask
- {
- /**
- * Counts the number of queries being sent.
- */
- int count = 0;
- private ServiceInfo info;
-
- public ServiceInfoResolver(ServiceInfo info)
- {
- this.info = info;
- info.dns = JmDNS.this;
- addListener(info,
- new DNSQuestion(
- info.getQualifiedName(),
- DNSConstants.TYPE_ANY,
- DNSConstants.CLASS_IN));
- }
-
- public void start()
- {
- timer.schedule(this,
- DNSConstants.QUERY_WAIT_INTERVAL,
- DNSConstants.QUERY_WAIT_INTERVAL);
- }
-
- @Override
- public void run()
- {
- try
- {
- if (state == DNSState.ANNOUNCED)
- {
- if (count++ < 3 && !info.hasData())
- {
- long now = System.currentTimeMillis();
- DNSOutgoing out =
- new DNSOutgoing(DNSConstants.FLAGS_QR_QUERY);
- out.addQuestion(
- new DNSQuestion(
- info.getQualifiedName(),
- DNSConstants.TYPE_SRV,
- DNSConstants.CLASS_IN));
- out.addQuestion(
- new DNSQuestion(
- info.getQualifiedName(),
- DNSConstants.TYPE_TXT,
- DNSConstants.CLASS_IN));
- if (info.server != null)
- {
- out.addQuestion(
- new DNSQuestion(
- info.server,
- DNSConstants.TYPE_A,
- DNSConstants.CLASS_IN));
- }
- out.addAnswer((DNSRecord) cache.get(
- info.getQualifiedName(),
- DNSConstants.TYPE_SRV,
- DNSConstants.CLASS_IN), now);
- out.addAnswer((DNSRecord) cache.get(
- info.getQualifiedName(),
- DNSConstants.TYPE_TXT,
- DNSConstants.CLASS_IN), now);
- if (info.server != null)
- {
- out.addAnswer((DNSRecord) cache.get(
- info.server,
- DNSConstants.TYPE_A,
- DNSConstants.CLASS_IN), now);
- }
- send(out);
- }
- else
- {
- // After three queries, we can quit.
- this.cancel();
- removeListener(info);
- }
- }
- else
- {
- if (state == DNSState.CANCELED)
- {
- this.cancel();
- removeListener(info);
- }
- }
- }
- catch (Throwable e)
- {
- logger.warn( "run() exception ", e);
- recover();
- }
- }
- }
-
- /**
- * The Canceler sends two announces with TTL=0 for the specified services.
- */
- /* TODO: Clarify whether 2 or 3 announces should be sent. The header says 2,
- * run() uses the (misleading) ++count < 3 (while all other tasks use count++ < 3)
- * and the comment in the else block in run() says: "After three successful..."
- */
- public class Canceler extends TimerTask
- {
- /**
- * Counts the number of announces being sent.
- */
- int count = 0;
- /**
- * The services that need cancelling.
- * Note: We have to use a local variable here, because the services
- * that are canceled, are removed immediately from variable JmDNS.services.
- */
- private ServiceInfo[] infos;
- /**
- * We call notifyAll() on the lock object, when we have canceled the
- * service infos.
- * This is used by method JmDNS.unregisterService() and
- * JmDNS.unregisterAllServices, to ensure that the JmDNS
- * socket stays open until the Canceler has canceled all services.
- * <p/>
- * Note: We need this lock, because ServiceInfos do the transition from
- * state ANNOUNCED to state CANCELED before we get here. We could get
- * rid of this lock, if we added a state named CANCELLING to DNSState.
- */
- private Object lock;
- int ttl = 0;
-
- public Canceler(ServiceInfo info, Object lock)
- {
- this.infos = new ServiceInfo[]{info};
- this.lock = lock;
- addListener(info,
- new DNSQuestion(
- info.getQualifiedName(),
- DNSConstants.TYPE_ANY,
- DNSConstants.CLASS_IN));
- }
-
- public Canceler(ServiceInfo[] infos, Object lock)
- {
- this.infos = infos;
- this.lock = lock;
- }
-
- public Canceler(Collection<ServiceInfo> infos, Object lock)
- {
- this.infos = infos.toArray(new ServiceInfo[infos.size()]);
- this.lock = lock;
- }
-
- public void start()
- {
- timer.schedule(this, 0, DNSConstants.ANNOUNCE_WAIT_INTERVAL);
- }
-
- @Override
- public void run()
- {
- try
- {
- if (++count < 3)
- {
- if (logger.isDebugEnabled())
- logger.debug("run() JmDNS canceling service");
- // announce the service
- //long now = System.currentTimeMillis();
- DNSOutgoing out =
- new DNSOutgoing(
- DNSConstants.FLAGS_QR_RESPONSE | DNSConstants.FLAGS_AA);
- for (int i = 0; i < infos.length; i++)
- {
- ServiceInfo info = infos[i];
- out.addAnswer(
- new DNSRecord.Pointer(
- info.type,
- DNSConstants.TYPE_PTR,
- DNSConstants.CLASS_IN,
- ttl,
- info.getQualifiedName()), 0);
- out.addAnswer(
- new DNSRecord.Service(
- info.getQualifiedName(),
- DNSConstants.TYPE_SRV,
- DNSConstants.CLASS_IN,
- ttl,
- info.priority,
- info.weight,
- info.port,
- localHost.getName()), 0);
- out.addAnswer(
- new DNSRecord.Text(
- info.getQualifiedName(),
- DNSConstants.TYPE_TXT,
- DNSConstants.CLASS_IN,
- ttl,
- info.text), 0);
- DNSRecord answer = localHost.getDNS4AddressRecord();
- if (answer != null)
- {
- out.addAnswer(answer, 0);
- }
- answer = localHost.getDNS6AddressRecord();
- if (answer != null)
- {
- out.addAnswer(answer, 0);
- }
- }
- send(out);
- }
- else
- {
- // After three successful announcements, we are finished.
- synchronized (lock)
- {
- closed=true;
- lock.notifyAll();
- }
- this.cancel();
- }
- }
- catch (Throwable e)
- {
- logger.warn( "run() exception ", e);
- recover();
- }
- }
- }
-
- /**
- * Recover jmdns when there is an error.
- */
- protected void recover()
- {
- if (logger.isDebugEnabled())
- logger.debug("recover()");
- // We have an IO error so lets try to recover if anything happens lets close it.
- // This should cover the case of the IP address changing under our feet
- if (DNSState.CANCELED != state)
- {
- synchronized (this)
- { // Synchronize only if we are not already in process to prevent dead locks
- //
- if (logger.isDebugEnabled())
- logger.debug("recover() Cleanning up");
- // Stop JmDNS
- state = DNSState.CANCELED; // This protects against recursive calls
-
- // We need to keep a copy for reregistration
- Collection<ServiceInfo> oldServiceInfos = new ArrayList<ServiceInfo>(services.values());
-
- // Cancel all services
- unregisterAllServices();
- disposeServiceCollectors();
- //
- // close multicast socket
- closeMulticastSocket();
- //
- cache.clear();
- if (logger.isDebugEnabled())
- logger.debug("recover() All is clean");
- //
- // All is clear now start the services
- //
- try
- {
- openMulticastSocket(localHost);
- start(oldServiceInfos);
- }
- catch (Exception exception)
- {
- logger.warn(
- "recover() Start services exception ", exception);
- }
- logger.warn( "recover() We are back!");
- }
- }
- }
-
- /**
- * Close down jmdns. Release all resources and unregister all services.
- */
- public void close()
- {
- if (state != DNSState.CANCELED)
- {
- synchronized (this)
- { // Synchronize only if we are not already in process to prevent dead locks
- // Stop JmDNS
- state = DNSState.CANCELED; // This protects against recursive calls
-
- unregisterAllServices();
- disposeServiceCollectors();
-
- // close socket
- closeMulticastSocket();
-
- // Stop the timer
- timer.cancel();
- }
- }
- }
-
- /**
- * List cache entries, for debugging only.
- */
- void print()
- {
- if (logger.isInfoEnabled())
- logger.info("---- cache ----\n");
- cache.print();
- if (logger.isInfoEnabled())
- logger.info("\n");
- }
-
- /**
- * List Services and serviceTypes.
- * Debugging Only
- */
-
- public void printServices()
- {
- if (logger.isInfoEnabled())
- logger.info(toString());
- }
-
- @Override
- public String toString()
- {
- StringBuffer aLog = new StringBuffer();
- aLog.append("\t---- Services -----");
- if (services != null)
- {
- for (Map.Entry<String, ServiceInfo> entry : services.entrySet())
- {
- aLog.append("\n\t\tService: " + entry.getKey() + ": "
- + entry.getValue());
- }
- }
- aLog.append("\n");
- aLog.append("\t---- Types ----");
- if (serviceTypes != null)
- {
- for (Map.Entry<String, String> entry : serviceTypes.entrySet())
- {
- aLog.append("\n\t\tType: " + entry.getKey() + ": "
- + entry.getValue());
- }
- }
- aLog.append("\n");
- aLog.append(cache.toString());
- aLog.append("\n");
- aLog.append("\t---- Service Collectors ----");
- if (serviceCollectors != null)
- {
- synchronized (serviceCollectors)
- {
- for (Map.Entry<String, ServiceCollector> entry
- : serviceCollectors.entrySet())
- {
- aLog.append("\n\t\tService Collector: " + entry.getKey()
- + ": " + entry.getValue());
- }
- serviceCollectors.clear();
- }
- }
- return aLog.toString();
- }
-
- /**
- * Returns a list of service infos of the specified type.
- *
- * @param type Service type name, such as <code>_http._tcp.local.</code>.
- * @return An array of service instance names.
- */
- public ServiceInfo[] list(String type)
- {
- // Implementation note: The first time a list for a given type is
- // requested, a ServiceCollector is created which collects service
- // infos. This greatly speeds up the performance of subsequent calls
- // to this method. The caveats are, that 1) the first call to this method
- // for a given type is slow, and 2) we spawn a ServiceCollector
- // instance for each service type which increases network traffic a
- // little.
-
- ServiceCollector collector;
-
- boolean newCollectorCreated;
- synchronized (serviceCollectors)
- {
- collector = serviceCollectors.get(type);
- if (collector == null)
- {
- collector = new ServiceCollector(type);
- serviceCollectors.put(type, collector);
- addServiceListener(type, collector);
- newCollectorCreated = true;
- }
- else
- {
- newCollectorCreated = false;
- }
- }
-
- // After creating a new ServiceCollector, we collect service infos for
- // 200 milliseconds. This should be enough time, to get some service
- // infos from the network.
- if (newCollectorCreated)
- {
- try
- {
- Thread.sleep(200);
- }
- catch (InterruptedException e)
- {
- }
- }
-
- return collector.list();
- }
-
- /**
- * This method disposes all ServiceCollector instances which have been
- * created by calls to method <code>list(type)</code>.
- *
- * @see #list
- */
- private void disposeServiceCollectors()
- {
- if (logger.isDebugEnabled())
- logger.debug("disposeServiceCollectors()");
- synchronized (serviceCollectors)
- {
- for (Iterator<ServiceCollector> i = serviceCollectors.values().iterator(); i.hasNext();)
- {
- ServiceCollector collector = i.next();
- removeServiceListener(collector.type, collector);
- }
- serviceCollectors.clear();
- }
- }
-
- /**
- * Instances of ServiceCollector are used internally to speed up the
- * performance of method <code>list(type)</code>.
- *
- * @see #list
- */
- private static class ServiceCollector implements ServiceListener
- {
-
- /**
- * A set of collected service instance names.
- */
- private Map<String, ServiceInfo> infos = Collections.synchronizedMap(new HashMap<String, ServiceInfo>());
-
- public String type;
-
- public ServiceCollector(String type)
- {
- this.type = type;
- }
-
- /**
- * A service has been added.
- */
- public void serviceAdded(ServiceEvent event)
- {
- synchronized (infos)
- {
- event.getDNS().requestServiceInfo(
- event.getType(), event.getName(), 0);
- }
- }
-
- /**
- * A service has been removed.
- */
- public void serviceRemoved(ServiceEvent event)
- {
- synchronized (infos)
- {
- infos.remove(event.getName());
- }
- }
-
- /**
- * A service hase been resolved. Its details are now available in the
- * ServiceInfo record.
- */
- public void serviceResolved(ServiceEvent event)
- {
- synchronized (infos)
- {
- infos.put(event.getName(), event.getInfo());
- }
- }
-
- /**
- * Returns an array of all service infos which have been collected by this
- * ServiceCollector.
- * @return
- */
- public ServiceInfo[] list()
- {
- synchronized (infos)
- {
- return infos.values().
- toArray(new ServiceInfo[infos.size()]);
- }
- }
-
- @Override
- public String toString()
- {
- StringBuffer aLog = new StringBuffer();
- synchronized (infos)
- {
- for (Map.Entry<String, ServiceInfo> entry : infos.entrySet())
- {
- aLog.append("\n\t\tService: " + entry.getKey() + ": "
- + entry.getValue());
- }
- }
- return aLog.toString();
- }
- };
-
- private static String toUnqualifiedName(String type, String qualifiedName)
- {
- if (qualifiedName.endsWith(type))
- {
- return qualifiedName.substring(0,
- qualifiedName.length() - type.length() - 1);
- }
- else
- {
- return qualifiedName;
- }
- }
-
- /**
- * SC-Bonjour Implementation : Method used to update the corresponding DNS
- * entry in the cache of JmDNS with the new information in this ServiceInfo.
- * A call to getLocalService must first be issued to get the
- * ServiceInfo object to be modified.
- * THIS METHOD MUST BE USED INSTEAD OF ANY DIRECT ACCESS TO JMDNS' CACHE!!
- * This is used in the implementation of Zeroconf in SIP Communicator
- * to be able to change fields declared by the local contact (status, etc).
- * @param info Updated service data to be used to replace the old
- * stuff contained in JmDNS' cache
- * @param old info bytes
- */
- public void updateInfos(ServiceInfo info, byte[] old)
- {
-
- DNSOutgoing out, out2;
- synchronized (JmDNS.this)
- {
- //list = new ArrayList(services.values());
- services.put(info.getQualifiedName().toLowerCase(), info);
- }
-
- synchronized (info)
- {
- if (logger.isDebugEnabled())
- logger.debug("updateInfos() JmDNS updating " +
- info.getQualifiedName() + " state " +
- info.getState());
-
- out = new DNSOutgoing(
- /*DNSConstants.FLAGS_QR_RESPONSE*/
- DNSConstants.FLAGS_RA | DNSConstants.FLAGS_AA);
- out2 = new DNSOutgoing(
- /*DNSConstants.FLAGS_QR_RESPONSE*/
- DNSConstants.FLAGS_RA | DNSConstants.FLAGS_AA);
-
-
- try
- {
- //out.addAnswer(new DNSRecord.Pointer(info.type, DNSConstants.TYPE_PTR, DNSConstants.CLASS_IN, DNSConstants.DNS_TTL, info.getQualifiedName()), 0);
- //out.addAnswer(new DNSRecord.Service(info.getQualifiedName(), DNSConstants.TYPE_A, DNSConstants.CLASS_IN | DNSConstants.CLASS_UNIQUE, DNSConstants.DNS_TTL, info.priority, info.weight, info.port, localHost.getName()), 0);
- //out.addAnswer(new DNSRecord.Service(info.getQualifiedName(), DNSConstants.TYPE_SRV, DNSConstants.CLASS_IN | DNSConstants.CLASS_UNIQUE, DNSConstants.DNS_TTL, info.priority, info.weight, info.port, localHost.getName()), 0);
-// out.addAnswer(
-// new DNSRecord.Text(
-// info.getQualifiedName(),
-// DNSConstants.TYPE_TXT,
-// DNSConstants.CLASS_IN ,
-// DNSConstants.DNS_TTL,
-// info.text), 0);
- out.addAnswer(
- new DNSRecord.Text(
- info.getQualifiedName(),
- DNSConstants.TYPE_TXT,
- DNSConstants.CLASS_IN ,
- 0,
- old), 0);
- out.addAnswer(
- new DNSRecord.Text(
- info.getQualifiedName(),
- DNSConstants.TYPE_TXT,
- DNSConstants.CLASS_IN | DNSConstants.CLASS_UNIQUE,
- DNSConstants.DNS_TTL,
- info.text), 0);
-
- out2.addAnswer(
- new DNSRecord.Text(
- info.getQualifiedName(),
- DNSConstants.TYPE_TXT,
- DNSConstants.CLASS_IN | DNSConstants.CLASS_UNIQUE,
- DNSConstants.DNS_TTL,
- info.text), 0);
-
- if (logger.isDebugEnabled())
- logger.debug("updateInfos() JmDNS updated infos for "+info);
-
- send(out);
- Thread.sleep(1000);
- send(out2);
- Thread.sleep(2000);
- send(out2);
- }
- catch( Exception e)
- {
- logger.warn( "", e);
- }
- }
- }
-
-
- /**
- * SC-Bonjour Implementation: Method to retrieve the DNS Entry corresponding to a service
- * that has been declared and return it as a ServiceInfo structure.
- * It is used in the implementation of Bonjour in SIP Communicator to retrieve the information
- * concerning the service declared by the local contact. THIS METHOD MUST BE USED INSTEAD OF ANY
- * LOCAL COPY SAVED BEFORE SERVICE REGISTRATION!!
- * @return information corresponding to the specified service
- * @param FQN String representing the Fully Qualified name of the service we want info about
- */
- public ServiceInfo getLocalService(String FQN)
- {
- return services.get(FQN);
- }
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/ServiceEvent.java b/src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/ServiceEvent.java
deleted file mode 100644
index ff922d1..0000000
--- a/src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/ServiceEvent.java
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright 2003-2005 Arthur van Hoff Rick Blair
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.zeroconf.jmdns;
-
-import java.util.*;
-import java.util.logging.*;
-
-/**
- * ServiceEvent.
- *
- * @author Werner Randelshofer, Rick Blair
- * @version %I%, %G%
- */
-public class ServiceEvent
- extends EventObject
-{
- private static Logger logger =
- Logger.getLogger(ServiceEvent.class.toString());
- /**
- * The type name of the service.
- */
- private String type;
- /**
- * The instance name of the service. Or null, if the event was
- * fired to a service type listener.
- */
- private String name;
- /**
- * The service info record, or null if the service could be be resolved.
- * This is also null, if the event was fired to a service type listener.
- */
- private ServiceInfo info;
-
- /**
- * Creates a new instance.
- *
- * @param source the JmDNS instance which originated the event.
- * @param type the type name of the service.
- * @param name the instance name of the service.
- * @param info the service info record, or null if the
- * service could be be resolved.
- */
- public ServiceEvent(JmDNS source, String type, String name, ServiceInfo info)
- {
- super(source);
- this.type = type;
- this.name = name;
- this.info = info;
-
- String SLevel = System.getProperty("jmdns.debug");
- if (SLevel == null) SLevel = "INFO";
- logger.setLevel(Level.parse(SLevel));
- }
-
- /**
- * Returns the JmDNS instance which originated the event.
- * @return Returns the JmDNS instance which originated the event.
- */
- public JmDNS getDNS()
- {
- return (JmDNS) getSource();
- }
-
- /**
- * Returns the fully qualified type of the service.
- * @return Returns the fully qualified type of the service.
- */
- public String getType()
- {
- return type;
- }
-
- /**
- * Returns the instance name of the service.
- * Always returns null, if the event is sent to a service type listener.
- * @return Returns the instance name of the service.
- */
- public String getName()
- {
- return name;
- }
-
- /**
- * Returns the service info record, or null if the service could not be
- * resolved.
- * Always returns null, if the event is sent to a service type listener.
- * @return Returns the service info record.
- */
- public ServiceInfo getInfo()
- {
- return info;
- }
-
- @Override
- public String toString()
- {
- StringBuffer buf = new StringBuffer();
- buf.append("<" + getClass().getName() + "> ");
- buf.append(super.toString());
- buf.append(" name ");
- buf.append(getName());
- buf.append(" type ");
- buf.append(getType());
- buf.append(" info ");
- buf.append(getInfo());
- return buf.toString();
- }
-
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/ServiceInfo.java b/src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/ServiceInfo.java
deleted file mode 100644
index b7f7f2d..0000000
--- a/src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/ServiceInfo.java
+++ /dev/null
@@ -1,785 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright 2003-2005 Arthur van Hoff Rick Blair
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.zeroconf.jmdns;
-
-import java.io.*;
-import java.net.*;
-import java.util.*;
-import java.util.logging.*;
-
-/**
- * JmDNS service information.
- *
- * @version %I%, %G%
- * @author Arthur van Hoff, Jeff Sonstein, Werner Randelshofer
- * @author Christian Vincenot
- */
-public class ServiceInfo implements DNSListener
-{
- private static Logger logger =
- Logger.getLogger(ServiceInfo.class.toString());
- public final static byte[] NO_VALUE = new byte[0];
- JmDNS dns;
-
- // State machine
- /**
- * The state of this service info.
- * This is used only for services announced by JmDNS.
- * <p/>
- * For proper handling of concurrency, this variable must be
- * changed only using methods advanceState(), revertState() and cancel().
- */
- private DNSState state = DNSState.PROBING_1;
-
- /**
- * Task associated to this service info.
- * Possible tasks are JmDNS.Prober, JmDNS.Announcer, JmDNS.Responder,
- * JmDNS.Canceler.
- */
- TimerTask task;
-
- String type;
- private String name;
- String server;
- int port;
- int weight;
- int priority;
- byte text[];
- private Map<String, Object> props;
- InetAddress addr;
-
-
- /**
- * Construct a service description for registrating with JmDNS.
- *
- * @param type fully qualified service type name,
- * such as <code>_http._tcp.local.</code>.
- * @param name unqualified service instance name,
- * such as <code>foobar</code>
- * @param port the local port on which the service runs
- * @param text string describing the service
- */
- public ServiceInfo(String type, String name, int port, String text)
- {
- this(type, name, port, 0, 0, text);
- }
-
- /**
- * Construct a service description for registrating with JmDNS.
- *
- * @param type fully qualified service type name,
- * such as <code>_http._tcp.local.</code>.
- * @param name unqualified service instance name,
- * such as <code>foobar</code>
- * @param port the local port on which the service runs
- * @param weight weight of the service
- * @param priority priority of the service
- * @param text string describing the service
- */
- public ServiceInfo(String type, String name,
- int port, int weight,
- int priority, String text)
- {
- this(type, name, port, weight, priority, (byte[]) null);
- try
- {
- ByteArrayOutputStream out = new ByteArrayOutputStream(text.length());
- writeUTF(out, text);
- this.text = out.toByteArray();
- }
- catch (IOException e)
- {
- throw new RuntimeException("unexpected exception: " + e);
- }
- }
-
- /**
- * Construct a service description for registrating with JmDNS. The properties hashtable must
- * map property names to either Strings or byte arrays describing the property values.
- *
- * @param type fully qualified service type name, such as <code>_http._tcp.local.</code>.
- * @param name unqualified service instance name, such as <code>foobar</code>
- * @param port the local port on which the service runs
- * @param weight weight of the service
- * @param priority priority of the service
- * @param props properties describing the service
- */
- public ServiceInfo(String type, String name,
- int port, int weight,
- int priority, Map<String, Object> props)
- {
- this(type, name, port, weight, priority, new byte[0]);
- if (props != null)
- {
- try
- {
- ByteArrayOutputStream out = new ByteArrayOutputStream(256);
- for (Map.Entry<String, Object> prop : props.entrySet())
- {
- String key = prop.getKey();
- Object val = prop.getValue();
- ByteArrayOutputStream out2 = new ByteArrayOutputStream(100);
- writeUTF(out2, key);
- if (val instanceof String)
- {
- out2.write('=');
- writeUTF(out2, (String) val);
- }
- else
- {
- if (val instanceof byte[])
- {
- out2.write('=');
- byte[] bval = (byte[]) val;
- out2.write(bval, 0, bval.length);
- }
- else
- {
- if (val != NO_VALUE)
- {
- throw new IllegalArgumentException(
- "invalid property value: " + val);
- }
- }
- }
- byte data[] = out2.toByteArray();
- out.write(data.length);
- out.write(data, 0, data.length);
- }
- this.text = out.toByteArray();
- }
- catch (IOException e)
- {
- throw new RuntimeException("unexpected exception: " + e);
- }
- }
- }
-
- /**
- * Construct a service description for registrating with JmDNS.
- *
- * @param type fully qualified service type name,
- * such as <code>_http._tcp.local.</code>.
- * @param name unqualified service instance name,
- * such as <code>foobar</code>
- * @param port the local port on which the service runs
- * @param weight weight of the service
- * @param priority priority of the service
- * @param text bytes describing the service
- */
- public ServiceInfo(String type, String name,
- int port, int weight,
- int priority, byte text[])
- {
- this.type = type;
- this.name = name;
- this.port = port;
- this.weight = weight;
- this.priority = priority;
- this.text = text;
-
- String SLevel = System.getProperty("jmdns.debug");
- if (SLevel == null) SLevel = "INFO";
- logger.setLevel(Level.parse(SLevel));
- }
-
- /**
- * Construct a service record during service discovery.
- */
- ServiceInfo(String type, String name)
- {
- if (!type.endsWith("."))
- {
- throw new IllegalArgumentException(
- "type must be fully qualified DNS name ending in '.': " + type);
- }
-
- this.type = type;
- this.name = name;
- }
-
- /**
- * During recovery we need to duplicate service info to reregister them
- */
- ServiceInfo(ServiceInfo info)
- {
- if (info != null)
- {
- this.type = info.type;
- this.name = info.name;
- this.port = info.port;
- this.weight = info.weight;
- this.priority = info.priority;
- this.text = info.text;
- }
- }
-
- /**
- * Fully qualified service type name,
- * such as <code>_http._tcp.local.</code> .
- * @return Returns fully qualified service type name.
- */
- public String getType()
- {
- return type;
- }
-
- /**
- * Unqualified service instance name,
- * such as <code>foobar</code> .
- * @return Returns unqualified service instance name.
- */
- public String getName()
- {
- return name;
- }
-
- /**
- * Sets the service instance name.
- *
- * @param name unqualified service instance name,
- * such as <code>foobar</code>
- */
- void setName(String name)
- {
- this.name = name;
- }
-
- /**
- * Fully qualified service name,
- * such as <code>foobar._http._tcp.local.</code> .
- * @return Returns fully qualified service name.
- */
- public String getQualifiedName()
- {
- return name + "." + type;
- }
-
- /**
- * Get the name of the server.
- * @return Returns name of the server.
- */
- public String getServer()
- {
- return server;
- }
-
- /**
- * Get the host address of the service (ie X.X.X.X).
- * @return Returns host address of the service.
- */
- public String getHostAddress()
- {
- return (addr != null ? addr.getHostAddress() : "");
- }
-
- public InetAddress getAddress()
- {
- return addr;
- }
-
- /**
- * Get the InetAddress of the service.
- * @return Returns the InetAddress of the service.
- */
- public InetAddress getInetAddress()
- {
- return addr;
- }
-
- /**
- * Get the port for the service.
- * @return Returns port for the service.
- */
- public int getPort()
- {
- return port;
- }
-
- /**
- * Get the priority of the service.
- * @return Returns the priority of the service.
- */
- public int getPriority()
- {
- return priority;
- }
-
- /**
- * Get the weight of the service.
- * @return Returns the weight of the service.
- */
- public int getWeight()
- {
- return weight;
- }
-
- /**
- * Get the text for the serivce as raw bytes.
- * @return Returns the text for the serivce as raw bytes.
- */
- public byte[] getTextBytes()
- {
- return text;
- }
-
- /**
- * Get the text for the service. This will interpret the text bytes
- * as a UTF8 encoded string. Will return null if the bytes are not
- * a valid UTF8 encoded string.
- * @return Returns the text for the service.
- */
- public String getTextString()
- {
- if ((text == null) ||
- (text.length == 0) ||
- ((text.length == 1) && (text[0] == 0)))
- {
- return null;
- }
- return readUTF(text, 0, text.length);
- }
-
- /**
- * Get the URL for this service. An http URL is created by
- * combining the address, port, and path properties.
- * @return Returns the URL for this service.
- */
- public String getURL()
- {
- return getURL("http");
- }
-
- /**
- * Get the URL for this service. An URL is created by
- * combining the protocol, address, port, and path properties.
- * @param protocol
- * @return Returns URL for this service.
- */
- public String getURL(String protocol)
- {
- String url = protocol + "://" + getHostAddress() + ":" + getPort();
- String path = getPropertyString("path");
- if (path != null)
- {
- if (path.indexOf("://") >= 0)
- {
- url = path;
- }
- else
- {
- url += path.startsWith("/") ? path : "/" + path;
- }
- }
- return url;
- }
-
- /**
- * Get a property of the service. This involves decoding the
- * text bytes into a property list. Returns null if the property
- * is not found or the text data could not be decoded correctly.
- * @param name
- * @return Returns property of the service as bytes.
- */
- public synchronized byte[] getPropertyBytes(String name)
- {
- return (byte[]) getProperties().get(name);
- }
-
- /**
- * Get a property of the service. This involves decoding the
- * text bytes into a property list. Returns null if the property
- * is not found, the text data could not be decoded correctly, or
- * the resulting bytes are not a valid UTF8 string.
- * @param name
- * @return Returns property of the service as string.
- */
- public synchronized String getPropertyString(String name)
- {
- byte data[] = (byte[]) getProperties().get(name);
-
- if (data == null)
- {
- return null;
- }
- if (data == NO_VALUE)
- {
- return "true";
- }
- String res = readUTF(data, 0, data.length);
-
- return res;
- }
-
- /**
- * Iterator<String> of the property names.
- * @return Iterator<String> of the property names.
- */
- public Iterator<String> getPropertyNames()
- {
- Map<String, Object> properties = getProperties();
- Iterable<String> propertyNames
- = (properties != null) ? properties.keySet() : new Vector<String>();
- return propertyNames.iterator();
- }
-
- /**
- * Write a UTF string with a length to a stream.
- */
- void writeUTF(OutputStream out, String str) throws IOException
- {
- for (int i = 0, len = str.length(); i < len; i++)
- {
- int c = str.charAt(i);
- if ((c >= 0x0001) && (c <= 0x007F))
- {
- out.write(c);
- }
- else
- {
- if (c > 0x07FF)
- {
- out.write(0xE0 | ((c >> 12) & 0x0F));
- out.write(0x80 | ((c >> 6) & 0x3F));
- out.write(0x80 | ((c >> 0) & 0x3F));
- }
- else
- {
- out.write(0xC0 | ((c >> 6) & 0x1F));
- out.write(0x80 | ((c >> 0) & 0x3F));
- }
- }
- }
- }
-
- /**
- * Read data bytes as a UTF stream.
- */
- String readUTF(byte data[], int off, int len)
- {
- StringBuffer buf = new StringBuffer();
- for (int end = off + len; off < end;)
- {
- int ch = data[off++] & 0xFF;
- switch (ch >> 4)
- {
- case 0:
- case 1:
- case 2:
- case 3:
- case 4:
- case 5:
- case 6:
- case 7:
- // 0xxxxxxx
- break;
- case 12:
- case 13:
- if (off >= len)
- {
- return null;
- }
- // 110x xxxx 10xx xxxx
- ch = ((ch & 0x1F) << 6) | (data[off++] & 0x3F);
- break;
- case 14:
- if (off + 2 >= len)
- {
- return null;
- }
- // 1110 xxxx 10xx xxxx 10xx xxxx
- ch = ((ch & 0x0f) << 12) |
- ((data[off++] & 0x3F) << 6) |
- (data[off++] & 0x3F);
- break;
- default:
- if (off + 1 >= len)
- {
- return null;
- }
- // 10xx xxxx, 1111 xxxx
- ch = ((ch & 0x3F) << 4) | (data[off++] & 0x0f);
- break;
- }
- buf.append((char) ch);
- }
- return buf.toString();
- }
-
- synchronized Map<String, Object> getProperties()
- {
- if ((props == null) && (text != null))
- {
- Map<String, Object> props = new Hashtable<String, Object>();
- int off = 0;
- while (off < text.length)
- {
- // length of the next key value pair
- int len = text[off++] & 0xFF;
- if ((len == 0) || (off + len > text.length))
- {
- props.clear();
- break;
- }
- // look for the '='
- int i = 0;
- for (; (i < len) && (text[off + i] != '='); i++)
- {
- ;
- }
-
- // get the property name
- String name = readUTF(text, off, i);
- if (name == null)
- {
- props.clear();
- break;
- }
- if (i == len)
- {
- props.put(name, NO_VALUE);
- }
- else
- {
- byte value[] = new byte[len - ++i];
- System.arraycopy(text, off + i, value, 0, len - i);
- props.put(name, value);
- off += len;
- }
- }
- this.props = props;
- }
- return props;
- }
-
-
- /**
- * JmDNS callback to update a DNS record.
- * @param rec
- */
- public void updateRecord(JmDNS jmdns, long now, DNSRecord rec)
- {
- if ((rec != null) && !rec.isExpired(now))
- {
- switch (rec.type)
- {
- case DNSConstants.TYPE_A: // IPv4
- case DNSConstants.TYPE_AAAA: // IPv6 FIXME [PJYF Oct 14 2004] This has not been tested
- if (rec.name.equals(server))
- {
- addr = ((DNSRecord.Address) rec).getAddress();
-
- }
- break;
- case DNSConstants.TYPE_SRV:
- if (rec.name.equals(getQualifiedName()))
- {
- DNSRecord.Service srv = (DNSRecord.Service) rec;
- server = srv.server;
- port = srv.port;
- weight = srv.weight;
- priority = srv.priority;
- addr = null;
- // changed to use getCache() instead - jeffs
- // updateRecord(jmdns, now, (DNSRecord)jmdns.cache.get(server, TYPE_A, CLASS_IN));
- updateRecord(jmdns,
- now,
- (DNSRecord) jmdns.getCache().get(
- server,
- DNSConstants.TYPE_A,
- DNSConstants.CLASS_IN));
- }
- break;
- case DNSConstants.TYPE_TXT:
- if (rec.name.equals(getQualifiedName()))
- {
- DNSRecord.Text txt = (DNSRecord.Text) rec;
- text = txt.text;
- }
- break;
- }
- // Future Design Pattern
- // This is done, to notify the wait loop in method
- // JmDNS.getServiceInfo(type, name, timeout);
- if (hasData() && dns != null)
- {
- dns.handleServiceResolved(this);
- dns = null;
- }
- synchronized (this)
- {
- notifyAll();
- }
- }
- }
-
- /**
- * Returns true if the service info is filled with data.
- */
- boolean hasData()
- {
- return server != null && addr != null && text != null;
- }
-
-
- // State machine
- /**
- * Sets the state and notifies all objects that wait on the ServiceInfo.
- */
- synchronized void advanceState()
- {
- state = state.advance();
- notifyAll();
- }
-
- /**
- * Sets the state and notifies all objects that wait on the ServiceInfo.
- */
- synchronized void revertState()
- {
- state = state.revert();
- notifyAll();
- }
-
- /**
- * Sets the state and notifies all objects that wait on the ServiceInfo.
- */
- synchronized void cancel()
- {
- state = DNSState.CANCELED;
- notifyAll();
- }
-
- /**
- * Returns the current state of this info.
- */
- DNSState getState()
- {
- return state;
- }
-
-
- @Override
- public int hashCode()
- {
- return getQualifiedName().hashCode();
- }
-
- @Override
- public boolean equals(Object obj)
- {
- return (obj instanceof ServiceInfo) &&
- getQualifiedName().equals(((ServiceInfo) obj).getQualifiedName());
- }
-
- public String getNiceTextString()
- {
- StringBuffer buf = new StringBuffer();
- for (int i = 0, len = text.length; i < len; i++)
- {
- if (i >= 20)
- {
- buf.append("...");
- break;
- }
- int ch = text[i] & 0xFF;
- if ((ch < ' ') || (ch > 127))
- {
- buf.append("\\0");
- buf.append(Integer.toString(ch, 8));
- }
- else
- {
- buf.append((char) ch);
- }
- }
- return buf.toString();
- }
-
- @Override
- public String toString()
- {
- StringBuffer buf = new StringBuffer();
- buf.append("service[");
- buf.append(getQualifiedName());
- buf.append(',');
- buf.append(getAddress());
- buf.append(':');
- buf.append(port);
- buf.append(',');
- buf.append(getNiceTextString());
- buf.append(']');
- return buf.toString();
- }
-
- /**
- * SC-Bonjour Implementation: Method used to set the properties of an existing ServiceInfo.
- * This is used in the implementation of Bonjour in SIP Communicator to be able to replace
- * old properties of the service we've declared to announce the local user with new properties
- * (for example in case of a status change).
- * @param props Hashtable containing all the new properties to set
- */
- public void setProps(Map<String, Object> props)
- {
- if (props != null)
- {
- try
- {
- ByteArrayOutputStream out = new ByteArrayOutputStream(256);
- for (Map.Entry<String, Object> prop : props.entrySet())
- {
- String key = prop.getKey();
- Object val = prop.getValue();
-
- ByteArrayOutputStream out2 = new ByteArrayOutputStream(100);
- writeUTF(out2, key);
- if (val instanceof String)
- {
- out2.write('=');
- writeUTF(out2, (String) val);
- }
- else
- {
- if (val instanceof byte[])
- {
- out2.write('=');
- byte[] bval = (byte[]) val;
- out2.write(bval, 0, bval.length);
- }
- else
- {
- if (val != NO_VALUE)
- {
- throw new IllegalArgumentException(
- "invalid property value: " + val);
- }
- }
- }
- byte data[] = out2.toByteArray();
- out.write(data.length);
- out.write(data, 0, data.length);
- }
- this.text = out.toByteArray();
- }
- catch (IOException e)
- {
- throw new RuntimeException("unexpected exception: " + e);
- }
- }
- }
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/ServiceListener.java b/src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/ServiceListener.java
deleted file mode 100644
index 1c34adf..0000000
--- a/src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/ServiceListener.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright 2003-2005 Arthur van Hoff Rick Blair
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.zeroconf.jmdns;
-
-import java.util.*;
-
-/**
- * Listener for service updates.
- *
- * @version %I%, %G%
- * @author Arthur van Hoff, Werner Randelshofer
- */
-public interface ServiceListener extends EventListener
-{
- /**
- * A service has been added.
- *
- * @param event The ServiceEvent providing the name and fully qualified type
- * of the service.
- */
-
- void serviceAdded(ServiceEvent event);
-
- /**
- * A service has been removed.
- *
- * @param event The ServiceEvent providing the name and fully qualified type
- * of the service.
- */
- void serviceRemoved(ServiceEvent event);
-
- /**
- * A service has been resolved. Its details are now available in the
- * ServiceInfo record.
- *
- * @param event The ServiceEvent providing the name, the fully qualified
- * type of the service, and the service info record,
- * or null if the service could not be resolved.
- */
-
- void serviceResolved(ServiceEvent event);
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/ServiceTypeListener.java b/src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/ServiceTypeListener.java
deleted file mode 100644
index 84e5c59..0000000
--- a/src/net/java/sip/communicator/impl/protocol/zeroconf/jmdns/ServiceTypeListener.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
- *
- * Copyright 2003-2005 Arthur van Hoff Rick Blair
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package net.java.sip.communicator.impl.protocol.zeroconf.jmdns;
-
-import java.util.*;
-
-/**
- * Listener for service types.
- *
- * @version %I%, %G%
- * @author Arthur van Hoff, Werner Randelshofer
- */
-public interface ServiceTypeListener extends EventListener
-{
- /**
- * A new service type was discovered.
- *
- * @param event The service event providing the fully qualified type of
- * the service.
- */
- void serviceTypeAdded(ServiceEvent event);
-}
diff --git a/src/net/java/sip/communicator/impl/protocol/zeroconf/zeroconf.provider.manifest.mf b/src/net/java/sip/communicator/impl/protocol/zeroconf/zeroconf.provider.manifest.mf
deleted file mode 100644
index 24daba0..0000000
--- a/src/net/java/sip/communicator/impl/protocol/zeroconf/zeroconf.provider.manifest.mf
+++ /dev/null
@@ -1,12 +0,0 @@
-Bundle-Activator: net.java.sip.communicator.impl.protocol.zeroconf.ZeroconfActivator
-Bundle-Name: Zeroconf Protocol Provider
-Bundle-Description: A bundle providing support for the Zeroconf protocol.
-Bundle-Vendor: jitsi.org
-Bundle-Version: 0.0.1
-Bundle-SymbolicName: net.java.sip.communicator.protocol.zeroconf
-Import-Package: org.osgi.framework,
- org.jitsi.service.configuration,
- org.jitsi.service.resources, net.java.sip.communicator.service.resources,
- net.java.sip.communicator.util,
- net.java.sip.communicator.service.protocol,
- net.java.sip.communicator.service.protocol.event