mirror of https://github.com/sipwise/jitsi.git
parent
6a4b944b94
commit
24b7926bc9
@ -0,0 +1,343 @@
|
||||
/*
|
||||
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
|
||||
*
|
||||
* Distributable under LGPL license.
|
||||
* See terms of license at gnu.org.
|
||||
*/
|
||||
package net.java.sip.communicator.impl.protocol.icq;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import net.java.sip.communicator.impl.protocol.icq.message.common.*;
|
||||
import net.java.sip.communicator.impl.protocol.icq.message.usrinfo.*;
|
||||
import net.java.sip.communicator.service.protocol.*;
|
||||
import net.java.sip.communicator.service.protocol.ServerStoredDetails.*;
|
||||
import net.kano.joscar.snac.*;
|
||||
|
||||
/**
|
||||
* @author Damian Minkov
|
||||
*/
|
||||
public class OperationSetServerStoredAccountInfoIcqImpl
|
||||
implements OperationSetServerStoredAccountInfo
|
||||
{
|
||||
private InfoRetreiver infoRetreiver = null;
|
||||
private String uin = null;
|
||||
|
||||
/**
|
||||
* The icq provider that created us.
|
||||
*/
|
||||
private ProtocolProviderServiceIcqImpl icqProvider = null;
|
||||
|
||||
|
||||
public OperationSetServerStoredAccountInfoIcqImpl
|
||||
(InfoRetreiver infoRetreiver, String uin,
|
||||
ProtocolProviderServiceIcqImpl icqProvider)
|
||||
{
|
||||
this.infoRetreiver = infoRetreiver;
|
||||
this.uin = uin;
|
||||
this.icqProvider = icqProvider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all details currently available and set for our account.
|
||||
*
|
||||
* @return a java.util.Iterator over all details currently set our
|
||||
* account.
|
||||
*/
|
||||
public Iterator getAllAvailableDetails()
|
||||
{
|
||||
return infoRetreiver.getContactDetails(uin).iterator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an iterator over all details that are instances of exactly the
|
||||
* same class as the one specified.
|
||||
*
|
||||
* @param detailClass one of the detail classes defined in the
|
||||
* ServerStoredDetails class, indicating the kind of details we're
|
||||
* interested in. <p>
|
||||
* @return a java.util.Iterator over all details of specified class.
|
||||
*/
|
||||
public Iterator getDetails(Class detailClass)
|
||||
{
|
||||
return infoRetreiver.getDetails(uin, detailClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an iterator over all details that are instances or descendants
|
||||
* of the specified class.
|
||||
*
|
||||
* @param detailClass one of the detail classes defined in the
|
||||
* ServerStoredDetails class, indicating the kind of details we're
|
||||
* interested in. <p>
|
||||
* @return a java.util.Iterator over all details that are instances or
|
||||
* descendants of the specified class.
|
||||
*/
|
||||
public Iterator getDetailsAndDescendants(Class detailClass)
|
||||
{
|
||||
return infoRetreiver.getDetailsAndDescendants(uin, detailClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* The method returns the number of instances supported for a particular
|
||||
* detail type.
|
||||
*
|
||||
* @param detailClass the class whose max instance number we'd like to
|
||||
* find out. <p>
|
||||
* @return int the maximum number of detail instances.
|
||||
*/
|
||||
public int getMaxDetailInstances(Class detailClass)
|
||||
{
|
||||
return ((int[])FullInfoCmd.supportedTypes.get(detailClass))[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all detail Class-es that the underlying implementation
|
||||
* supports setting.
|
||||
*
|
||||
* @return a java.util.Iterator over all detail classes supported by the
|
||||
* implementation.
|
||||
*/
|
||||
public Iterator getSupportedDetailTypes()
|
||||
{
|
||||
return FullInfoCmd.supportedTypes.keySet().iterator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines wheter a detail class represents a detail supported by the
|
||||
* underlying implementation or not.
|
||||
*
|
||||
* @param detailClass the class the support for which we'd like to
|
||||
* determine. <p>
|
||||
* @return true if the underlying implementation supports setting
|
||||
* details of this type and false otherwise.
|
||||
*/
|
||||
public boolean isDetailClassSupported(Class detailClass)
|
||||
{
|
||||
return FullInfoCmd.supportedTypes.get(detailClass) != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the specified detail to the list of details registered on-line
|
||||
* for this account. If such a detail already exists its max instance number
|
||||
* is consulted and if it allows it - a second instance is added or otherwise
|
||||
* and illegal argument exception is thrown. An IllegalArgumentException is
|
||||
* also thrown in case the class of the specified detail is not supported by
|
||||
* the underlying implementation, i.e. its class name was not returned by the
|
||||
* getSupportedDetailTypes() method.
|
||||
* <p>
|
||||
* @param detail the detail that we'd like registered on the server.
|
||||
* <p>
|
||||
* @throws IllegalArgumentException if such a detail already exists and its
|
||||
* max instances number has been atteined or if the underlying
|
||||
* implementation does not support setting details of the corresponding
|
||||
* class.
|
||||
* @throws OperationFailedException with code Network Failure if putting the
|
||||
* new value online has failed
|
||||
* @throws java.lang.ArrayIndexOutOfBoundsException if the number of
|
||||
* instances currently registered by the application is already equal to the
|
||||
* maximum number of supported instances (@see getMaxDetailInstances())
|
||||
*/
|
||||
public void addDetail(GenericDetail detail) throws IllegalArgumentException,
|
||||
OperationFailedException, ArrayIndexOutOfBoundsException
|
||||
{
|
||||
if(!isDetailClassSupported(detail.getClass()))
|
||||
throw new IllegalArgumentException(
|
||||
"implementation does not support such details " +
|
||||
detail.getClass());
|
||||
|
||||
Iterator iter = getDetails(detail.getClass());
|
||||
int count = 0;
|
||||
while (iter.hasNext())
|
||||
{
|
||||
count++;
|
||||
}
|
||||
|
||||
if(count >= getMaxDetailInstances(detail.getClass()))
|
||||
throw new ArrayIndexOutOfBoundsException(
|
||||
"Max count for this detail is already reached");
|
||||
|
||||
// everything is ok , so set it
|
||||
Vector change = new Vector();
|
||||
change.add(detail);
|
||||
|
||||
SuccessResponseListener responseListener = new SuccessResponseListener();
|
||||
icqProvider.getAimConnection().getInfoService().
|
||||
sendSnacRequest(new FullInfoCmd(uin, change, false), responseListener);
|
||||
responseListener.wait(2000);
|
||||
|
||||
if(!responseListener.success)
|
||||
if(responseListener.timeout)
|
||||
throw new OperationFailedException("Adding Detail Failed!",
|
||||
OperationFailedException.NETWORK_FAILURE);
|
||||
else
|
||||
throw new OperationFailedException("Adding Detail Failed!",
|
||||
OperationFailedException.GENERAL_ERROR);
|
||||
|
||||
infoRetreiver.detailsChanged(uin);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the specified detail from the list of details stored online
|
||||
* for this account.
|
||||
*
|
||||
* @param detail the detail to remove
|
||||
* @return true if the specified detail existed and was successfully
|
||||
* removed and false otherwise.
|
||||
* @throws OperationFailedException with code Network Failure if
|
||||
* removing the detail from the server has failed
|
||||
*/
|
||||
public boolean removeDetail(GenericDetail detail) throws
|
||||
OperationFailedException
|
||||
{
|
||||
// as there is no remove method for the details we will
|
||||
// set it with empty or default value
|
||||
|
||||
boolean isFound = false;
|
||||
Iterator iter = infoRetreiver.getDetails(uin, detail.getClass());
|
||||
while (iter.hasNext())
|
||||
{
|
||||
GenericDetail item = (GenericDetail) iter.next();
|
||||
if(item.getDetailDisplayName().equals(detail.getDetailDisplayName()) &&
|
||||
item.getDetailValue().equals(detail.getDetailValue()))
|
||||
{
|
||||
isFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// current detail value does not exist
|
||||
if(!isFound)
|
||||
return false;
|
||||
|
||||
Vector change = new Vector();
|
||||
change.add(detail);
|
||||
|
||||
SuccessResponseListener responseListener = new SuccessResponseListener();
|
||||
icqProvider.getAimConnection().getInfoService().
|
||||
sendSnacRequest(new FullInfoCmd(uin, change, true), responseListener);
|
||||
responseListener.wait(2000);
|
||||
|
||||
if(!responseListener.success && responseListener.timeout)
|
||||
throw new OperationFailedException("Replacing Detail Failed!",
|
||||
OperationFailedException.NETWORK_FAILURE);
|
||||
|
||||
if(responseListener.success)
|
||||
{
|
||||
infoRetreiver.detailsChanged(uin);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces the currentDetailValue detail with newDetailValue and returns
|
||||
* true if the operation was a success or false if currentDetailValue did
|
||||
* not previously exist (in this case an additional call to addDetail is
|
||||
* required).
|
||||
*
|
||||
* @param currentDetailValue the detail value we'd like to replace.
|
||||
* @param newDetailValue the value of the detail that we'd like to
|
||||
* replace currentDetailValue with.
|
||||
* @throws ClassCastException if newDetailValue is not an instance of
|
||||
* the same class as currentDetailValue.
|
||||
* @throws OperationFailedException with code Network Failure if putting
|
||||
* the new value back online has failed
|
||||
* @return boolean
|
||||
*/
|
||||
public boolean replaceDetail(GenericDetail currentDetailValue,
|
||||
GenericDetail newDetailValue) throws
|
||||
ClassCastException, OperationFailedException
|
||||
{
|
||||
if(!newDetailValue.getClass().equals(currentDetailValue.getClass()))
|
||||
throw new ClassCastException("New value to be replaced is not as the current one");
|
||||
|
||||
boolean isFound = false;
|
||||
Iterator iter = infoRetreiver.getDetails(uin, currentDetailValue.getClass());
|
||||
while (iter.hasNext())
|
||||
{
|
||||
GenericDetail item = (GenericDetail) iter.next();
|
||||
if(item.getDetailDisplayName().equals(currentDetailValue.getDetailDisplayName()) &&
|
||||
item.getDetailValue().equals(currentDetailValue.getDetailValue()))
|
||||
{
|
||||
isFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// current detail value does not exist
|
||||
if(!isFound)
|
||||
return false;
|
||||
|
||||
Vector change = new Vector();
|
||||
change.add(newDetailValue);
|
||||
|
||||
SuccessResponseListener responseListener = new SuccessResponseListener();
|
||||
icqProvider.getAimConnection().getInfoService().
|
||||
sendSnacRequest(new FullInfoCmd(uin, change, false), responseListener);
|
||||
responseListener.wait(2000);
|
||||
|
||||
if(!responseListener.success && responseListener.timeout)
|
||||
throw new OperationFailedException("Replacing Detail Failed!",
|
||||
OperationFailedException.NETWORK_FAILURE);
|
||||
|
||||
if(responseListener.success)
|
||||
{
|
||||
infoRetreiver.detailsChanged(uin);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
private class SuccessResponseListener
|
||||
implements SnacRequestListener
|
||||
{
|
||||
private boolean ran = false;
|
||||
boolean success = false;
|
||||
|
||||
private boolean timeout = false;
|
||||
|
||||
private IcqType RESPONSE_TYPE = new IcqType(0x07DA, 0x0C3F);
|
||||
private int SUCCESS_BYTE = 0x0A;
|
||||
|
||||
public void handleSent(SnacRequestSentEvent e)
|
||||
{}
|
||||
|
||||
public void handleTimeout(SnacRequestTimeoutEvent event)
|
||||
{
|
||||
timeout = true;
|
||||
|
||||
synchronized(this) {
|
||||
if (ran) return;
|
||||
ran = true;
|
||||
notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
public void handleResponse(SnacResponseEvent e)
|
||||
{
|
||||
synchronized(this) {
|
||||
if (ran) return;
|
||||
ran = true;
|
||||
|
||||
FromIcqCmd cmd = new FromIcqCmd(e.getSnacPacket());
|
||||
byte[] data = cmd.getIcqData().toByteArray();
|
||||
if (cmd.getType().equals(RESPONSE_TYPE) &&
|
||||
data.length == 1 &&
|
||||
data[0] == SUCCESS_BYTE)
|
||||
{
|
||||
success = true;
|
||||
notifyAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void wait(int milliseconds)
|
||||
{
|
||||
synchronized (this){
|
||||
if(ran) return;
|
||||
this.wait(milliseconds);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,118 @@
|
||||
/*
|
||||
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
|
||||
*
|
||||
* Distributable under LGPL license.
|
||||
* See terms of license at gnu.org.
|
||||
*/
|
||||
package net.java.sip.communicator.impl.protocol.icq.message.usrinfo;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
import net.java.sip.communicator.impl.protocol.icq.message.common.*;
|
||||
import net.kano.joscar.*;
|
||||
|
||||
/**
|
||||
* Tlv set in command for changis user account info stored on server
|
||||
* @author Damian Minkov
|
||||
*/
|
||||
public class DetailTlv
|
||||
implements Writable
|
||||
{
|
||||
private byte[] data = new byte[0];
|
||||
private int type;
|
||||
|
||||
public DetailTlv(int type)
|
||||
{
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public void write(OutputStream out)
|
||||
throws IOException
|
||||
{
|
||||
LEBinaryTools.writeUShort(out, type);
|
||||
LEBinaryTools.writeUShort(out, data.length);
|
||||
out.write(data);
|
||||
}
|
||||
|
||||
public long getWritableLength()
|
||||
{
|
||||
return 4 + data.length;
|
||||
}
|
||||
|
||||
public void writeUInt(long number)
|
||||
{
|
||||
byte[] tmp = LEBinaryTools.getUInt(number);
|
||||
byte[] newData = new byte[data.length + tmp.length];
|
||||
|
||||
System.arraycopy(data, 0, newData, 0, data.length);
|
||||
System.arraycopy(tmp, 0, newData, data.length, tmp.length);
|
||||
|
||||
data = newData;
|
||||
}
|
||||
|
||||
public void writeUShort(int number)
|
||||
{
|
||||
byte[] tmp = LEBinaryTools.getUShort(number);
|
||||
byte[] newData = new byte[data.length + tmp.length];
|
||||
|
||||
System.arraycopy(data, 0, newData, 0, data.length);
|
||||
System.arraycopy(tmp, 0, newData, data.length, tmp.length);
|
||||
|
||||
data = newData;
|
||||
}
|
||||
|
||||
public void writeUByte(int number)
|
||||
{
|
||||
byte[] tmp = LEBinaryTools.getUByte(number);
|
||||
byte[] newData = new byte[data.length + tmp.length];
|
||||
|
||||
System.arraycopy(data, 0, newData, 0, data.length);
|
||||
System.arraycopy(tmp, 0, newData, data.length, tmp.length);
|
||||
|
||||
data = newData;
|
||||
}
|
||||
|
||||
public void writeString(String str)
|
||||
{
|
||||
if(str == null)
|
||||
str = "";// empty string so length will be 0 and nothing to be writen
|
||||
|
||||
byte[] tmp = BinaryTools.getAsciiBytes(str);
|
||||
|
||||
// save the string length before we process the string bytes
|
||||
writeUShort(tmp.length);
|
||||
|
||||
byte[] newData = new byte[data.length + tmp.length];
|
||||
|
||||
System.arraycopy(data, 0, newData, 0, data.length);
|
||||
System.arraycopy(tmp, 0, newData, data.length, tmp.length);
|
||||
|
||||
data = newData;
|
||||
}
|
||||
|
||||
|
||||
public String toString()
|
||||
{
|
||||
StringBuilder result = new StringBuilder();
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
|
||||
try
|
||||
{
|
||||
write(out);
|
||||
}
|
||||
catch(IOException ex)
|
||||
{
|
||||
ex.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
|
||||
byte[] arrOut = out.toByteArray();
|
||||
for(int i = 0; i < arrOut.length; i++)
|
||||
{
|
||||
byte temp = arrOut[i];
|
||||
result.append(Integer.toHexString(temp&0xFF)).append(' ');
|
||||
}
|
||||
|
||||
return result.toString();
|
||||
}
|
||||
}
|
||||
Loading…
Reference in new issue