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.api.Skype;
013 import com.skype.ipc.SidGetResponding;
014
015 /**
016 * Events in a conversation context are expressed as Messages. It is therefore useful to think of Message objects as events, rather than specifically text chat messages.
017 *
018 * Message member functions all return a Boolean indicating the success (true) or failure (false) of processing the request itself (transport, runtime availability, and so forth) - not the success or failure of its associated functionality. For example, Message.Edit returns true if it was able to make a determination, and its result parameter reflects whether this Message can be edited. Similarly, Message.Edit returns false if it was unable to make a determination, and the value of its result parameter is undefined.
019 *
020 * Message member functions that are specific to a Message TYPE return false if this Message is not of that type. For example, Message.GetVoiceMessage will return false if this Message's type is not POSTED_VOICE_MESSAGE.
021 *
022 * The actual meaning of a Message can be determined by its P_TYPE property. The meanings of most other Message properties depend on the value of P_TYPE. For example, let's take P_BODY_XML property.
023 *
024 * Following messages have a text entered by the user as a body. It may contain emoticons, URLs, etc.
025 * - POSTED_TEXT
026 * - POSTED_EMOTE
027 * - SET_METADATA
028 * - REQUESTED_AUTH
029 *
030 * Following messages have a custom XML format for the body (see the specific section on these message types for details):
031 * - POSTED_CONTACTS
032 * - POSTED_VOICE_MESSAGE
033 * - POSTED_FILES
034 * - POSTED_SMS
035 * - STARTED_LIVESESSION and ENDED_LIVESESSION (same format)
036 *
037 * Following messages do not use the body property:
038 * - SPAWNED_CONFERENCE
039 * - ADDED_CONSUMERS
040 * - ADDED_APPLICANTS
041 * - RETIRED_OTHERS
042 * - RETIRED
043 * - SET_RANK
044 * - HAS_BIRTHDAY
045 * - GRANTED_AUTH
046 * - BLOCKED
047 *
048 * Messages such as POSTED_TEXT use a small subset of a HTML-like markup to control the visual representation of the text. This markup is used by POSTED_TEXT and POSTED_EMOTE, but also for the conversation topic (CONVERSATION_META_TOPIC property and the body of the SET_METADATA message) and for authorization requests.
049 *
050 * Having chat messages in XML format means that all formatting is indicated by XML tags. This includes emoticons and URls. The big advantage is that it makes the parsing of the message by the UI much easier. The UI does not need to do emoticons or URL detection, this is already done and it only needs to look for the XML tags.
051 *
052 * For text messages, it is possible for the UI to simply ignore (meaning strip) the XML and the message will be understandable fine, it will only have lost some formatting.
053 *
054 * But it is obviously nicer to display at least the most commonly used tags.
055 *
056 * To strip the XML:
057 * - if they have the alt="sometext" attribute set, return sometext as the output of that tag and ignore the rest of tag and all nested sub tags
058 * - if no alt="" attribute set, use tag content as output - <sometag>hereissomething</sometag> is output as hereissomething
059 * - if no alt="" and no tag content, ignore the tag altogether (return nothing)
060 * Skype for Windows supports displaying many XML tags, but only a sub-set is regularly used and should be supported by the UI for a good experience. These are the ones described here.
061 * Animated emoticons
062 * Emoticons are encoded with the "ss" tag. The element content is the plain text representation. It has a "type" attribute indicating the emoticons canonical name. Example:
063 * @code
064 * Hi <ss type="smile">:-)</ss>
065 * </CODE>
066 *
067 * Flag emoticons
068 * Flag emoticons are little flags. They are encoded with the "flag" tag. The element contents is the plain text representation and it has a "country" attribute which is a 2-letter ISO-3166 country code. The user can enter a flag using "(flag:XX)", where XX is a valid ISO country code. Example:
069 * @code
070 * I am in <flag country="cc">CC</flag>
071 * </CODE>
072 *
073 * Links
074 * If the library detects a URL, it will encode it using the html "a" tag, with the "href" attribute indicating the URL. The plain text representation is what the user originally typed. Example:
075 * @code
076 * I am in <a href="http://wwww.skype.com">www.skype.com</a>
077 * </CODE>
078 *
079 * Alert matches
080 * When a conversation is configured to display only alerts if specific words are present in the message (see "/alertson [text to match]" command), if a message matches the alert, it will be marked with the <alertmatch> tag. This allows the UI to highlight the word matching. Example:
081 * @code
082 * Maybe <alertmatch>Vincent</alertmatch> knows the answer
083 * </CODE>
084 *
085 * Bold, italic, etc
086 * Skype for Windows also supports displaying bold and italic text, using the "b" and "i" tags.
087 *
088 * Encoding messages
089 * When sending a chat message via PostText(), there is the possibility to indicate if the library should do the XML encoding, or if the message has already been encoded. Usually, the UI can let library do the encoding. This is the case when the message does not contain any specific formatting. It may contain emoticons or URls, which will be detected by the library encoder and converted into XML tags.
090 * If the message has some more complex encoding, such as a quote or some bold text, it is up to the UI to encode the message.
091 */
092 public final class Message extends SidObject {
093 /** The P_TYPE property determines the actual meaning of the Message object. Only Messages of POSTED_TEXT type contain actual text messages. The meaning and content of the rest of the message properties are largely dependant of the value of the Message.P_TYPE. */
094 public enum Type implements EnumConverting {
095 /** Conference metadata were changed */
096 SET_METADATA (2),
097 /** A conference was spawned from this dialog */
098 SPAWNED_CONFERENCE (4),
099 /** Some users were added to the conference */
100 ADDED_CONSUMERS (10),
101 /** Some users are applying to be added to the conference */
102 ADDED_APPLICANTS (11),
103 /** User was kicked from the conference */
104 RETIRED_OTHERS (12),
105 /** User left the conference */
106 RETIRED (13),
107 /** Changed the rank of a user in the Conversation (multichat administration) */
108 SET_RANK (21),
109 /** A live session started */
110 STARTED_LIVE_SESSION(30),
111 /** A live session ended */
112 ENDED_LIVE_SESSION (39),
113 /** User requested authorization */
114 REQUESTED_AUTH (50),
115 /** User was granted authorization. Notification message that user is now an authorized contact (of the local user). */
116 GRANTED_AUTH (51),
117 /** User was blocked */
118 BLOCKED (53),
119 /** A text message */
120 POSTED_TEXT (61),
121 /** An emote ('John Doe is laughing', cf /me chat command) */
122 POSTED_EMOTE (60),
123 /** The message represents (a set of) contact card(s) posted in the conversation. One message can contain more than one contact cards. The contacts can be retrieved from the message by parsing them out from the P_BODY_XML property. For more information, see Conversation.PostContacts */
124 POSTED_CONTACTS (63),
125 /** The message represents an SMS object that was posted in the Conversation. See Conversation.PostSMS for more details. The Sms object itself can be retrieved from the Message with Message.GetSms The message BODY_XML contains a set of SMS properties, such as status, failurereason, targets, price and timestamp. */
126 POSTED_SMS (64),
127 /** Deprecated, never sent */
128 POSTED_ALERT (65),
129 /** A voicemail */
130 POSTED_VOICE_MESSAGE(67),
131 /** The message represents a (list of) file transfers that were posted in the Conversation with Conversation.PostFiles. Transfer objects can be retrieved from the Message with Message.GetTransfers */
132 POSTED_FILES (68),
133 /** Currently unused. */
134 POSTED_INVOICE (69),
135 /** The message represents a Contact birthday notification. */
136 HAS_BIRTHDAY (110);
137 private final int key;
138 Type(int key) {
139 this.key = key;
140 };
141 public int getId() { return key; }
142 public EnumConverting getDefault() { return SET_METADATA; }
143 public EnumConverting convert(int from) { return Type.get(from); }
144 public EnumConverting[] getArray(final int size) { return new Type[size]; } public static Type get(int from) {
145 switch (from) {
146 case 2: return SET_METADATA;
147 case 4: return SPAWNED_CONFERENCE;
148 case 10: return ADDED_CONSUMERS;
149 case 11: return ADDED_APPLICANTS;
150 case 12: return RETIRED_OTHERS;
151 case 13: return RETIRED;
152 case 21: return SET_RANK;
153 case 30: return STARTED_LIVE_SESSION;
154 case 39: return ENDED_LIVE_SESSION;
155 case 50: return REQUESTED_AUTH;
156 case 51: return GRANTED_AUTH;
157 case 53: return BLOCKED;
158 case 61: return POSTED_TEXT;
159 case 60: return POSTED_EMOTE;
160 case 63: return POSTED_CONTACTS;
161 case 64: return POSTED_SMS;
162 case 65: return POSTED_ALERT;
163 case 67: return POSTED_VOICE_MESSAGE;
164 case 68: return POSTED_FILES;
165 case 69: return POSTED_INVOICE;
166 case 110: return HAS_BIRTHDAY;
167 }
168 return SET_METADATA;
169 }
170 public static final int SET_METADATA_VALUE = 2;
171 public static final int SPAWNED_CONFERENCE_VALUE = 4;
172 public static final int ADDED_CONSUMERS_VALUE = 10;
173 public static final int ADDED_APPLICANTS_VALUE = 11;
174 public static final int RETIRED_OTHERS_VALUE = 12;
175 public static final int RETIRED_VALUE = 13;
176 public static final int SET_RANK_VALUE = 21;
177 public static final int STARTED_LIVE_SESSION_VALUE = 30;
178 public static final int ENDED_LIVE_SESSION_VALUE = 39;
179 public static final int REQUESTED_AUTH_VALUE = 50;
180 public static final int GRANTED_AUTH_VALUE = 51;
181 public static final int BLOCKED_VALUE = 53;
182 public static final int POSTED_TEXT_VALUE = 61;
183 public static final int POSTED_EMOTE_VALUE = 60;
184 public static final int POSTED_CONTACTS_VALUE = 63;
185 public static final int POSTED_SMS_VALUE = 64;
186 public static final int POSTED_ALERT_VALUE = 65;
187 public static final int POSTED_VOICE_MESSAGE_VALUE = 67;
188 public static final int POSTED_FILES_VALUE = 68;
189 public static final int POSTED_INVOICE_VALUE = 69;
190 public static final int HAS_BIRTHDAY_VALUE = 110;
191 }
192 public enum SendingStatus implements EnumConverting {
193 /** Message has not been delivered to at least one of the participants */
194 SENDING (1),
195 /** Message has been delivered to at least one other participant */
196 SENT (2),
197 /** Message could not be delivered (for SMS this reflects the actual SMS, not the chat message) */
198 FAILED_TO_SEND(3);
199 private final int key;
200 SendingStatus(int key) {
201 this.key = key;
202 };
203 public int getId() { return key; }
204 public EnumConverting getDefault() { return SENDING; }
205 public EnumConverting convert(int from) { return SendingStatus.get(from); }
206 public EnumConverting[] getArray(final int size) { return new SendingStatus[size]; }
207 public static SendingStatus get(int from) {
208 switch (from) {
209 case 1: return SENDING;
210 case 2: return SENT;
211 case 3: return FAILED_TO_SEND;
212 }
213 return SENDING;
214 }
215 public static final int SENDING_VALUE = 1;
216 public static final int SENT_VALUE = 2;
217 public static final int FAILED_TO_SEND_VALUE = 3;
218 }
219 /** Indicates if a message has been consumed (meaning read) or not */
220 public enum ConsumptionStatus implements EnumConverting {
221 /** Message has been read. Note that this is a read-only property. Consumption status of individual messages can not be set selectively. Message consumption status is determined at the conversation level, based conversation consumption horizon and individual message timestamps. Conversation consumption horizon can be updated with Conversation.SetConsumedHorizon method. */
222 CONSUMED (0),
223 /** Do not notify the user that they have this unread message */
224 UNCONSUMED_SUPPRESSED(1),
225 /** Notify the user that they have this unread message */
226 UNCONSUMED_NORMAL (2),
227 /** This message consumption state is marked as DEPRECATED */
228 UNCONSUMED_ELEVATED (3);
229 private final int key;
230 ConsumptionStatus(int key) {
231 this.key = key;
232 };
233 public int getId() { return key; }
234 public EnumConverting getDefault() { return CONSUMED; }
235 public EnumConverting convert(int from) { return ConsumptionStatus.get(from); }
236 public EnumConverting[] getArray(final int size) { return new ConsumptionStatus[size]; }
237 public static ConsumptionStatus get(int from) {
238 switch (from) {
239 case 0: return CONSUMED;
240 case 1: return UNCONSUMED_SUPPRESSED;
241 case 2: return UNCONSUMED_NORMAL;
242 case 3: return UNCONSUMED_ELEVATED;
243 }
244 return CONSUMED;
245 }
246 public static final int CONSUMED_VALUE = 0;
247 public static final int UNCONSUMED_SUPPRESSED_VALUE = 1;
248 public static final int UNCONSUMED_NORMAL_VALUE = 2;
249 public static final int UNCONSUMED_ELEVATED_VALUE = 3;
250 }
251 /**
252 * For messages of type SET_METADATA that alert participants to changes to the associated Conversation's metadata, indicates which metadata property changed and its P_BODY_XML property contains the changed data. Your UI is expected to detect messages with PARAM_KEY set and to update its visual representation of Conversation accordingly.
253 * You can use the associated Conversation's properties and methods to obtain the updated metadata rather than parse the message body XML, for example, Conversation.P_META_PICTURE and Conversation.Conversation.GetPropMetaPicture.
254 */
255 public enum SetMetadataKey implements EnumConverting {
256 /** Notification message that conversation name has changed. */
257 SET_META_NAME (3640),
258 /** Notification message that conversation topic has changed. */
259 SET_META_TOPIC (3644),
260 /** Notification message that conversation guidelines have changed. */
261 SET_META_GUIDELINES(3652),
262 /** Notification message that conversation picture has changed. */
263 SET_META_PICTURE (3658);
264 private final int key;
265 SetMetadataKey(int key) {
266 this.key = key;
267 };
268 public int getId() { return key; }
269 public EnumConverting getDefault() { return SET_META_NAME; }
270 public EnumConverting convert(int from) { return SetMetadataKey.get(from); }
271 public EnumConverting[] getArray(final int size) { return new SetMetadataKey[size]; }
272 public static SetMetadataKey get(int from) {
273 switch (from) {
274 case 3640: return SET_META_NAME;
275 case 3644: return SET_META_TOPIC;
276 case 3652: return SET_META_GUIDELINES;
277 case 3658: return SET_META_PICTURE;
278 }
279 return SET_META_NAME;
280 }
281 public static final int SET_META_NAME_VALUE = 3640;
282 public static final int SET_META_TOPIC_VALUE = 3644;
283 public static final int SET_META_GUIDELINES_VALUE = 3652;
284 public static final int SET_META_PICTURE_VALUE = 3658;
285 }
286 /** Indicates the reason a user could not join or left a Conversation. SkypeKit automatically sets "could not join"-related values. "Left voluntarily"-related values are set as a result of explicit user actions. */
287 public enum Leavereason implements EnumConverting {
288 /** User cannot chat (user is currently logged in with a client that has chat disabled - see Contact.CAPABILITY.CAPABILITY_TEXT) */
289 USER_INCAPABLE (2),
290 /** Attempt to add local user to a conversation by an unknown contact */
291 ADDER_MUST_BE_FRIEND (3),
292 /** Attempt to add local user to a conversation by an unauthorized contact */
293 ADDER_MUST_BE_AUTHORIZED(4),
294 /** Local user declined an "invitation" to join a chat */
295 DECLINE_ADD (5),
296 /** User decided to end participation in an on-going multi-chat */
297 UNSUBSCRIBE (6);
298 private final int key;
299 Leavereason(int key) {
300 this.key = key;
301 };
302 public int getId() { return key; }
303 public EnumConverting getDefault() { return USER_INCAPABLE; }
304 public EnumConverting convert(int from) { return Leavereason.get(from); }
305 public EnumConverting[] getArray(final int size) { return new Leavereason[size]; }
306 public static Leavereason get(int from) {
307 switch (from) {
308 case 2: return USER_INCAPABLE;
309 case 3: return ADDER_MUST_BE_FRIEND;
310 case 4: return ADDER_MUST_BE_AUTHORIZED;
311 case 5: return DECLINE_ADD;
312 case 6: return UNSUBSCRIBE;
313 }
314 return USER_INCAPABLE;
315 }
316 public static final int USER_INCAPABLE_VALUE = 2;
317 public static final int ADDER_MUST_BE_FRIEND_VALUE = 3; public static final int ADDER_MUST_BE_AUTHORIZED_VALUE = 4;
318 public static final int DECLINE_ADD_VALUE = 5;
319 public static final int UNSUBSCRIBE_VALUE = 6;
320 }
321 private final static byte[] P_CONVERSATION_req = {(byte) 90,(byte) 71,(byte) 192,(byte) 7,(byte) 93,(byte) 9};
322 private final static byte[] P_CONVO_GUID_req = {(byte) 90,(byte) 71,(byte) 120,(byte) 93,(byte) 9};
323 private final static byte[] P_AUTHOR_req = {(byte) 90,(byte) 71,(byte) 122,(byte) 93,(byte) 9};
324 private final static byte[] P_AUTHOR_DISPLAY_NAME_req = {(byte) 90,(byte) 71,(byte) 123,(byte) 93,(byte) 9};
325 private final static byte[] P_GUID_req = {(byte) 90,(byte) 71,(byte) 152,(byte) 6,(byte) 93,(byte) 9};
326 private final static byte[] P_ORIGINALLY_MEANT_FOR_req = {(byte) 90,(byte) 71,(byte) 150,(byte) 6,(byte) 93,(byte) 9};
327 private final static byte[] P_TIMESTAMP_req = {(byte) 90,(byte) 71,(byte) 121,(byte) 93,(byte) 9};
328 private final static byte[] P_TYPE_req = {(byte) 90,(byte) 71,(byte) 193,(byte) 7,(byte) 93,(byte) 9};
329 private final static byte[] P_SENDING_STATUS_req = {(byte) 90,(byte) 71,(byte) 194,(byte) 7,(byte) 93,(byte) 9};
330 private final static byte[] P_CONSUMPTION_STATUS_req = {(byte) 90,(byte) 71,(byte) 200,(byte) 7,(byte) 93,(byte) 9};
331 private final static byte[] P_EDITED_BY_req = {(byte) 90,(byte) 71,(byte) 222,(byte) 1,(byte) 93,(byte) 9};
332 private final static byte[] P_EDIT_TIMESTAMP_req = {(byte) 90,(byte) 71,(byte) 223,(byte) 1,(byte) 93,(byte) 9};
333 private final static byte[] P_PARAM_KEY_req = {(byte) 90,(byte) 71,(byte) 195,(byte) 7,(byte) 93,(byte) 9};
334 private final static byte[] P_PARAM_VALUE_req = {(byte) 90,(byte) 71,(byte) 196,(byte) 7,(byte) 93,(byte) 9};
335 private final static byte[] P_BODY_XML_req = {(byte) 90,(byte) 71,(byte) 127,(byte) 93,(byte) 9};
336 private final static byte[] P_IDENTITIES_req = {(byte) 90,(byte) 71,(byte) 125,(byte) 93,(byte) 9};
337 private final static byte[] P_REASON_req = {(byte) 90,(byte) 71,(byte) 198,(byte) 7,(byte) 93,(byte) 9};
338 private final static byte[] P_LEAVEREASON_req = {(byte) 90,(byte) 71,(byte) 126,(byte) 93,(byte) 9};
339 private final static byte[] P_PARTICIPANT_COUNT_req = {(byte) 90,(byte) 71,(byte) 214,(byte) 7,(byte) 93,(byte) 9};
340 /** Properties of the Message class */
341 public enum Property implements PropertyEnumConverting {
342 P_UNKNOWN (0,0,null,0,null),
343 P_CONVERSATION (960, 1, P_CONVERSATION_req, 18, null),
344 P_CONVO_GUID (120, 2, P_CONVO_GUID_req, 0, null),
345 P_AUTHOR (122, 3, P_AUTHOR_req, 0, null),
346 P_AUTHOR_DISPLAY_NAME (123, 4, P_AUTHOR_DISPLAY_NAME_req, 0, null),
347 P_GUID (792, 5, P_GUID_req, 0, null),
348 P_ORIGINALLY_MEANT_FOR(790, 6, P_ORIGINALLY_MEANT_FOR_req, 0, null),
349 P_TIMESTAMP (121, 7, P_TIMESTAMP_req, 0, null),
350 P_TYPE (961, 8, P_TYPE_req, 0, Type.get(0)),
351 P_SENDING_STATUS (962, 9, P_SENDING_STATUS_req, 0, SendingStatus.get(0)),
352 P_CONSUMPTION_STATUS (968, 10, P_CONSUMPTION_STATUS_req, 0, ConsumptionStatus.get(0)),
353 P_EDITED_BY (222, 11, P_EDITED_BY_req, 0, null),
354 P_EDIT_TIMESTAMP (223, 12, P_EDIT_TIMESTAMP_req, 0, null),
355 P_PARAM_KEY (963, 13, P_PARAM_KEY_req, 0, null),
356 P_PARAM_VALUE (964, 14, P_PARAM_VALUE_req, 0, null),
357 P_BODY_XML (127, 15, P_BODY_XML_req, 0, null),
358 P_IDENTITIES (125, 16, P_IDENTITIES_req, 0, null),
359 P_REASON (966, 17, P_REASON_req, 0, null),
360 P_LEAVEREASON (126, 18, P_LEAVEREASON_req, 0, Skype.LeaveReason.get(0)),
361 P_PARTICIPANT_COUNT (982, 19, P_PARTICIPANT_COUNT_req, 0, null);
362 private final int key;
363 private final int idx;
364 private final byte[] req;
365 private final int mod;
366 private final EnumConverting enumConverter;
367 Property(int key, int idx, byte[] req, int mod, EnumConverting converter) {
368 this.key = key;
369 this.idx = idx;
370 this.req = req;
371 this.mod = mod;
372 this.enumConverter = converter;
373 };
374 public boolean isCached() { return idx > 0; }
375 public int getIdx() { return idx; }
376 public int getId() { return key; }
377 public byte[] getRequest() { return req; }
378 public EnumConverting getDefault() { return P_UNKNOWN; }
379 public int getModuleId() { return mod; }
380 public EnumConverting getEnumConverter() { return enumConverter; }
381 public EnumConverting convert(final int from) { return Property.get(from); }
382 public EnumConverting[] getArray(final int size) { return new Property[size]; }
383 public static Property get(final int from) {
384 switch (from) {
385 case 960: return P_CONVERSATION;
386 case 120: return P_CONVO_GUID;
387 case 122: return P_AUTHOR;
388 case 123: return P_AUTHOR_DISPLAY_NAME;
389 case 792: return P_GUID;
390 case 790: return P_ORIGINALLY_MEANT_FOR;
391 case 121: return P_TIMESTAMP;
392 case 961: return P_TYPE;
393 case 962: return P_SENDING_STATUS;
394 case 968: return P_CONSUMPTION_STATUS;
395 case 222: return P_EDITED_BY;
396 case 223: return P_EDIT_TIMESTAMP;
397 case 963: return P_PARAM_KEY;
398 case 964: return P_PARAM_VALUE;
399 case 127: return P_BODY_XML;
400 case 125: return P_IDENTITIES;
401 case 966: return P_REASON;
402 case 126: return P_LEAVEREASON;
403 case 982: return P_PARTICIPANT_COUNT;
404 }
405 return P_UNKNOWN;
406 }
407 public static final int P_CONVERSATION_VALUE = 960;
408 public static final int P_CONVO_GUID_VALUE = 120;
409 public static final int P_AUTHOR_VALUE = 122;
410 public static final int P_AUTHOR_DISPLAY_NAME_VALUE = 123;
411 public static final int P_GUID_VALUE = 792;
412 public static final int P_ORIGINALLY_MEANT_FOR_VALUE = 790;
413 public static final int P_TIMESTAMP_VALUE = 121;
414 public static final int P_TYPE_VALUE = 961;
415 public static final int P_SENDING_STATUS_VALUE = 962;
416 public static final int P_CONSUMPTION_STATUS_VALUE = 968;
417 public static final int P_EDITED_BY_VALUE = 222;
418 public static final int P_EDIT_TIMESTAMP_VALUE = 223;
419 public static final int P_PARAM_KEY_VALUE = 963;
420 public static final int P_PARAM_VALUE_VALUE = 964;
421 public static final int P_BODY_XML_VALUE = 127;
422 public static final int P_IDENTITIES_VALUE = 125;
423 public static final int P_REASON_VALUE = 966;
424 public static final int P_LEAVEREASON_VALUE = 126;
425 public static final int P_PARTICIPANT_COUNT_VALUE = 982;
426 public static final Property[] mget_info_mreq = { P_CONVERSATION, P_AUTHOR_DISPLAY_NAME, P_TYPE, P_BODY_XML, P_TIMESTAMP };
427 }
428 private final static byte[] canEdit_req = {(byte) 90,(byte) 82,(byte) 9,(byte) 1};
429 /** For Message types having a body, determines whether that body is editable by the user. * @return result
430 */
431 public boolean canEdit() {
432 try {
433 return sidDoRequest(canEdit_req)
434 .endRequest().getBoolParm(1, true);
435 } catch(IOException e) {
436 mSidRoot.sidOnFatalError(e);
437 return false
438 ;}
439 }
440 private final static byte[] edit_req = {(byte) 90,(byte) 82,(byte) 9,(byte) 2};
441 /**
442 * For Message types that include a body and are editable:
443 * - alters BODY_XML of the message object
444 * - sets EDITED_BY and EDIT_TIMESTAMP properties
445 * - propagates the changes to remote users.
446 * @param newText New value of the message BODY_XML property.
447 * @param isXml Specify isXML as true if the message body is formatted as XML; omit it or specify it as false if the message body is plain text.
448 * @param undo Reverts the message body to the original version. newText parameter is ignored when this is set
449 */
450 public void edit(String newText, boolean isXml, boolean undo) {
451 try {
452 sidDoRequest(edit_req)
453 .addStringParm(1, newText)
454 .addBoolParm(2, isXml)
455 .addBoolParm(3, undo)
456 .endOneWay();
457 } catch(IOException e) {
458 mSidRoot.sidOnFatalError(e);
459 }
460 }
461 private final static byte[] getContacts_req = {(byte) 90,(byte) 82,(byte) 9,(byte) 3};
462 /** For messages of type POSTED_CONTACTS, parses the body XML and formats the data as a list of Contact instances. * @return contacts
463 */
464 public Contact[] getContacts() {
465 try {
466 return (Contact[]) sidDoRequest(getContacts_req) .endRequest().getObjectListParm(1, 2, true);
467 } catch(IOException e) {
468 mSidRoot.sidOnFatalError(e);
469 return null
470 ;}
471 }
472 private final static byte[] getTransfers_req = {(byte) 90,(byte) 82,(byte) 9,(byte) 4};
473 /** For messages of type POSTED_FILES, parses the body XML and creates a list of Transfer instances. * @return transfers
474 */
475 public Transfer[] getTransfers() {
476 try {
477 return (Transfer[]) sidDoRequest(getTransfers_req)
478 .endRequest().getObjectListParm(1, 6, true);
479 } catch(IOException e) {
480 mSidRoot.sidOnFatalError(e);
481 return null
482 ;}
483 }
484 private final static byte[] getVoiceMessage_req = {(byte) 90,(byte) 82,(byte) 9,(byte) 5};
485 /** For messages of type POSTED_VOICE_MESSAGE, parses the body XML and creates a Voicemail instance. * @return voicemail
486 */
487 public Voicemail getVoiceMessage() {
488 try {
489 return (Voicemail) sidDoRequest(getVoiceMessage_req)
490 .endRequest().getObjectParm(1, 7, true);
491 } catch(IOException e) {
492 mSidRoot.sidOnFatalError(e);
493 return null
494 ;}
495 }
496 private final static byte[] getSms_req = {(byte) 90,(byte) 82,(byte) 9,(byte) 6};
497 /** For messages of type POSTED_SMS, parses the body XML and creates an SMS instances * @return sms
498 */
499 public Sms getSms() {
500 try {
501 return (Sms) sidDoRequest(getSms_req)
502 .endRequest().getObjectParm(1, 12, true);
503 } catch(IOException e) {
504 mSidRoot.sidOnFatalError(e);
505 return null
506 ;}
507 }
508 private final static byte[] deleteLocally_req = {(byte) 90,(byte) 82,(byte) 9,(byte) 8};
509 /** Deletes this message from the local database. These deletions do not propagate to the other Skype instances that the user may have on other computers. Nor do they affect other participants that have the same message. This method is specifically from removing Message objects from the database - not for removing Messages from conversations. To remove a Message from a conversation, use Message.Edit method to replace the existing body text with an empty string. */
510 public void deleteLocally() {
511 try {
512 sidDoRequest(deleteLocally_req)
513 .endOneWay();
514 } catch(IOException e) {
515 mSidRoot.sidOnFatalError(e);
516 }
517 }
518 /***
519 * generic multiget of a list of Property
520 * @param requested the list of requested properties of Message
521 * @return SidGetResponding
522 */
523 public SidGetResponding sidMultiGet(Property[] requested) {
524 return super.sidMultiGet(requested);
525 }
526 /***
527 * generic multiget of list of Property for a list of Message
528 * @param requested the list of requested properties
529 * @return SidGetResponding[] can be casted to (Message[]) if all properties are cached
530 */
531 static public SidGetResponding[] sidMultiGet(Property[] requested, Message[] objects) {
532 return SidObject.sidMultiGet(requested, objects);
533 }
534 /*** multiget the following properties
535 * - P_CONVERSATION
536 * - P_AUTHOR_DISPLAY_NAME
537 * - P_TYPE
538 * - P_BODY_XML
539 * - P_TIMESTAMP
540 */
541 public Message mgetInfo() {
542 return (Message) super.sidMultiGet(Property.mget_info_mreq, this);
543 }
544 /*** multiget the following properties for a list of Message
545 * - P_CONVERSATION
546 * - P_AUTHOR_DISPLAY_NAME
547 * - P_TYPE
548 * - P_BODY_XML
549 * - P_TIMESTAMP
550 * @param objects targets of the request
551 * @return Message[] responses
552 */
553 static public Message[] mgetInfo(Message[] objects) {
554 return (Message[]) SidObject.sidMultiGet(Property.mget_info_mreq, objects, objects);
555 }
556 /** DB ID of corresponding conversation */
557 public Conversation getConversation() {
558 synchronized(this) {
559 if ((mSidCached & 0x1) != 0)
560 return mConversation;
561 }
562 return (Conversation) sidRequestObjectProperty(Property.P_CONVERSATION);
563 }
564 /** GUID of the Conversation. The GUID is a "global ID" - these values are shared accross Skype client instances and accross all the participants of the conversation. */
565 public String getConvoGuid() {
566 synchronized(this) {
567 if ((mSidCached & 0x2) != 0)
568 return mConvoGuid;
569 }
570 return sidRequestStringProperty(Property.P_CONVO_GUID);
571 }
572 /** Identity of the sender. While this is almost always the same as SKYPENAME property of the Contact, in some rare cases it can also be a phone number - for example, incoming voicemail notification Messages (message type = POSTED_VOICE_MESSAGE). */
573 public String getAuthor() {
574 synchronized(this) {
575 if ((mSidCached & 0x4) != 0)
576 return mAuthor;
577 }
578 return sidRequestStringProperty(Property.P_AUTHOR);
579 }
580 /** displayname of the sender at the time of posting */
581 public String getAuthorDisplayName() {
582 synchronized(this) {
583 if ((mSidCached & 0x8) != 0)
584 return mAuthorDisplayName;
585 }
586 return sidRequestStringProperty(Property.P_AUTHOR_DISPLAY_NAME);
587 }
588 /** Unlike the message id, the GUID is the same on all instances and for all participants. */
589 public byte[] getGuid() {
590 synchronized(this) {
591 if ((mSidCached & 0x10) != 0)
592 return mGuid;
593 }
594 return sidRequestBinaryProperty(Property.P_GUID);
595 }
596 /** This property gets set when a conference is spawned from dialog Conversation. In that case recent message history from the original dialog is copied to the target conversation. For all the copied messages, the ORIGINALLY_MEANT_FOR property will be set to identity of the remote participant of the original dialog. */
597 public String getOriginallyMeantFor() {
598 synchronized(this) {
599 if ((mSidCached & 0x20) != 0)
600 return mOriginallyMeantFor;
601 }
602 return sidRequestStringProperty(Property.P_ORIGINALLY_MEANT_FOR);
603 }
604 /** UNIX timestamp (sent time, adjusted for local clock) */
605 public int getTimestamp() {
606 synchronized(this) {
607 if ((mSidCached & 0x40) != 0)
608 return mTimestamp;
609 }
610 return sidRequestUintProperty(Property.P_TIMESTAMP);
611 }
612 public Type getType() {
613 synchronized(this) {
614 if ((mSidCached & 0x80) != 0)
615 return mType;
616 }
617 return (Type) sidRequestEnumProperty(Property.P_TYPE);
618 }
619 public SendingStatus getSendingStatus() {
620 synchronized(this) {
621 if ((mSidCached & 0x100) != 0)
622 return mSendingStatus;
623 }
624 return (SendingStatus) sidRequestEnumProperty(Property.P_SENDING_STATUS);
625 }
626 public ConsumptionStatus getConsumptionStatus() {
627 synchronized(this) {
628 if ((mSidCached & 0x200) != 0)
629 return mConsumptionStatus;
630 }
631 return (ConsumptionStatus) sidRequestEnumProperty(Property.P_CONSUMPTION_STATUS);
632 }
633 /** Identity of the author that last edited this message. NULL if message has not been edited */
634 public String getEditedBy() {
635 synchronized(this) {
636 if ((mSidCached & 0x400) != 0)
637 return mEditedBy;
638 }
639 return sidRequestStringProperty(Property.P_EDITED_BY);
640 }
641 /** UNIX timestamp of last edit */
642 public int getEditTimestamp() {
643 synchronized(this) {
644 if ((mSidCached & 0x800) != 0)
645 return mEditTimestamp;
646 }
647 return sidRequestUintProperty(Property.P_EDIT_TIMESTAMP);
648 }
649 /** Message type-specific parameter. See Message.SET_METADATA_KEY for more information. */
650 public int getParamKey() {
651 synchronized(this) {
652 if ((mSidCached & 0x1000) != 0)
653 return mParamKey;
654 }
655 return sidRequestUintProperty(Property.P_PARAM_KEY);
656 }
657 /** Message type-specific parameter */
658 public int getParamValue() {
659 synchronized(this) {
660 if ((mSidCached & 0x2000) != 0)
661 return mParamValue;
662 }
663 return sidRequestUintProperty(Property.P_PARAM_VALUE);
664 }
665 /** Message type-specific parameter */
666 public String getBodyXml() {
667 synchronized(this) {
668 if ((mSidCached & 0x4000) != 0)
669 return mBodyXml;
670 }
671 return sidRequestXmlProperty(Property.P_BODY_XML);
672 }
673 /**
674 * Message type-specific parameter. Depending of Message type, this property contains:
675 * - STARTED_LIVESESSION - list of participants in the cal;
676 * - ENDED_LIVESESSION - list of participants in the call;
677 * - POSTED_SMS - list of recipients of the message;
678 * - SPAWNED_CONFERENCE - the list of identities that were added;
679 * - ADDED_CONSUMERS - the list of identities that were added;
680 * - RETIRED_OTHERS - the skypename of the participant who was kicked;
681 * - SET_RANK - the skypename of the participant whose rank was changed;
682 * - REQUESTED_AUTH - Message.P_AUTHOR and Message.P_IDENTITIES are set to the users receiving and requesting the authorization, depending if the message was received or sent;
683 * - GRANTED_AUTH - the skypename of the user we granted authorization; * - BLOCKED - the skypename of the user who was blocked;
684 * - HAS_BIRTHDAY - skypename of current logged in user.
685 */
686 public String getIdentities() {
687 synchronized(this) {
688 if ((mSidCached & 0x8000) != 0)
689 return mIdentities;
690 }
691 return sidRequestStringProperty(Property.P_IDENTITIES);
692 }
693 /**
694 * Message type-specific parameter. Possible values for STARTED/ENDED_LIVESESSION (only set for dialogs):
695 * - no_answer
696 * - manual
697 * - busy
698 * - connection_dropped
699 * - no_skypeout_subscription;
700 * - insufficient_funds
701 * - internet_connection_lost
702 * - skypeout_account_blocked
703 * - pstn_could_not_connect_to_skype_proxy
704 * - pstn_invalid_number
705 * - pstn_number_forbidden
706 * - pstn_call_timed_out
707 * - pstn_busy
708 * - pstn_call_terminated
709 * - pstn_network_error
710 * - number_unavailable
711 * - pstn_call_rejected
712 * - pstn_misc_error
713 * - internal_error
714 * - unable_to_connect
715 * - connection_dropped
716 * - recording_failed
717 * - playback_error
718 * - legacy_error
719 * - blocked_by_privacy_settings
720 * - error
721 * - transfer_failed
722 * - transfer_insufficient_funds
723 * - blocked_by_us
724 * - emergency_call_denied
725 *
726 * This information is now available as an enum in LEAVEREASON
727 */
728 public String getReason() {
729 synchronized(this) {
730 if ((mSidCached & 0x10000) != 0)
731 return mReason;
732 }
733 return sidRequestStringProperty(Property.P_REASON);
734 }
735 /** Leave reason for message of the RETIRED type, and STARTED/ENDED_LIVESESSION. Use for STARTED/ENDED_LIVESESSION is to provide simpler, enum based handling and deprecates the reason property (only set for dialogs) */
736 public Skype.LeaveReason getLeavereason() {
737 synchronized(this) {
738 if ((mSidCached & 0x20000) != 0)
739 return mLeavereason;
740 }
741 return (Skype.LeaveReason) sidRequestEnumProperty(Property.P_LEAVEREASON);
742 }
743 /** Number of people who received this message (including local user) */
744 public int getParticipantCount() {
745 synchronized(this) {
746 if ((mSidCached & 0x40000) != 0)
747 return mParticipantCount;
748 }
749 return sidRequestUintProperty(Property.P_PARTICIPANT_COUNT);
750 }
751 public String sidGetStringProperty(final PropertyEnumConverting prop) {
752 switch(prop.getId()) {
753 case 120:
754 return mConvoGuid;
755 case 122:
756 return mAuthor;
757 case 123:
758 return mAuthorDisplayName;
759 case 790:
760 return mOriginallyMeantFor;
761 case 222:
762 return mEditedBy;
763 case 127:
764 return mBodyXml;
765 case 125:
766 return mIdentities;
767 case 966:
768 return mReason;
769 }
770 return "";
771 }
772 public SidObject sidGetObjectProperty(final PropertyEnumConverting prop) {
773 assert(prop.getId() == 960);
774 return mConversation;
775 }
776 public int sidGetIntProperty(final PropertyEnumConverting prop) {
777 switch(prop.getId()) {
778 case 121:
779 return mTimestamp;
780 case 223:
781 return mEditTimestamp;
782 case 963:
783 return mParamKey;
784 case 964:
785 return mParamValue;
786 case 982:
787 return mParticipantCount;
788 }
789 return 0;
790 }
791 public EnumConverting sidGetEnumProperty(final PropertyEnumConverting prop) {
792 switch(prop.getId()) {
793 case 961:
794 return mType;
795 case 962:
796 return mSendingStatus;
797 case 968:
798 return mConsumptionStatus;
799 case 126:
800 return mLeavereason;
801 }
802 return null;
803 }
804 public byte[] sidGetBinaryProperty(final PropertyEnumConverting prop) {
805 assert(prop.getId() == 792);
806 return mGuid;
807 }
808 public String getPropertyAsString(final int prop) {
809 switch (prop) {
810 case 960: return Integer.toString(getConversation().getOid());
811 case 120: return getConvoGuid();
812 case 122: return getAuthor();
813 case 123: return getAuthorDisplayName();
814 case 792: return "<binary>";
815 case 790: return getOriginallyMeantFor();
816 case 121: return Integer.toString(getTimestamp());
817 case 961: return getType().toString();
818 case 962: return getSendingStatus().toString();
819 case 968: return getConsumptionStatus().toString();
820 case 222: return getEditedBy();
821 case 223: return Integer.toString(getEditTimestamp());
822 case 963: return Integer.toString(getParamKey());
823 case 964: return Integer.toString(getParamValue());
824 case 125: return getIdentities();
825 case 966: return getReason();
826 case 126: return getLeavereason().toString();
827 case 982: return Integer.toString(getParticipantCount());
828 }
829 return "<unkown>";
830 }
831 public String getPropertyAsString(final Property prop) {
832 return getPropertyAsString(prop.getId());
833 }
834 protected void sidOnChangedProperty(final int propertyId, final int value, final String svalue) {
835 final Property property = Property.get(propertyId);
836 if (property == Property.P_UNKNOWN) return;
837 final int idx = property.getIdx();
838 if (idx != 0) {
839 int bit = 1<<((idx-1)%32);
840 synchronized (this) {
841 mSidCached|=bit;
842 switch (propertyId) {
843 case 120:
844 if (svalue != null) mConvoGuid = svalue;
845 else mSidCached &=~bit;
846 break;
847 case 122:
848 if (svalue != null) mAuthor = svalue;
849 else mSidCached &=~bit;
850 break;
851 case 123:
852 if (svalue != null) mAuthorDisplayName = svalue;
853 else mSidCached &=~bit;
854 break;
855 case 790:
856 if (svalue != null) mOriginallyMeantFor = svalue;
857 else mSidCached &=~bit;
858 break;
859 case 121: mTimestamp = value; break;
860 case 961: mType = Type.get(value); break;
861 case 962: mSendingStatus = SendingStatus.get(value); break;
862 case 968: mConsumptionStatus = ConsumptionStatus.get(value); break;
863 case 222:
864 if (svalue != null) mEditedBy = svalue;
865 else mSidCached &=~bit;
866 break;
867 case 223: mEditTimestamp = value; break;
868 case 963: mParamKey = value; break;
869 case 964: mParamValue = value; break;
870 case 125:
871 if (svalue != null) mIdentities = svalue;
872 else mSidCached &=~bit;
873 break;
874 case 966:
875 if (svalue != null) mReason = svalue;
876 else mSidCached &=~bit;
877 break;
878 case 126: mLeavereason = Skype.LeaveReason.get(value); break;
879 case 982: mParticipantCount = value; break;
880 default: mSidCached|=bit; break;
881 }
882 }
883 }
884 MessageListener listener = ((Skype) mSidRoot).getMessageListener();
885 if (listener != null)
886 listener.onPropertyChange(this, property, value, svalue);
887 }
888 public void sidSetProperty(final PropertyEnumConverting prop, final String newValue) {
889 final int propId = prop.getId();
890 switch(propId) {
891 case 120:
892 mSidCached |= 0x2;
893 mConvoGuid= newValue;
894 break;
895 case 122:
896 mSidCached |= 0x4;
897 mAuthor= newValue;
898 break;
899 case 123:
900 mSidCached |= 0x8;
901 mAuthorDisplayName= newValue;
902 break;
903 case 790:
904 mSidCached |= 0x20;
905 mOriginallyMeantFor= newValue;
906 break;
907 case 222:
908 mSidCached |= 0x400;
909 mEditedBy= newValue;
910 break;
911 case 127:
912 mSidCached |= 0x4000;
913 mBodyXml= newValue;
914 break;
915 case 125:
916 mSidCached |= 0x8000;
917 mIdentities= newValue;
918 break;
919 case 966:
920 mSidCached |= 0x10000;
921 mReason= newValue;
922 break;
923 }
924 }
925 public void sidSetProperty(final PropertyEnumConverting prop, final SidObject newValue) {
926 final int propId = prop.getId();
927 assert(propId == 960);
928 mSidCached |= 0x1;
929 mConversation= (Conversation) newValue;
930 }
931 public void sidSetProperty(final PropertyEnumConverting prop, final int newValue) {
932 final int propId = prop.getId();
933 switch(propId) {
934 case 121:
935 mSidCached |= 0x40;
936 mTimestamp= newValue;
937 break;
938 case 961:
939 mSidCached |= 0x80;
940 mType= Type.get(newValue);
941 break;
942 case 962:
943 mSidCached |= 0x100;
944 mSendingStatus= SendingStatus.get(newValue);
945 break;
946 case 968:
947 mSidCached |= 0x200;
948 mConsumptionStatus= ConsumptionStatus.get(newValue);
949 break;
950 case 223:
951 mSidCached |= 0x800;
952 mEditTimestamp= newValue;
953 break;
954 case 963:
955 mSidCached |= 0x1000;
956 mParamKey= newValue;
957 break;
958 case 964:
959 mSidCached |= 0x2000;
960 mParamValue= newValue;
961 break;
962 case 126:
963 mSidCached |= 0x20000;
964 mLeavereason= Skype.LeaveReason.get(newValue);
965 break;
966 case 982:
967 mSidCached |= 0x40000;
968 mParticipantCount= newValue;
969 break;
970 }
971 }
972 public void sidSetProperty(final PropertyEnumConverting prop, final byte[] newValue) {
973 final int propId = prop.getId();
974 assert(propId == 792);
975 mSidCached |= 0x10; mGuid= newValue;
976 }
977 public Conversation mConversation;
978 public String mConvoGuid;
979 public String mAuthor;
980 public String mAuthorDisplayName;
981 public byte[] mGuid;
982 public String mOriginallyMeantFor;
983 public int mTimestamp;
984 public Type mType;
985 public SendingStatus mSendingStatus;
986 public ConsumptionStatus mConsumptionStatus;
987 public String mEditedBy;
988 public int mEditTimestamp;
989 public int mParamKey;
990 public int mParamValue;
991 public String mBodyXml;
992 public String mIdentities;
993 public String mReason;
994 public Skype.LeaveReason mLeavereason;
995 public int mParticipantCount;
996 public int moduleId() {
997 return 9;
998 }
999
1000 public Message(final int oid, final SidRoot root) {
1001 super(oid, root, 19);
1002 }
1003 }