Added UserinInfo Implementation

cusax-fix
Damian Minkov 20 years ago
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);
}
}
}
}

@ -269,6 +269,24 @@ protected void initialize(String screenname,
OperationSetTypingNotifications.class.getName(),
typingNotifications);
InfoRetreiver infoRetreiver = new InfoRetreiver(this);
OperationSetServerStoredContactInfo serverStoredContactInfo =
new OperationSetServerStoredContactInfoIcqImpl(infoRetreiver);
supportedOperationSets.put(
OperationSetServerStoredContactInfo.class.getName(),
serverStoredContactInfo);
OperationSetServerStoredAccountInfo serverStoredAccountInfo =
new OperationSetServerStoredAccountInfoIcqImpl
(infoRetreiver, screenname, this);
supportedOperationSets.put(
OperationSetServerStoredAccountInfo.class.getName(),
serverStoredAccountInfo);
isInitialized = true;
}
}

@ -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();
}
}

@ -1518,15 +1518,14 @@ public void writeData(OutputStream out)
ByteArrayOutputStream icqout = new ByteArrayOutputStream();
ByteArrayOutputStream icqDataOut = new ByteArrayOutputStream();
byte b[] = new byte[]{
(byte)0xf8, (byte)0x02, // 0x02F8 User 'show web status' permissions
(byte)0x01, (byte)0x00, (byte)0x00,
(byte)0x0c, (byte)0x03, // 0x030C User authorization permissions
(byte)0x01, (byte)0x00, (byte)0x00
};
icqDataOut.write(b);
// new Tlv(0x030C, ByteBlock.wrap(b)).write(icqDataOut);
writeUShort(icqDataOut, 0x030c); // 0x030C User authorization permissions
writeUShort(icqDataOut, 1);
writeUByte(icqDataOut, 0);
writeUShort(icqDataOut, 0x02F8); // 0x02F8 User 'show web status' permissions
writeUShort(icqDataOut, 1);
writeUByte(icqDataOut, 0);
int hdrlen = 10; // The expected header length, not counting the length field itself.
int primary = 0x07D0;
@ -1570,6 +1569,12 @@ public void writeUShort(OutputStream out, int number)
(byte)((number >> 8) & 0xff)
});
}
public void writeUByte(OutputStream out, int number)
throws IOException
{
out.write(new byte[]{(byte) (number & 0xff)});
}
}
private static class BuddyAwaitingAuth

Loading…
Cancel
Save