001 package com.skype.api;
002
003 import com.skype.ipc.SidRoot;
004 import com.skype.ipc.SidObject;
005 import com.skype.ipc.EnumConverting;
006 import com.skype.ipc.PropertyEnumConverting;
007 import com.skype.ipc.Decoding;
008 import com.skype.ipc.Encoding;
009 import com.skype.ipc.Encoding;
010 import java.io.IOException;
011 import com.skype.ipc.PropertyEnumConverting;
012 import com.skype.ipc.SidGetResponding;
013
014 /**
015 * Transfer in this context refers to transferring (sending/receiving) files among Skype Contacts, not transferring a call to another Skype or PSTN Contact. This class includes file transfer-specific properties and methods, such as FILESIZE, BYTESPERSECOND, Pause and Resume. Recipients of these file transfers must explicitly accept (or decline) any incoming transfer. Transfer instances represent files being sent and received within a Conversation context. Each Transfer instance represents a single file transfer - if a conversation has multiple remote participants, a separate Transfer instance must be instantiated for each remote participant (a Transfer instance is not instantiated for the sender).
016 *
017 * Transfer instances cannot be instantiated directly. Instead, you initiate a file transfer by invoking Conversation.PostFiles. This instantiates a Message instance of type POSTED_FILES, which is added to the Conversation for all the participants (including the sender). The Transfer instance is associated with
018 * this Message instance, and the Message.P_BODY_XML looks like this:
019 *
020 * @code
021 * Some text<files alt=""><file size="2336020" index="0">test.zip</file></files>
022 * </CODE>
023 *
024 * To put it another way, the object chain goes like this:
025 * @code
026 * Conversation->Message->Transfer
027 * </CODE>
028 *
029 * The first part of the message (before the files section) comes from the Conversation.PostFiles body argument. For each file in the message, a file section is provided with three fields:
030 * - file size in bytes
031 * - index - more or less arbitrary order in which the transfers should be displayed in the UI
032 * - file name.
033 *
034 * For practical purposes, the Message.P_BODY_XML property is not all that useful in this context. The Transfer instances, however, contain the state and progress feedback for your UI. You retrieve these Transfer instances using Message.GetTransfers method. Since the sender can post multiple files to
035 * a Conversation using the same Message, Message:GetTransfers retrieves a list of Transfer instances - one per file per recipient.
036 *
037 * You can determine the direction of particular Transfer instance by querying Transfer.P_TYPE (INCOMING/OUTGOING).
038 *
039 * You can implement a progress indicator by monitoring Transfer.P_BYTESTRANSFERRED. Note that when testing this on your local network, you will most likely catch these property change events at the beginning and the end of the transfer only - which does not look like too useful. However, for non-local network transfers where the transfer speeds are in the neighborhood of 200-300 KB per second, you should consider implementing progress feedback as being mandatory and expect to catch multiple property change events for all but the smallest files.
040 *
041 * Another property of interest is Transfer.P_STATUS. The normal transfer status sequence during successful outgoing transfer is this:
042 * - TRANSFER STATUS -> NEW
043 * - TRANSFER STATUS -> WAITING_FOR_ACCEPT
044 * - TRANSFER STATUS -> CONNECTING
045 * - TRANSFER STATUS -> TRANSFERRING
046 * - TRANSFER STATUS -> CONNECTING
047 * - TRANSFER STATUS -> COMPLETED
048 *
049 * The list of all terminal Transfer statuses is:
050 * - COMPLETED
051 * - FAILED
052 * - CANCELLED
053 * - CANCELLED_BY_REMOTE
054 *
055 * In-progress transfers can be canceled with Transfer.Cancel and paused/resumed with Transfer.Pause and Transfer.Resume. For transfers that complete with a status of FAILED, your UI should provide feedback based on the value of Transfer.P_FAILUREREASON.
056 *
057 * Incoming transfers, once accepted, overwrite existing files with the same name. Before accepting an incoming file transfer,
058 * your UI should prompt the recipient to:
059 * - accept or decline the file
060 * - if accepted, specify the directory of here to save the file (with a pre-filled default)
061 * - if accepted and a file having the same name already exists at the specified destination, your UI should prompt for confirmation to overwrite and provide a way to alter the file name before accepting it
062 *
063 * Similarly, your UI should verify the existence of outgoing files prior to invoking Conversation.PostFiles.
064 *
065 * Note that you should provide both Conversation.PostFiles and Transfer.Accept methods fully-qualified paths. Otherwise, the paths will be assumed to be relative to the path of SkypeKit runtime, since the methods are actually executed in the runtime context.
066 */
067 public final class Transfer extends SidObject {
068 public enum Type implements EnumConverting {
069 INCOMING(1),
070 OUTGOING(2);
071 private final int key;
072 Type(int key) {
073 this.key = key;
074 };
075 public int getId() { return key; }
076 public EnumConverting getDefault() { return INCOMING; }
077 public EnumConverting convert(int from) { return Type.get(from); }
078 public EnumConverting[] getArray(final int size) { return new Type[size]; }
079 public static Type get(int from) {
080 switch (from) {
081 case 1: return INCOMING;
082 case 2: return OUTGOING;
083 }
084 return INCOMING;
085 }
086 public static final int INCOMING_VALUE = 1;
087 public static final int OUTGOING_VALUE = 2;
088 }
089 /** Recognized values for the P_STATUS property. Reflects current state of this Transfer. */
090 public enum Status implements EnumConverting {
091 /** The file has either not been posted (sent) (OUTGOING), or not accepted (received) (INCOMING). */
092 NEW (0),
093 /** A temporary state that transitions either into TRANSFERRING (relayed or direct) or to FAILED. For unknown reasons, outgoing transfers tend go into this state twice - immediately before the actual data transfer starts and immediately after it ends. */
094 CONNECTING (1),
095 /** The files have been posted but the recipient has not yet accepted (or has declined) the transfer. */
096 WAITING_FOR_ACCEPT (2),
097 /** The transfer has been accepted and file data is being sent/received. Periodic updates of P_BYTESTRANSFERRED property should occur. */
098 TRANSFERRING (3),
099 /** The transfer has been accepted and file data is being sent/received but is going over at least one relay. Since relayed transfers tend to be significantly slower than direct transfers, you might want to differentiate the two in your UI and notify the user that relayed transfer typically take significantly longer to finish. */
100 TRANSFERRING_OVER_RELAY (4),
101 /** The local user (either the sender or a receiver) has paused the transfer. */
102 PAUSED (5),
103 /** A remote user has paused the transfer. For senders, a receiver has paused the transfer; for receivers, the sender has paused the transfer. */
104 REMOTELY_PAUSED (6),
105 /** Local side (either sender or receiver) has canceled the transfer. This is a final state of the STATE property. */
106 CANCELLED (7),
107 /** File transfer has completed. This is a terminal state. */
108 COMPLETED (8),
109 /** File transfer has failed. This is a terminal state. UI should provide feedback, based on value of P_FAILUREREASON. */
110 FAILED (9),
111 /** Transfer whose existence has been hinted by corresponding chat message, but which is yet to arrive. */
112 PLACEHOLDER (10),
113 /** Outgoing transfer object from another instance of the same account as current local login, running on another system. Hinted through chat message - only implies an offer was made; not necessarily accepted, failed, or completed. */
114 OFFER_FROM_OTHER_INSTANCE(11),
115 /** Remote side (either sender or receiver) has canceled the transfer. This is a final state of the STATE property. */
116 CANCELLED_BY_REMOTE (12);
117 private final int key;
118 Status(int key) {
119 this.key = key;
120 };
121 public int getId() { return key; }
122 public EnumConverting getDefault() { return NEW; }
123 public EnumConverting convert(int from) { return Status.get(from); }
124 public EnumConverting[] getArray(final int size) { return new Status[size]; }
125 public static Status get(int from) {
126 switch (from) {
127 case 0: return NEW;
128 case 1: return CONNECTING;
129 case 2: return WAITING_FOR_ACCEPT;
130 case 3: return TRANSFERRING;
131 case 4: return TRANSFERRING_OVER_RELAY;
132 case 5: return PAUSED; case 6: return REMOTELY_PAUSED;
133 case 7: return CANCELLED;
134 case 8: return COMPLETED;
135 case 9: return FAILED;
136 case 10: return PLACEHOLDER;
137 case 11: return OFFER_FROM_OTHER_INSTANCE;
138 case 12: return CANCELLED_BY_REMOTE;
139 }
140 return NEW;
141 }
142 public static final int NEW_VALUE = 0;
143 public static final int CONNECTING_VALUE = 1;
144 public static final int WAITING_FOR_ACCEPT_VALUE = 2;
145 public static final int TRANSFERRING_VALUE = 3;
146 public static final int TRANSFERRING_OVER_RELAY_VALUE = 4;
147 public static final int PAUSED_VALUE = 5;
148 public static final int REMOTELY_PAUSED_VALUE = 6;
149 public static final int CANCELLED_VALUE = 7;
150 public static final int COMPLETED_VALUE = 8;
151 public static final int FAILED_VALUE = 9;
152 public static final int PLACEHOLDER_VALUE = 10;
153 public static final int OFFER_FROM_OTHER_INSTANCE_VALUE = 11;
154 public static final int CANCELLED_BY_REMOTE_VALUE = 12;
155 }
156 public enum FailureReason implements EnumConverting {
157 SENDER_NOT_AUTHORISED (1),
158 REMOTELY_CANCELLED (2),
159 FAILED_READ (3),
160 FAILED_REMOTE_READ (4),
161 FAILED_WRITE (5),
162 FAILED_REMOTE_WRITE (6),
163 REMOTE_DOES_NOT_SUPPORT_FT (7),
164 REMOTE_OFFLINE_FOR_TOO_LONG(8),
165 TOO_MANY_PARALLEL (9),
166 PLACEHOLDER_TIMEOUT (10);
167 private final int key;
168 FailureReason(int key) {
169 this.key = key;
170 };
171 public int getId() { return key; }
172 public EnumConverting getDefault() { return SENDER_NOT_AUTHORISED; }
173 public EnumConverting convert(int from) { return FailureReason.get(from); }
174 public EnumConverting[] getArray(final int size) { return new FailureReason[size]; }
175 public static FailureReason get(int from) {
176 switch (from) {
177 case 1: return SENDER_NOT_AUTHORISED;
178 case 2: return REMOTELY_CANCELLED;
179 case 3: return FAILED_READ;
180 case 4: return FAILED_REMOTE_READ;
181 case 5: return FAILED_WRITE;
182 case 6: return FAILED_REMOTE_WRITE;
183 case 7: return REMOTE_DOES_NOT_SUPPORT_FT;
184 case 8: return REMOTE_OFFLINE_FOR_TOO_LONG;
185 case 9: return TOO_MANY_PARALLEL;
186 case 10: return PLACEHOLDER_TIMEOUT;
187 }
188 return SENDER_NOT_AUTHORISED;
189 }
190 public static final int SENDER_NOT_AUTHORISED_VALUE = 1;
191 public static final int REMOTELY_CANCELLED_VALUE = 2;
192 public static final int FAILED_READ_VALUE = 3;
193 public static final int FAILED_REMOTE_READ_VALUE = 4;
194 public static final int FAILED_WRITE_VALUE = 5;
195 public static final int FAILED_REMOTE_WRITE_VALUE = 6;
196 public static final int REMOTE_DOES_NOT_SUPPORT_FT_VALUE = 7;
197 public static final int REMOTE_OFFLINE_FOR_TOO_LONG_VALUE = 8;
198 public static final int TOO_MANY_PARALLEL_VALUE = 9;
199 public static final int PLACEHOLDER_TIMEOUT_VALUE = 10;
200 }
201 private final static byte[] P_TYPE_req = {(byte) 90,(byte) 71,(byte) 80,(byte) 93,(byte) 6};
202 private final static byte[] P_PARTNER_HANDLE_req = {(byte) 90,(byte) 71,(byte) 81,(byte) 93,(byte) 6};
203 private final static byte[] P_PARTNER_DISPLAY_NAME_req = {(byte) 90,(byte) 71,(byte) 82,(byte) 93,(byte) 6};
204 private final static byte[] P_STATUS_req = {(byte) 90,(byte) 71,(byte) 83,(byte) 93,(byte) 6};
205 private final static byte[] P_FAILURE_REASON_req = {(byte) 90,(byte) 71,(byte) 84,(byte) 93,(byte) 6};
206 private final static byte[] P_START_TIME_req = {(byte) 90,(byte) 71,(byte) 85,(byte) 93,(byte) 6};
207 private final static byte[] P_FINISH_TIME_req = {(byte) 90,(byte) 71,(byte) 86,(byte) 93,(byte) 6};
208 private final static byte[] P_FILE_PATH_req = {(byte) 90,(byte) 71,(byte) 87,(byte) 93,(byte) 6};
209 private final static byte[] P_FILE_NAME_req = {(byte) 90,(byte) 71,(byte) 88,(byte) 93,(byte) 6};
210 private final static byte[] P_FILE_SIZE_req = {(byte) 90,(byte) 71,(byte) 89,(byte) 93,(byte) 6};
211 private final static byte[] P_BYTES_TRANSFERRED_req = {(byte) 90,(byte) 71,(byte) 90,(byte) 93,(byte) 6};
212 private final static byte[] P_BYTES_PER_SECOND_req = {(byte) 90,(byte) 71,(byte) 91,(byte) 93,(byte) 6};
213 private final static byte[] P_CHAT_MSG_GUID_req = {(byte) 90,(byte) 71,(byte) 92,(byte) 93,(byte) 6};
214 private final static byte[] P_CHAT_MSG_INDEX_req = {(byte) 90,(byte) 71,(byte) 93,(byte) 93,(byte) 6};
215 private final static byte[] P_CONVERSATION_req = {(byte) 90,(byte) 71,(byte) 98,(byte) 93,(byte) 6};
216 /** Properties of the Transfer class */
217 public enum Property implements PropertyEnumConverting {
218 P_UNKNOWN (0,0,null,0,null),
219 P_TYPE (80, 1, P_TYPE_req, 0, Type.get(0)),
220 P_PARTNER_HANDLE (81, 2, P_PARTNER_HANDLE_req, 0, null),
221 P_PARTNER_DISPLAY_NAME(82, 3, P_PARTNER_DISPLAY_NAME_req, 0, null),
222 P_STATUS (83, 4, P_STATUS_req, 0, Status.get(0)),
223 P_FAILURE_REASON (84, 5, P_FAILURE_REASON_req, 0, FailureReason.get(0)),
224 P_START_TIME (85, 6, P_START_TIME_req, 0, null),
225 P_FINISH_TIME (86, 7, P_FINISH_TIME_req, 0, null),
226 P_FILE_PATH (87, 8, P_FILE_PATH_req, 0, null),
227 P_FILE_NAME (88, 9, P_FILE_NAME_req, 0, null),
228 P_FILE_SIZE (89, 10, P_FILE_SIZE_req, 0, null),
229 P_BYTES_TRANSFERRED (90, 11, P_BYTES_TRANSFERRED_req, 0, null),
230 P_BYTES_PER_SECOND (91, 12, P_BYTES_PER_SECOND_req, 0, null),
231 P_CHAT_MSG_GUID (92, 13, P_CHAT_MSG_GUID_req, 0, null),
232 P_CHAT_MSG_INDEX (93, 14, P_CHAT_MSG_INDEX_req, 0, null),
233 P_CONVERSATION (98, 15, P_CONVERSATION_req, 18, null);
234 private final int key;
235 private final int idx;
236 private final byte[] req;
237 private final int mod;
238 private final EnumConverting enumConverter;
239 Property(int key, int idx, byte[] req, int mod, EnumConverting converter) {
240 this.key = key;
241 this.idx = idx;
242 this.req = req;
243 this.mod = mod;
244 this.enumConverter = converter;
245 };
246 public boolean isCached() { return idx > 0; }
247 public int getIdx() { return idx; }
248 public int getId() { return key; }
249 public byte[] getRequest() { return req; }
250 public EnumConverting getDefault() { return P_UNKNOWN; }
251 public int getModuleId() { return mod; }
252 public EnumConverting getEnumConverter() { return enumConverter; }
253 public EnumConverting convert(final int from) { return Property.get(from); }
254 public EnumConverting[] getArray(final int size) { return new Property[size]; }
255 public static Property get(final int from) {
256 switch (from) {
257 case 80: return P_TYPE;
258 case 81: return P_PARTNER_HANDLE;
259 case 82: return P_PARTNER_DISPLAY_NAME;
260 case 83: return P_STATUS;
261 case 84: return P_FAILURE_REASON;
262 case 85: return P_START_TIME;
263 case 86: return P_FINISH_TIME;
264 case 87: return P_FILE_PATH;
265 case 88: return P_FILE_NAME;
266 case 89: return P_FILE_SIZE;
267 case 90: return P_BYTES_TRANSFERRED;
268 case 91: return P_BYTES_PER_SECOND;
269 case 92: return P_CHAT_MSG_GUID;
270 case 93: return P_CHAT_MSG_INDEX;
271 case 98: return P_CONVERSATION;
272 }
273 return P_UNKNOWN;
274 }
275 public static final int P_TYPE_VALUE = 80;
276 public static final int P_PARTNER_HANDLE_VALUE = 81;
277 public static final int P_PARTNER_DISPLAY_NAME_VALUE = 82;
278 public static final int P_STATUS_VALUE = 83;
279 public static final int P_FAILURE_REASON_VALUE = 84;
280 public static final int P_START_TIME_VALUE = 85;
281 public static final int P_FINISH_TIME_VALUE = 86;
282 public static final int P_FILE_PATH_VALUE = 87;
283 public static final int P_FILE_NAME_VALUE = 88;
284 public static final int P_FILE_SIZE_VALUE = 89;
285 public static final int P_BYTES_TRANSFERRED_VALUE = 90;
286 public static final int P_BYTES_PER_SECOND_VALUE = 91;
287 public static final int P_CHAT_MSG_GUID_VALUE = 92;
288 public static final int P_CHAT_MSG_INDEX_VALUE = 93;
289 public static final int P_CONVERSATION_VALUE = 98;
290 }
291 private final static byte[] accept_req = {(byte) 90,(byte) 82,(byte) 6,(byte) 3};
292 /** Accepts an incoming file transfer and saves it to specified file on the local file system. If the specified file exists, SkypeKit will silently overwrite it. Your UI should prompting the user for confirmation in this case and provide a means for canceling the file transfer or specifying a different target file. * @param filenameWithPath Where on the local file system to save the file being transferred. Note that you should specify the path as being fully-qualified. Otherwise, SkypeKit will be assume it to be relative to the SkypeKit runtime path, since the method is actually executed in the runtime context. * @return success Set to true if the specified target file was successfully created on the local file system -and- the initial write(s) succeeded. However, the transfer itself can subsequently fail before completion due to its being canceled (either locally or remotely), network failure, local file system space/write issues, and so forth.
293 */
294 public boolean accept(String filenameWithPath) {
295 try {
296 return sidDoRequest(accept_req)
297 .addFilenameParm(1, filenameWithPath)
298 .endRequest().getBoolParm(1, true);
299 } catch(IOException e) {
300 mSidRoot.sidOnFatalError(e);
301 return false
302 ;}
303 }
304 private final static byte[] pause_req = {(byte) 90,(byte) 82,(byte) 6,(byte) 4};
305 /** Temporarily pauses an in-progress incoming or outgoing file transfer. For incoming transfers, only this affects the sender and the invoking recipient only. For outgoing transfers, this affects the sender and all recipients. */
306 public void pause() {
307 try {
308 sidDoRequest(pause_req)
309 .endOneWay();
310 } catch(IOException e) {
311 mSidRoot.sidOnFatalError(e);
312 }
313 }
314 private final static byte[] resume_req = {(byte) 90,(byte) 82,(byte) 6,(byte) 5};
315 /** Resumes a previously paused file transfer. */
316 public void resume() {
317 try {
318 sidDoRequest(resume_req)
319 .endOneWay();
320 } catch(IOException e) {
321 mSidRoot.sidOnFatalError(e);
322 }
323 }
324 private final static byte[] cancel_req = {(byte) 90,(byte) 82,(byte) 6,(byte) 6};
325 /** Cancels an in-progress file transfer. Transfer.STATUS will transition to CANCELLED for incoming file transfers and to CANCELLED_BY_REMOTE for outgoing transfers. */
326 public void cancel() {
327 try {
328 sidDoRequest(cancel_req)
329 .endOneWay();
330 } catch(IOException e) {
331 mSidRoot.sidOnFatalError(e);
332 }
333 }
334 /***
335 * generic multiget of a list of Property
336 * @param requested the list of requested properties of Transfer
337 * @return SidGetResponding
338 */
339 public SidGetResponding sidMultiGet(Property[] requested) {
340 return super.sidMultiGet(requested);
341 }
342 /***
343 * generic multiget of list of Property for a list of Transfer
344 * @param requested the list of requested properties
345 * @return SidGetResponding[] can be casted to (Transfer[]) if all properties are cached
346 */
347 static public SidGetResponding[] sidMultiGet(Property[] requested, Transfer[] objects) {
348 return SidObject.sidMultiGet(requested, objects);
349 }
350 /** INCOMING / OUTGOING */
351 public Type getType() {
352 synchronized(this) {
353 if ((mSidCached & 0x1) != 0)
354 return mType;
355 }
356 return (Type) sidRequestEnumProperty(Property.P_TYPE);
357 }
358 /** Skype Name of the remote party of the file transfer. If a file is posted in a conversation with more than one participant, Transfer objects are created for each of them - so a transfer is always to one single remote target. */
359 public String getPartnerHandle() {
360 synchronized(this) {
361 if ((mSidCached & 0x2) != 0)
362 return mPartnerHandle;
363 }
364 return sidRequestStringProperty(Property.P_PARTNER_HANDLE);
365 }
366 /** Display name of the remote participant. */
367 public String getPartnerDisplayName() {
368 synchronized(this) {
369 if ((mSidCached & 0x4) != 0)
370 return mPartnerDisplayName;
371 }
372 return sidRequestStringProperty(Property.P_PARTNER_DISPLAY_NAME);
373 }
374 /** Current state of the transfer */
375 public Status getStatus() {
376 synchronized(this) {
377 if ((mSidCached & 0x8) != 0)
378 return mStatus;
379 }
380 return (Status) sidRequestEnumProperty(Property.P_STATUS);
381 }
382 /** Set whenever P_STATUS transitions to FAILED. */
383 public FailureReason getFailureReason() {
384 synchronized(this) {
385 if ((mSidCached & 0x10) != 0)
386 return mFailureReason;
387 }
388 return (FailureReason) sidRequestEnumProperty(Property.P_FAILURE_REASON);
389 }
390 /** UNIX timestamp of when this Transfer instance was instantiated, not when the transfer process actually started (was accepted from receiver side). Do not use this property when calculate the data transfer speed! Instead, monitor changes to P_BYTESPERSECOND. */
391 public int getStartTime() {
392 synchronized(this) {
393 if ((mSidCached & 0x20) != 0)
394 return mStartTime;
395 }
396 return sidRequestUintProperty(Property.P_START_TIME);
397 }
398 /** UNIX timestamp of when this Transfer COMPLETED or FAILED. This property is never set if the receiving side (local or remote) canceled the transfer. */
399 public int getFinishTime() {
400 synchronized(this) {
401 if ((mSidCached & 0x40) != 0)
402 return mFinishTime;
403 }
404 return sidRequestUintProperty(Property.P_FINISH_TIME);
405 }
406 /** The path -and- filename of the file being transfered (typically fully qualified). For the receiver, SkypeKit sets this property upon acceptance of the incoming transfer. If not fully qualified, the path is assumed to be relative to the path of the SkypeKit runtime. */
407 public String getFilePath() {
408 synchronized(this) {
409 if ((mSidCached & 0x80) != 0)
410 return mFilePath;
411 }
412 return sidRequestStringProperty(Property.P_FILE_PATH);
413 }
414 /** The filename -only- of the file being transfered. The receiver side can use this property to pre-populate relevant UI components while prompting the user to accept the incoming transfer. */
415 public String getFileName() {
416 synchronized(this) {
417 if ((mSidCached & 0x100) != 0)
418 return mFileName;
419 }
420 return sidRequestStringProperty(Property.P_FILE_NAME);
421 }
422 /** The size of the file being transferred in bytes. Depending on the magnitude of this value, your UI might want to display the size in terms of kilobytes or even megabytes. */
423 public String getFileSize() {
424 synchronized(this) {
425 if ((mSidCached & 0x200) != 0)
426 return mFileSize;
427 }
428 return sidRequestStringProperty(Property.P_FILE_SIZE);
429 }
430 /**
431 * The number of bytes already transferred. Calculate the percentage of the file transferred so far as:
432 * @code
433 * P_BYTESTRANSFERRED / (P_FILESIZE / 100);
434 * </CODE>
435 *
436 * Use float variables to avoid problems with files smaller than 100 bytes!
437 */
438 public String getBytesTransferred() {
439 synchronized(this) {
440 if ((mSidCached & 0x400) != 0)
441 return mBytesTransferred;
442 }
443 return sidRequestStringProperty(Property.P_BYTES_TRANSFERRED);
444 }
445 /** Current data transfer speed in bytes per second. Typically, your UI will want to display this value as kilobytes per second (KBps). */
446 public int getBytesPerSecond() {
447 synchronized(this) {
448 if ((mSidCached & 0x800) != 0)
449 return mBytesPerSecond;
450 }
451 return sidRequestUintProperty(Property.P_BYTES_PER_SECOND);
452 }
453 /** The "global ID" of this Transfer's associated Message instance. GUIDs are shared across Skype client instances and across all users that can see this Message. */
454 public byte[] getChatMsgGuid() {
455 synchronized(this) {
456 if ((mSidCached & 0x1000) != 0)
457 return mChatMsgGuid;
458 }
459 return sidRequestBinaryProperty(Property.P_CHAT_MSG_GUID);
460 }
461 /** A more or less arbitrary index for ordering multiple file transfers within the UI. */
462 public int getChatMsgIndex() {
463 synchronized(this) {
464 if ((mSidCached & 0x2000) != 0)
465 return mChatMsgIndex;
466 }
467 return sidRequestUintProperty(Property.P_CHAT_MSG_INDEX);
468 }
469 /**
470 * The "global ID" of this Transfer's associated Conversation (as chained through its associated Message). GUIDs are shared across Skype client instances and across all users that can see this Conversation.
471 *
472 * Note that currently SkypeKit sets this property for INCOMING file transfers only and returns 0 (zero) for all sending side transfers. This is a known bug.
473 */
474 public Conversation getConversation() {
475 synchronized(this) {
476 if ((mSidCached & 0x4000) != 0)
477 return mConversation;
478 }
479 return (Conversation) sidRequestObjectProperty(Property.P_CONVERSATION);
480 }
481 public String sidGetStringProperty(final PropertyEnumConverting prop) {
482 switch(prop.getId()) {
483 case 81:
484 return mPartnerHandle;
485 case 82:
486 return mPartnerDisplayName;
487 case 87:
488 return mFilePath;
489 case 88:
490 return mFileName;
491 case 89:
492 return mFileSize;
493 case 90:
494 return mBytesTransferred;
495 }
496 return "";
497 }
498 public SidObject sidGetObjectProperty(final PropertyEnumConverting prop) {
499 assert(prop.getId() == 98);
500 return mConversation;
501 }
502 public int sidGetIntProperty(final PropertyEnumConverting prop) {
503 switch(prop.getId()) { case 85:
504 return mStartTime;
505 case 86:
506 return mFinishTime;
507 case 91:
508 return mBytesPerSecond;
509 case 93:
510 return mChatMsgIndex;
511 }
512 return 0;
513 }
514 public EnumConverting sidGetEnumProperty(final PropertyEnumConverting prop) {
515 switch(prop.getId()) {
516 case 80:
517 return mType;
518 case 83:
519 return mStatus;
520 case 84:
521 return mFailureReason;
522 }
523 return null;
524 }
525 public byte[] sidGetBinaryProperty(final PropertyEnumConverting prop) {
526 assert(prop.getId() == 92);
527 return mChatMsgGuid;
528 }
529 public String getPropertyAsString(final int prop) {
530 switch (prop) {
531 case 80: return getType().toString();
532 case 81: return getPartnerHandle();
533 case 82: return getPartnerDisplayName();
534 case 83: return getStatus().toString();
535 case 84: return getFailureReason().toString();
536 case 85: return Integer.toString(getStartTime());
537 case 86: return Integer.toString(getFinishTime());
538 case 87: return getFilePath();
539 case 88: return getFileName();
540 case 89: return getFileSize();
541 case 90: return getBytesTransferred();
542 case 91: return Integer.toString(getBytesPerSecond());
543 case 92: return "<binary>";
544 case 93: return Integer.toString(getChatMsgIndex());
545 case 98: return Integer.toString(getConversation().getOid());
546 }
547 return "<unkown>";
548 }
549 public String getPropertyAsString(final Property prop) {
550 return getPropertyAsString(prop.getId());
551 }
552 protected void sidOnChangedProperty(final int propertyId, final int value, final String svalue) {
553 final Property property = Property.get(propertyId);
554 if (property == Property.P_UNKNOWN) return;
555 final int idx = property.getIdx();
556 if (idx != 0) {
557 int bit = 1<<((idx-1)%32);
558 synchronized (this) {
559 mSidCached|=bit;
560 switch (propertyId) {
561 case 80: mType = Type.get(value); break;
562 case 81:
563 if (svalue != null) mPartnerHandle = svalue;
564 else mSidCached &=~bit;
565 break;
566 case 82:
567 if (svalue != null) mPartnerDisplayName = svalue;
568 else mSidCached &=~bit;
569 break;
570 case 83: mStatus = Status.get(value); break;
571 case 84: mFailureReason = FailureReason.get(value); break;
572 case 85: mStartTime = value; break;
573 case 86: mFinishTime = value; break;
574 case 87:
575 if (svalue != null) mFilePath = svalue;
576 else mSidCached &=~bit;
577 break;
578 case 88:
579 if (svalue != null) mFileName = svalue;
580 else mSidCached &=~bit;
581 break;
582 case 89:
583 if (svalue != null) mFileSize = svalue;
584 else mSidCached &=~bit;
585 break;
586 case 90:
587 if (svalue != null) mBytesTransferred = svalue;
588 else mSidCached &=~bit;
589 break;
590 case 91: mBytesPerSecond = value; break;
591 case 93: mChatMsgIndex = value; break;
592 default: mSidCached|=bit; break;
593 }
594 }
595 }
596 TransferListener listener = ((Skype) mSidRoot).getTransferListener();
597 if (listener != null)
598 listener.onPropertyChange(this, property, value, svalue);
599 }
600 public void sidSetProperty(final PropertyEnumConverting prop, final String newValue) {
601 final int propId = prop.getId();
602 switch(propId) {
603 case 81:
604 mSidCached |= 0x2;
605 mPartnerHandle= newValue;
606 break;
607 case 82:
608 mSidCached |= 0x4;
609 mPartnerDisplayName= newValue;
610 break;
611 case 87:
612 mSidCached |= 0x80;
613 mFilePath= newValue;
614 break;
615 case 88:
616 mSidCached |= 0x100;
617 mFileName= newValue;
618 break;
619 case 89:
620 mSidCached |= 0x200;
621 mFileSize= newValue;
622 break;
623 case 90:
624 mSidCached |= 0x400;
625 mBytesTransferred= newValue;
626 break;
627 }
628 }
629 public void sidSetProperty(final PropertyEnumConverting prop, final SidObject newValue) {
630 final int propId = prop.getId();
631 assert(propId == 98);
632 mSidCached |= 0x4000;
633 mConversation= (Conversation) newValue;
634 }
635 public void sidSetProperty(final PropertyEnumConverting prop, final int newValue) {
636 final int propId = prop.getId();
637 switch(propId) {
638 case 80:
639 mSidCached |= 0x1;
640 mType= Type.get(newValue);
641 break;
642 case 83:
643 mSidCached |= 0x8;
644 mStatus= Status.get(newValue);
645 break;
646 case 84:
647 mSidCached |= 0x10;
648 mFailureReason= FailureReason.get(newValue);
649 break;
650 case 85:
651 mSidCached |= 0x20;
652 mStartTime= newValue;
653 break;
654 case 86:
655 mSidCached |= 0x40;
656 mFinishTime= newValue;
657 break;
658 case 91:
659 mSidCached |= 0x800;
660 mBytesPerSecond= newValue;
661 break;
662 case 93:
663 mSidCached |= 0x2000;
664 mChatMsgIndex= newValue;
665 break;
666 }
667 }
668 public void sidSetProperty(final PropertyEnumConverting prop, final byte[] newValue) {
669 final int propId = prop.getId();
670 assert(propId == 92);
671 mSidCached |= 0x1000;
672 mChatMsgGuid= newValue;
673 }
674 public Type mType;
675 public String mPartnerHandle;
676 public String mPartnerDisplayName;
677 public Status mStatus;
678 public FailureReason mFailureReason;
679 public int mStartTime;
680 public int mFinishTime;
681 public String mFilePath;
682 public String mFileName;
683 public String mFileSize;
684 public String mBytesTransferred;
685 public int mBytesPerSecond;
686 public byte[] mChatMsgGuid;
687 public int mChatMsgIndex;
688 public Conversation mConversation;
689 public int moduleId() {
690 return 6;
691 }
692
693 public Transfer(final int oid, final SidRoot root) {
694 super(oid, root, 15);
695 }
696 }