001    package com.skype.api;
002    
003    import java.io.IOException;
004    import java.util.*;
005    import com.skype.ipc.*;
006    /**
007     * The Conversation class encapsulates all types of communication possible with Skype client. Instant messaging, calls, video calls, file transfers, SMS, screen sharing - all take place within the context of a Conversation. Contacts are represented in Conversation as Participant objects. This also applies to contacts of PSTN type. All events in a conversation are represented as Message objects.  <br>
008     */
009    
010    
011    public class Conversation extends SkypeObject {
012    
013    
014            public interface ConversationListener {
015                    /** This event gets called when there are changes to Conversation properties defined in Conversation.PROPERTY  */
016                    public void OnPropertyChange(SkypeObject obj, PROPERTY prop, Object value);
017                    
018                    /**This callback gets fired when participants join or leave the conversation. <br>*/
019                    public void OnParticipantListChange(SkypeObject obj);
020                    
021                    /**Called for each message in currently loaded conversations*/
022                    public void OnMessage(SkypeObject obj, Message message);
023                    
024                    /**This callback gets fired when a new Conversation is created using SpawnConference. <br>*/
025                    public void OnSpawnConference(SkypeObject obj, Conversation spawned);
026                    
027            }
028            
029            public Conversation(int oid, Skype skype) {
030                    super(oid,skype);
031                    /**get default properties for this module **/
032                    GetDefaultProps();
033            }
034            
035            private static final int MODULE_ID = 18;
036            
037            public static final int moduleID() {
038                    return MODULE_ID;
039            }
040            
041            /** Properties of the Conversation class */
042            public enum PROPERTY {
043            
044                    /** contact identity in case of dialogs, chat name in case of conferences, type: String */
045                    identity(972),
046                    
047                    /** type of the conversation, type: Conversation.TYPE */
048                    type(902),
049                    
050                    /** host of current live session. none => no session. myself in case of 1:1 calls, type: String */
051                    live_host(918),
052                    
053                    /** moment when first participant other than host joined the current or last live session, type: int */
054                    live_start_timestamp(974),
055                    
056                    /** if live session is muted, type: boolean */
057                    live_is_muted(996),
058                    
059                    /** '' everything matches, '=' nothing matches, '=string' string matches, type: String */
060                    alert_string(920),
061                    
062                    /** if conversation is bookmarked/flagged, type: boolean */
063                    is_bookmarked(921),
064                    
065                    /** local name assigned via Rename, type: String */
066                    given_displayname(925),
067                    
068                    /** resulting display name of the conversation (based on given name, topic, participant list, etc), type: String */
069                    displayname(924),
070                    
071                    /** if the conversation is live and in which status it is then, type: LOCAL_LIVESTATUS */
072                    local_livestatus(927),
073                    
074                    /** timestamp to sort the conversations in inbox by. 0 means not in inbox, type: int */
075                    inbox_timestamp(928),
076                    
077                    /** ID of the message that caused INBOX_TIMESTAMP to be set, type: Message */
078                    inbox_message_id(973),
079                    
080                    /** number of messages in UNCONSUMED_SUPPRESSED consumption status, type: int */
081                    unconsumed_suppressed_messages(975),
082                    
083                    /** number of messages in UNCONSUMED_NORMAL consumption status, type: int */
084                    unconsumed_normal_messages(976),
085                    
086                    /** DEPRECATED, not set anymore, type: int */
087                    unconsumed_elevated_messages(977),
088                    
089                    /** if there are unconsumed voice or call messages in the conversation, type: boolean */
090                    unconsumed_messages_voice(970),
091                    
092                    /** ID of voice message that is being played or recorded in this conversation, type: Voicemail */
093                    active_vm_id(971),
094                    
095                    /** consumption cutoff timestamp: messages after (but not including) this are considered unconsumed, type: int */
096                    consumption_horizon(979),
097                    
098                    /** timestamp of last activity in conversation, type: int */
099                    last_activity_timestamp(981),
100                    
101                    /** dialog this conference was spawned from, type: Conversation */
102                    spawned_from_convo_id(915),
103                    
104                    /** identity of conversation creator (doesn't apply to dialogs), type: String */
105                    creator(903),
106                    
107                    /** timestamp of creation, tells you how far you can retrieve messages, type: int */
108                    creation_timestamp(904),
109                    
110                    /** my status in this conversation (connecting, participating, retired, etc) (doesn't apply to dialogs), type: MY_STATUS */
111                    my_status(919),
112                    
113                    /** if it's a public conversation (doesn't apply to dialogs), type: boolean */
114                    opt_joining_enabled(922),
115                    
116                    /** rank that is auto-assigned at join (doesn't apply to dialogs), type: Participant.RANK */
117                    opt_entry_level_rank(906),
118                    
119                    /** if history visible to new consumers (doesn't apply to dialogs), type: boolean */
120                    opt_disclose_history(907),
121                    
122                    /** activities that only ADMIN can do. Bitmap of ALLOWED_ACTIVITY values (doesn't apply to dialogs), type: ALLOWED_ACTIVITY */
123                    opt_admin_only_activities(909),
124                    
125                    /** public conversation password hint, use SetPassword to set (doesn't apply to dialogs), type: String */
126                    passwordhint(980),
127                    
128                    /** deprecated, not used, type: String */
129                    meta_name(910),
130                    
131                    /** conversation topic (doesn't apply to dialogs), type: String */
132                    meta_topic(911),
133                    
134                    /** guidelines (doesn't apply to dialogs), type: String */
135                    meta_guidelines(913),
136                    
137                    /** conversation picture, in jpeg format (doesn't apply to dialogs), type: byte[] */
138                    meta_picture(914);
139                    
140                    private static final Map<Integer,PROPERTY> lookup = new HashMap<Integer,PROPERTY>();
141                    
142                    static {
143                            for(PROPERTY s : EnumSet.allOf(PROPERTY.class))
144                                    lookup.put(s.getId(), s);
145                    }
146                    
147                    private final int id;
148                    
149                    private PROPERTY(int value) {
150                            this.id = value;
151                    }
152                    
153                    public int getId() { return id; }
154                    
155                    public static PROPERTY get(int code) {
156                            return lookup.get(code);
157                    }
158                    
159                    public static PROPERTY fromString(String s) {
160                            for (PROPERTY p : lookup.values()) {
161                                    if (p.toString() == s) {
162                                            return p;
163                                    }
164                            }
165                            return null;
166                    }
167            }
168            
169            public Object GetPropertyAsEnum(int propid) {
170                    return PROPERTY.get(propid);
171            }
172            
173            public String GetStrProperty(PROPERTY prop) {
174                    //check in propcache if so then return
175                    if (mPropCache.containsKey(new Integer(prop.id))){
176                            String value =  (String)mPropCache.get(prop.id);
177                            if (value != null && !(value.length() == 0) ){
178                                    return value;
179                            }
180                    }
181                    //else get from skypekit...
182                    GetPropertyRequest request = new GetPropertyRequest(18, mObjectId, prop.id);
183                    
184                    String string = null;
185                    GetPropertyResponse r = skype.GetProperty(request);
186                    if (r != null){
187                            string = r.GetAsString();
188                    }
189                    
190                    if (string != null)
191                    {
192                            mPropCache.put(new Integer(prop.id), string);
193                    }
194                    return string;
195            }
196            
197            public int GetIntProperty(PROPERTY prop) {
198                    //check in propcache if so then return
199                    if (mPropCache.containsKey(new Integer(prop.id))){
200                            int value = ((Integer)mPropCache.get(prop.id)).intValue();
201                            if (value != 0){
202                                    return value;
203                            }
204                    }
205                    //else get from skypekit...
206                    GetPropertyRequest request = new GetPropertyRequest(moduleID(), mObjectId, prop.id);
207                    
208                    Integer integer = null;
209                    GetPropertyResponse r = skype.GetProperty(request);
210                    if (r != null){
211                            integer  = r.GetAsInt();
212                    }
213                    
214                    if (integer != null)
215                    {
216                            mPropCache.put(new Integer(prop.id), integer);
217                            return integer.intValue();
218                    }
219                    else
220                    {
221                            return 0;
222                    }
223            }
224            
225            public boolean GetBooleanProperty(PROPERTY prop) {
226                    //check in propcache if so then return
227                    if (mPropCache.containsKey(new Integer(prop.id))){
228                            return ((Boolean)mPropCache.get(prop.id)).booleanValue();
229                    }
230                    //else get from skypekit...
231                    GetPropertyRequest request = new GetPropertyRequest(moduleID(), mObjectId, prop.id);
232                    
233                    Boolean boolResp = null;
234                    GetPropertyResponse r = skype.GetProperty(request);
235                    if (r != null){
236                            boolResp  = r.GetAsBoolean();
237                    }
238                    
239                    if (boolResp != null)
240                    {
241                            mPropCache.put(new Integer(prop.id), boolResp);
242                            return boolResp.booleanValue();
243                    }
244                    else
245                    {
246                            return false;
247                    }
248            }
249            
250            public byte [] GetBinProperty(PROPERTY prop) {
251                    //get from skypekit...
252                    GetPropertyRequest request = new GetPropertyRequest(18, mObjectId, prop.id);
253                    
254                    byte [] data = null;
255                    GetPropertyResponse r = skype.GetProperty(request);
256                    if (r != null) {
257                            data = r.GetAsBinary();
258                    }
259                    return data;
260            }
261            
262            /**default array of Conversation Properties that get fetched & cached upon class construction*/
263            private static PROPERTY [] defaultProperties = { PROPERTY.identity, PROPERTY.type, PROPERTY.given_displayname, PROPERTY.displayname, PROPERTY.last_activity_timestamp, PROPERTY.live_host, PROPERTY.consumption_horizon, PROPERTY.unconsumed_suppressed_messages, PROPERTY.unconsumed_normal_messages};
264            
265            private void GetDefaultProps() {
266                    MultiGetPropertyRequest request = null;
267                    ArrayList<Integer> proparray = null;
268                            /**Add the single oid into array*/
269                            ArrayList<Integer> oidarray=new ArrayList<Integer>();
270                            oidarray.add(mObjectId);
271                            
272                            /**Add all requested propids into array*/
273                            proparray=new ArrayList<Integer>();
274                            for (PROPERTY defaultProp : defaultProperties) {
275                                    proparray.add(defaultProp.getId());
276                            }
277                            /**Generate the request*/
278                            request = new MultiGetPropertyRequest(moduleID(), oidarray,proparray);
279                            
280                            /** Make Multi Get call*/
281                            GetPropertyResponse r=skype.MultiGetProperty(request);
282                            /**Verify that it is a proper multiresponse*/
283                            if(!r.isMultiresponse())
284                            {
285                                    return;
286                            }
287                            /**update property cache with results*/
288                            mPropCache.putAll(r.GetAsMap(mObjectId, proparray));
289                    }
290                    
291                    /** Setupkey SETUPKEY_ENABLE_BIRTHDAY_NOTIFICATION type:int default value:"1" <br>Enables/disables birthday notification messages. <br> - 0 - disable;  <br> - 1 - enable; <br>This is account-specific setup key. It can only be used while an account is logged in. <br> */
292                    public static final String ENABLE_BIRTHDAY_NOTIFICATION = "Lib/Conversation/EnableBirthday";
293                    
294                    /** Setupkey SETUPKEY_INBOX_UPDATE_TIMEOUT type:int  <br>Timeout in seconds, how old the Conversation.P_INBOX_TIMESTAMP has to be for it to be re-sorted in the inbox. <br>This is account-specific setup key. It can only be used while an account is logged in. <br> */
295                    public static final String INBOX_UPDATE_TIMEOUT = "Lib/Conversation/InboxUpdateTimeout";
296                    
297                    /** Setupkey SETUPKEY_RECENTLY_LIVE_TIMEOUT type:int default value:"20" <br>The number of seconds a formerly live conversation will remain the Conversation.LIVE_CONVERSATIONS filter. Note that while the conversation remains in Conversation.LIVE_CONVERSATIONS filter, Skype.OnConversationListChange events will not fire if there is another call coming up within the same conversation. Seeting this key to 0 will cause conversations to exit the Conversation.LIVE_CONVERSATIONS list immediately, after live state drops. <br><br>This is account-specific setup key. It can only be used while an account is logged in. <br> */
298                    public static final String RECENTLY_LIVE_TIMEOUT = "Lib/Conversation/RecentlyLiveTimeout";
299                    
300                    /** Setupkey SETUPKEY_DISABLE_CHAT type:int  Disables chat (for voice only clients). <br>This setup key is machine-specific and affects all local accounts. <br> */
301                    public static final String DISABLE_CHAT = "Lib/Chat/DisableChat";
302                    
303                    /** Setupkey SETUPKEY_DISABLE_CHAT_HISTORY type:int  <br>Disables storage of chat history. <br>This is account-specific setup key. It can only be used while an account is logged in. <br> */
304                    public static final String DISABLE_CHAT_HISTORY = "Lib/Message/DisableHistory";
305                    
306                    /** Setupkey SETUPKEY_CHAT_HISTORY_DAYS type:int  <br>Time limit for keeping local chat message history. <br>This is account-specific setup key. It can only be used while an account is logged in. <br> */
307                    public static final String CHAT_HISTORY_DAYS = "Lib/Chat/HistoryDays";
308                    
309                    /** Setupkey SETUPKEY_CHATDB_LIMIT_KB type:int default value:"0" Use this key to limit the size of the chat db. Value is in KB. By default there is no limit. A minimum of 16 MB is recommended. */
310                    public static final String CHATDB_LIMIT_KB = "Lib/Chat/ChatDBLimitKb";
311                    
312                    /** Setupkey SETUPKEY_DISABLE_CHAT_ACTIVITY_INDICATION type:int  <br>Enables/disables transmitting typing indicator signals to othe participants of conversations. <br> - 0 - disable;  <br> - 1 - enable; <br>This is account-specific setup key. It can only be used while an account is logged in. <br> */
313                    public static final String DISABLE_CHAT_ACTIVITY_INDICATION = "Lib/Chat/DisableActivityIndication";
314                    
315                    /** Setupkey SETUPKEY_CALL_NOANSWER_TIMEOUT type:int default value:"15" <br>Timeout in seconds after which the incoming live session will stop ringing (and if possible, proceed to voicemail or call forward). <br>This is account-specific setup key. It can only be used while an account is logged in. <br> */
316                    public static final String CALL_NOANSWER_TIMEOUT = "Lib/Call/NoAnswerTimeout";
317                    
318                    /** Setupkey SETUPKEY_CALL_SEND_TO_VM type:int  <br>Autoforwarding of incoming calls to voicemail. <br> - 0 - off <br> - 1 - on <br>This is account-specific setup key. It can only be used while an account is logged in. <br> */
319                    public static final String CALL_SEND_TO_VM = "Lib/Call/SendToVM";
320                    
321                    /** Setupkey SETUPKEY_CALL_APPLY_CF type:int  <br>Enables/disables call forwarding. <br> - 0 - disable;  <br> - 1 - enable; <br>This is account-specific setup key. It can only be used while an account is logged in. <br> */
322                    public static final String CALL_APPLY_CF = "Lib/Call/ApplyCF";
323                    
324                    /** Setupkey SETUPKEY_CALL_EMERGENCY_COUNTRY type:string  <br>Country code for emergency calls <br>This is account-specific setup key. It can only be used while an account is logged in. <br> */
325                    public static final String CALL_EMERGENCY_COUNTRY = "Lib/Call/EmergencyCountry";
326                    
327                    /**
328                     */
329                    public enum TYPE {
330                    
331                            /** 1:1 conversations, there is a one dialog per identity*/
332                            DIALOG(1),
333                            
334                            /** equivalent of a multichat*/
335                            CONFERENCE(2),
336                            
337                            /** a conference that has been terminated (disbanded chat)*/
338                            TERMINATED_CONFERENCE(3),
339                            
340                            /** voice-only conference, when host is using a legacy non-conversation client*/
341                            LEGACY_VOICE_CONFERENCE(4),
342                            
343                            /** chat used for legacy shared groups, can be ignored*/
344                            LEGACY_SHAREDGROUP(5);
345                            
346                            private static final Map<Integer,TYPE> lookup = new HashMap<Integer,TYPE>();
347                            
348                            static {
349                                    for(TYPE s : EnumSet.allOf(TYPE.class))
350                                            lookup.put(s.getId(), s);
351                            }
352                            
353                            private final int id;
354                            
355                            private TYPE(int value) {
356                                    this.id = value;
357                            }
358                            
359                            public int getId() { return id; }
360                            
361                            public static TYPE get(int code) {
362                                    return lookup.get(code);
363                            }
364                            
365                            public static TYPE fromString(String s) {
366                                    for (TYPE p : lookup.values()) {
367                                            if (p.toString() == s) {
368                                                    return p;
369                                            }
370                                    }
371                                    return null;
372                            }
373                    }
374                    
375                    /**
376                     */
377                    public enum MY_STATUS {
378                    
379                            /** connecting to conference*/
380                            CONNECTING(1),
381                            
382                            /** */
383                            RETRY_CONNECTING(2),
384                            
385                            /** unused*/
386                            DOWNLOADING_MESSAGES(3),
387                            
388                            /** conference is full for now, being queued*/
389                            QUEUED_TO_ENTER(4),
390                            
391                            /** I'm applying to join the conference*/
392                            APPLICANT(5),
393                            
394                            /** My application to join the conference was denied*/
395                            APPLICATION_DENIED(6),
396                            
397                            /** The password I provided is incorrect*/
398                            INVALID_ACCESS_TOKEN(7),
399                            
400                            /** I'm part of the conference, I can participate*/
401                            CONSUMER(8),
402                            
403                            /** I was kicked from the conference*/
404                            RETIRED_FORCEFULLY(9),
405                            
406                            /** I left the conference*/
407                            RETIRED_VOLUNTARILY(10);
408                            
409                            private static final Map<Integer,MY_STATUS> lookup = new HashMap<Integer,MY_STATUS>();
410                            
411                            static {
412                                    for(MY_STATUS s : EnumSet.allOf(MY_STATUS.class))
413                                            lookup.put(s.getId(), s);
414                            }
415                            
416                            private final int id;
417                            
418                            private MY_STATUS(int value) {
419                                    this.id = value;
420                            }
421                            
422                            public int getId() { return id; }
423                            
424                            public static MY_STATUS get(int code) {
425                                    return lookup.get(code);
426                            }
427                            
428                            public static MY_STATUS fromString(String s) {
429                                    for (MY_STATUS p : lookup.values()) {
430                                            if (p.toString() == s) {
431                                                    return p;
432                                            }
433                                    }
434                                    return null;
435                            }
436                    }
437                    
438                    /**
439                     */
440                    public enum LOCAL_LIVESTATUS {
441                    
442                            /** there isn't a live session*/
443                            NONE(0),
444                            
445                            /** trying to start or join a live session*/
446                            STARTING(1),
447                            
448                            /** there is a live session ringing*/
449                            RINGING_FOR_ME(2),
450                            
451                            /** the conference is live for me*/
452                            IM_LIVE(3),
453                            
454                            /** I put the live session on hold*/
455                            ON_HOLD_LOCALLY(5),
456                            
457                            /** the live session was put on hold by someone else*/
458                            ON_HOLD_REMOTELY(6),
459                            
460                            /** there is a live session on-going, I'm not participating but I could join*/
461                            OTHERS_ARE_LIVE(7),
462                            
463                            /** there is a live session on-going without me, but I can't join because it's full*/
464                            OTHERS_ARE_LIVE_FULL(11),
465                            
466                            /** playing a voicemail (dialog only)*/
467                            PLAYING_VOICE_MESSAGE(8),
468                            
469                            /** recording a voicemail (dialog only)*/
470                            RECORDING_VOICE_MESSAGE(9),
471                            
472                            /** a live session just finished, we stay in this state for RECENTLY_LIVE_TIMEOUT setup key*/
473                            RECENTLY_LIVE(10),
474                            
475                            /** call is being transferred*/
476                            TRANSFERRING(12);
477                            
478                            private static final Map<Integer,LOCAL_LIVESTATUS> lookup = new HashMap<Integer,LOCAL_LIVESTATUS>();
479                            
480                            static {
481                                    for(LOCAL_LIVESTATUS s : EnumSet.allOf(LOCAL_LIVESTATUS.class))
482                                            lookup.put(s.getId(), s);
483                            }
484                            
485                            private final int id;
486                            
487                            private LOCAL_LIVESTATUS(int value) {
488                                    this.id = value;
489                            }
490                            
491                            public int getId() { return id; }
492                            
493                            public static LOCAL_LIVESTATUS get(int code) {
494                                    return lookup.get(code);
495                            }
496                            
497                            public static LOCAL_LIVESTATUS fromString(String s) {
498                                    for (LOCAL_LIVESTATUS p : lookup.values()) {
499                                            if (p.toString() == s) {
500                                                    return p;
501                                            }
502                                    }
503                                    return null;
504                            }
505                    }
506                    
507                    /**
508                    values for opt_admin_only_activities property */
509                    public enum ALLOWED_ACTIVITY {
510                    
511                            /** allowed to set the CONVERSATION_META properties*/
512                            SET_META(1),
513                            
514                            /** allowed to add participants to the conference*/
515                            ADD_CONSUMERS(2),
516                            
517                            /** allowed to speak, but not write*/
518                            SPEAK(4),
519                            
520                            /** allowed to speak and write*/
521                            SPEAK_AND_WRITE(8);
522                            
523                            private static final Map<Integer,ALLOWED_ACTIVITY> lookup = new HashMap<Integer,ALLOWED_ACTIVITY>();
524                            
525                            static {
526                                    for(ALLOWED_ACTIVITY s : EnumSet.allOf(ALLOWED_ACTIVITY.class))
527                                            lookup.put(s.getId(), s);
528                            }
529                            
530                            private final int id;
531                            
532                            private ALLOWED_ACTIVITY(int value) {
533                                    this.id = value;
534                            }
535                            
536                            public int getId() { return id; }
537                            
538                            public static ALLOWED_ACTIVITY get(int code) {
539                                    return lookup.get(code);
540                            }
541                            
542                            public static ALLOWED_ACTIVITY fromString(String s) {
543                                    for (ALLOWED_ACTIVITY p : lookup.values()) {
544                                            if (p.toString() == s) {
545                                                    return p;
546                                            }
547                                    }
548                                    return null;
549                            }
550                    }
551                    
552                    /**
553                     *Setter method for Conversation option properties. Option properties are all Conversation properties starting with OPT_ prefix. <br>
554                     * @param propKey Conversation property key, for example: Conversation.OPT_JOINING_ENABLED <br>
555                     * @param value New value for the option property. <br>
556                     */
557                    public void SetOption( int propKey, int value) {
558                    
559                            Request request = null;
560                            try {
561                                    request = new XCallRequest(18,1);
562                            } catch (IOException e) {
563                                    e.printStackTrace();
564                                    if (skype.errorListener != null)
565                                            skype.errorListener.OnSkypeKitFatalError();
566                            }
567                            request.addParm('O',0,mObjectId);
568                            request.addParm('e',1,propKey);
569                            request.addParm('u',2,value);
570                            
571                            skype.XCall((XCallRequest)request);
572                    }
573                    
574                    /**
575                     *Setter for Conversation class META_TOPIC. This topic will be set for remote participants as well. <br>
576                     * @param topic New conversation topic. <br>
577                     * @param isXML Notifies remote UIs that the new topic contains xml tags. <br>
578                     */
579                    public void SetTopic( String topic, boolean isXML) {
580                    
581                            Request request = null;
582                            try {
583                                    request = new XCallRequest(18,2);
584                            } catch (IOException e) {
585                                    e.printStackTrace();
586                                    if (skype.errorListener != null)
587                                            skype.errorListener.OnSkypeKitFatalError();
588                            }
589                            request.addParm('O',0,mObjectId);
590                            request.addParm('S',1,topic);
591                            request.addParm('b',2,isXML);
592                            
593                            skype.XCall((XCallRequest)request);
594                    }
595                    
596                    /**
597                     *Setter for Conversation META_GUIDELINES. This property will be visible to remote participants of the conversation. <br>
598                     * @param guidelines New value for the META_GUIDELINES property. <br>
599                     * @param isXML Set true to notify remote UIs that the new guideline contains XML tags. <br>
600                     */
601                    public void SetGuidelines( String guidelines, boolean isXML) {
602                    
603                            Request request = null;
604                            try {
605                                    request = new XCallRequest(18,3);
606                            } catch (IOException e) {
607                                    e.printStackTrace();
608                                    if (skype.errorListener != null)
609                                            skype.errorListener.OnSkypeKitFatalError();
610                            }
611                            request.addParm('O',0,mObjectId);
612                            request.addParm('S',1,guidelines);
613                            request.addParm('b',2,isXML);
614                            
615                            skype.XCall((XCallRequest)request);
616                    }
617                    
618                    /**
619                     *Sets the conversation's avatar to the specified JPEG image, which is propagated to both local and remote participants. Before calling this method, you should use Skype.ValidateAvatar to verify that jpeg references a valid JPEG image. <br>
620                     * @param jpeg Conversation avatar binary. <br>
621                     */
622                    public void SetPicture( byte[] jpeg) {
623                    
624                            Request request = null;
625                            try {
626                                    request = new XCallRequest(18,4);
627                            } catch (IOException e) {
628                                    e.printStackTrace();
629                                    if (skype.errorListener != null)
630                                            skype.errorListener.OnSkypeKitFatalError();
631                            }
632                            request.addParm('O',0,mObjectId);
633                            request.addParm('B',1,jpeg);
634                            
635                            skype.XCall((XCallRequest)request);
636                    }
637                    
638                    /**
639                     *When called from dialog conversation, this spawns a new conversation, with existing two dialog participants plus new contact identities given in the identitiesToAdd list. You do not need to add existing dialog participants to the string list. In fact, passing only the existing participants in the identities list will cause the method call to fail (return false), the same as if the list was empty. This method will also return false if the original conversation was not a dialog (contained more than two participants). Also note that this method always creates a new Conversation - even if a conversation with exactly the same participant list existed before. <br>
640                     * @param identitiesToAdd String list of additional participant identities. You do not need to add existing two participants from the original dialog to this list. <br>
641                     * @return conference Returns the resulting conversation or 0 if the method call failed. <br>
642                     */
643                    public Conversation SpawnConference( String [] identitiesToAdd) {
644                    
645                            Request request = null;
646                            try {
647                                    request = new XCallRequest(18,6);
648                            } catch (IOException e) {
649                                    e.printStackTrace();
650                                    if (skype.errorListener != null)
651                                            skype.errorListener.OnSkypeKitFatalError();
652                            }
653                            request.addParm('O',0,mObjectId);
654                            request.addListStart(1);
655                            for (int i=0;i<identitiesToAdd.length;i++) {
656                                    request.addParm('S',identitiesToAdd[i]);
657                            }
658                            
659                            Response r = skype.XCall((XCallRequest)request);
660                            
661                            if (r.isErrCall())
662                                    return null;
663                                    
664                            int oid = 0;
665                            Conversation conference = null;
666                            oid = r.GetOid(1);
667                            if (oid != AbstractDecoder.NULL_VALUE) {
668                                    conference = (Conversation)skype.factory(Conversation.moduleID(), oid, skype);
669                            }
670                            return conference;
671                    }
672                    
673                    /**
674                     *Takes one or more Contact identities and creates corresponding Participant objects within the context of this Conversation, which must be of type CONFERENCE. If you have an existing dialog conversation, use SpawnConference instead. <br>
675                     * @param identities Contact identities to be added to the Conversation. <br>
676                     */
677                    public void AddConsumers( String [] identities) {
678                    
679                            Request request = null;
680                            try {
681                                    request = new XCallRequest(18,7);
682                            } catch (IOException e) {
683                                    e.printStackTrace();
684                                    if (skype.errorListener != null)
685                                            skype.errorListener.OnSkypeKitFatalError();
686                            }
687                            request.addParm('O',0,mObjectId);
688                            request.addListStart(1);
689                            for (int i=0;i<identities.length;i++) {
690                                    request.addParm('S',identities[i]);
691                            }
692                            
693                            skype.XCall((XCallRequest)request);
694                    }
695                    
696                    /**
697                     *Merges two live conversations. For example, if the user already has a live conversation up - let's call it conversation A. Then a new incoming call occurs - another conversation obtains LOCAL_LIVESTATUS == Conversation.RINGING_FOR_ME, let's call it conversation B. The user wishes to pick up the new incoming call and add it to the existing one. For this you can first call B->JoinLiveSession and then merge two calls with A->Assimilate(B, A). The second argument will return the merged conversation. Note that there are actually three conversation objects involved: A (before merge), B and C (after the merge). Normally it would make sense to have the first conversation (A) as the second argument, so that it gets overwritten with the assimilation result. <br>
698                     * @param otherConversation The new conversation to be merged with the one already in live state. <br>
699                     * @return conversation Returns a 3rd live conversation, result of merging two existing ones. <br>
700                     */
701                    public Conversation Assimilate( Conversation otherConversation) {
702                    
703                            Request request = null;
704                            try {
705                                    request = new XCallRequest(18,9);
706                            } catch (IOException e) {
707                                    e.printStackTrace();
708                                    if (skype.errorListener != null)
709                                            skype.errorListener.OnSkypeKitFatalError();
710                            }
711                            request.addParm('O',0,mObjectId);
712                            request.addParm('O',1,otherConversation.getOid());
713                            
714                            Response r = skype.XCall((XCallRequest)request);
715                            
716                            if (r.isErrCall())
717                                    return null;
718                                    
719                            int oid = 0;
720                            Conversation conversation = null;
721                            oid = r.GetOid(1);
722                            if (oid != AbstractDecoder.NULL_VALUE) {
723                                    conversation = (Conversation)skype.factory(Conversation.moduleID(), oid, skype);
724                            }
725                            return conversation;
726                    }
727                    
728                    /**
729                     *starts, answers or joins a live session (first one to join becomes LIVE_HOST)
730                     * @param accessToken if starting a live session, allows to set a custom access token
731                     */
732                    public void JoinLiveSession( String accessToken) {
733                    
734                            Request request = null;
735                            try {
736                                    request = new XCallRequest(18,10);
737                            } catch (IOException e) {
738                                    e.printStackTrace();
739                                    if (skype.errorListener != null)
740                                            skype.errorListener.OnSkypeKitFatalError();
741                            }
742                            request.addParm('O',0,mObjectId);
743                            request.addParm('S',1,accessToken);
744                            
745                            skype.XCall((XCallRequest)request);
746                    }
747                    
748                    /**
749                     *This is an alternative to calling Ring method for each Participant individually. This also works with dialogs (with identities containing only one item). <br>
750                     * @param identities List of Participants to ring. Leaving the list empty will result in ringing all participants of at least speaker level. <br>
751                     * @param videoCall If true, indicates that we want to do a video call (video still needs to be separately enabled) <br>
752                     * @param origin When call is initiated from web link, this argument must contain the URI that was used <br>
753                     */
754                    public void RingOthers( String [] identities, boolean videoCall, String origin) {
755                    
756                            Request request = null;
757                            try {
758                                    request = new XCallRequest(18,36);
759                            } catch (IOException e) {
760                                    e.printStackTrace();
761                                    if (skype.errorListener != null)
762                                            skype.errorListener.OnSkypeKitFatalError();
763                            }
764                            request.addParm('O',0,mObjectId);
765                            request.addListStart(1);
766                            for (int i=0;i<identities.length;i++) {
767                                    request.addParm('S',identities[i]);
768                            }
769                            request.addParm('b',2,videoCall);
770                            request.addParm('S',3,origin);
771                            
772                            skype.XCall((XCallRequest)request);
773                    }
774                    
775                    /**
776                     *Sets VOICE_STATUS to LISTENING in the Participant instance associated with us, causing any input from our microphone to be ignored. This is a Conversation class method, rather than Participant class, because this only applies to local participant. <br>
777                     */
778                    public void MuteMyMicrophone() {
779                    
780                            Request request = null;
781                            try {
782                                    request = new XCallRequest(18,11);
783                            } catch (IOException e) {
784                                    e.printStackTrace();
785                                    if (skype.errorListener != null)
786                                            skype.errorListener.OnSkypeKitFatalError();
787                            }
788                            request.addParm('O',0,mObjectId);
789                            
790                            skype.XCall((XCallRequest)request);
791                    }
792                    
793                    /**
794                     *Sets VOICE_STATUS to SPEAKING in the Participant instance associated with us, causing any input from our microphone to be sent to the call host. This is a Conversation class method, rather than Participant class, because this only applies to local participant. <br>
795                     */
796                    public void UnmuteMyMicrophone() {
797                    
798                            Request request = null;
799                            try {
800                                    request = new XCallRequest(18,12);
801                            } catch (IOException e) {
802                                    e.printStackTrace();
803                                    if (skype.errorListener != null)
804                                            skype.errorListener.OnSkypeKitFatalError();
805                            }
806                            request.addParm('O',0,mObjectId);
807                            
808                            skype.XCall((XCallRequest)request);
809                    }
810                    
811                    /**
812                     *Puts the conversation on hold - Conversation LOCAL_LIVESTATUS changes to ON_HOLD_LOCALLY and to ON_HOLD_REMOTELY for remote participants. <br>
813                     */
814                    public void HoldMyLiveSession() {
815                    
816                            Request request = null;
817                            try {
818                                    request = new XCallRequest(18,13);
819                            } catch (IOException e) {
820                                    e.printStackTrace();
821                                    if (skype.errorListener != null)
822                                            skype.errorListener.OnSkypeKitFatalError();
823                            }
824                            request.addParm('O',0,mObjectId);
825                            
826                            skype.XCall((XCallRequest)request);
827                    }
828                    
829                    /**
830                     *Resumes call from local hold. <br>
831                     */
832                    public void ResumeMyLiveSession() {
833                    
834                            Request request = null;
835                            try {
836                                    request = new XCallRequest(18,14);
837                            } catch (IOException e) {
838                                    e.printStackTrace();
839                                    if (skype.errorListener != null)
840                                            skype.errorListener.OnSkypeKitFatalError();
841                            }
842                            request.addParm('O',0,mObjectId);
843                            
844                            skype.XCall((XCallRequest)request);
845                    }
846                    
847                    /**
848                     *Hang up or refuse to answer an incoming call. Set postVoiceAutoresponse to true to enable a caller to leave a voicemail message. <br>
849                     * @param postVoiceAutoresponse
850                     */
851                    public void LeaveLiveSession( boolean postVoiceAutoresponse) {
852                    
853                            Request request = null;
854                            try {
855                                    request = new XCallRequest(18,15);
856                            } catch (IOException e) {
857                                    e.printStackTrace();
858                                    if (skype.errorListener != null)
859                                            skype.errorListener.OnSkypeKitFatalError();
860                            }
861                            request.addParm('O',0,mObjectId);
862                            request.addParm('b',1,postVoiceAutoresponse);
863                            
864                            skype.XCall((XCallRequest)request);
865                    }
866                    
867                    /**
868                     *Begin recording a voice mail for this conversation's remote participant. Applies to conversations of type DIALOG only. <br>
869                     */
870                    public void StartVoiceMessage() {
871                    
872                            Request request = null;
873                            try {
874                                    request = new XCallRequest(18,45);
875                            } catch (IOException e) {
876                                    e.printStackTrace();
877                                    if (skype.errorListener != null)
878                                            skype.errorListener.OnSkypeKitFatalError();
879                            }
880                            request.addParm('O',0,mObjectId);
881                            
882                            skype.XCall((XCallRequest)request);
883                    }
884                    
885                    /**
886                     *This method is for doing call transfers. NB! Call transfers only work in one-on-one conversations (dialogs). Before attempting call transfer, you should check availability of transfer recipients with Conversation class CanTransferLiveSession method. If the current conversation has a live session up, that session (call) will be transferred to targets specified in the identities list. Note that identities is a string list - all identities in that list will get incoming calls. The first one of them to pick up the call - wins, and rest of the transfer targets will stop ringing. <br><br>Let's take a closer look how this works in practice. We have three call participants involved in the process, and two separate conversations. Let there be three callers: Caller A (call originator), Caller B (transferor) and Caller C (recipient of transfer). <br><br> - Caller A - calls Caller B; Caller B picks up the call - live conversation C1 is now up with A and B in it. <br> - After awhile, Caller B initiates call transfers to Caller C (and optionally to Callers D, E, F.. ). LOCAL_LIVESTATUS of C1 will get set to TRANSFERRING for both A and B. <br> - Caller C picks up the call. Conversation C1 will go off live status. For Caller B, conversation C1 LOCAL_LIVESTATUS will change to RECENTLY_LIVE. Another live conversation - C2 gets spawned, with Caller A and Caller C in it. For caller C, participant object representing caller A will have TRANSFERRED_BY property set to identity of caller A. For Caller B (in now no longer live conversation C1), participant object representing caller A gets its TRANSFERRED_TO property set to identity of caller C. <br>
887                     * @param identities String list of transfer target identities. As soon as first one in this list picks up the call, others will stop ringing. <br>
888                     * @param transferTopic Optional conversation topic. This value will get set as META_TOPIC property of the conversation at the transferee end. Note that this is the only case where META_TOPIC field is used in context of dialog conversations. Thus assumption that remote UI will display topic field in case of dialogs may not be 100% correct. <br>
889                     */
890                    public void TransferLiveSession( String [] identities, String transferTopic) {
891                    
892                            Request request = null;
893                            try {
894                                    request = new XCallRequest(18,40);
895                            } catch (IOException e) {
896                                    e.printStackTrace();
897                                    if (skype.errorListener != null)
898                                            skype.errorListener.OnSkypeKitFatalError();
899                            }
900                            request.addParm('O',0,mObjectId);
901                            request.addListStart(1);
902                            for (int i=0;i<identities.length;i++) {
903                                    request.addParm('S',identities[i]);
904                            }
905                            request.addParm('S',2,transferTopic);
906                            
907                            skype.XCall((XCallRequest)request);
908                    }
909                    
910                    /**
911                     *Checks if the identity is available for receiving a transferred live session. If you are going to attempt to go for multiple transfer targets, you should use this check for all the target identities. <br>
912                     * @param identity Target identity. <br>
913                     * @return result Returns true if call transfer to given target is possible. <br>
914                     */
915                    public boolean CanTransferLiveSession( String identity) {
916                    
917                            Request request = null;
918                            try {
919                                    request = new XCallRequest(18,46);
920                            } catch (IOException e) {
921                                    e.printStackTrace();
922                                    if (skype.errorListener != null)
923                                            skype.errorListener.OnSkypeKitFatalError();
924                            }
925                            request.addParm('O',0,mObjectId);
926                            request.addParm('S',1,identity);
927                            
928                            Response r = skype.XCall((XCallRequest)request);
929                            
930                            if (r.isErrCall())
931                                    return false;
932                                    
933                            boolean result = false;
934                            result = r.GetAsBoolean(1);
935                            return result;
936                    }
937                    
938                    /**
939                     *Sends DTMF tone to a live conversation. <br>
940                     * @param dtmf Outgoing dtmf tone, possible values come from Participant.DTMF enumerator. <br>
941                     * @param lengthInMS Duration in milliseconds. Defaults to 260 ms. Note that the DTMF tone can be also cancelled with Conversation.StopSendDTMF method. <br>
942                     */
943                    public void SendDTMF( Participant.DTMF dtmf, int lengthInMS) {
944                    
945                            Request request = null;
946                            try {
947                                    request = new XCallRequest(18,16);
948                            } catch (IOException e) {
949                                    e.printStackTrace();
950                                    if (skype.errorListener != null)
951                                            skype.errorListener.OnSkypeKitFatalError();
952                            }
953                            request.addParm('O',0,mObjectId);
954                            request.addParm('e',1,dtmf.getId());
955                            request.addParm('u',2,lengthInMS);
956                            
957                            skype.XCall((XCallRequest)request);
958                    }
959                    
960                    /**
961                     *Stops the current DTMF tone being played into conversation. For example, use this method to cancel DTMF signals started with Conversation.SendDTMF before the duration given in lengthInMS runs out. <br>
962                     */
963                    public void StopSendDTMF() {
964                    
965                            Request request = null;
966                            try {
967                                    request = new XCallRequest(18,48);
968                            } catch (IOException e) {
969                                    e.printStackTrace();
970                                    if (skype.errorListener != null)
971                                            skype.errorListener.OnSkypeKitFatalError();
972                            }
973                            request.addParm('O',0,mObjectId);
974                            
975                            skype.XCall((XCallRequest)request);
976                    }
977                    
978                    /**
979                     *Sets local user typing indicator in the Conversation. Remote Participants can display these in their UI. <br>
980                     * @param status Typing indicator status value - Participant.TEXT_STATUS <br>
981                     */
982                    public void SetMyTextStatusTo( Participant.TEXT_STATUS status) {
983                    
984                            Request request = null;
985                            try {
986                                    request = new XCallRequest(18,18);
987                            } catch (IOException e) {
988                                    e.printStackTrace();
989                                    if (skype.errorListener != null)
990                                            skype.errorListener.OnSkypeKitFatalError();
991                            }
992                            request.addParm('O',0,mObjectId);
993                            request.addParm('e',1,status.getId());
994                            
995                            skype.XCall((XCallRequest)request);
996                    }
997                    
998                    /**
999                     *Posts the specified text the conversation, and populates message with a reference to the corresponding Message object (if no error occurred during execution). The isXML argument can be used if the client UI has already taken care of converting message text to xml (for example, your UI might enable users to use bold tags in text messages.) <br>
1000                     * @param text Text value of the outgoing message (gets set as BODY_XML property of the Message object). <br>
1001                     * @param isXML For cases where the text argument was already encoded as xml message. <br>
1002                     * @return message Returns the Message object created as a result of this method (if successful). <br>
1003                     */
1004                    public Message PostText( String text, boolean isXML) {
1005                    
1006                            Request request = null;
1007                            try {
1008                                    request = new XCallRequest(18,19);
1009                            } catch (IOException e) {
1010                                    e.printStackTrace();
1011                                    if (skype.errorListener != null)
1012                                            skype.errorListener.OnSkypeKitFatalError();
1013                            }
1014                            request.addParm('O',0,mObjectId);
1015                            request.addParm('S',1,text);
1016                            request.addParm('b',2,isXML);
1017                            
1018                            Response r = skype.XCall((XCallRequest)request);
1019                            
1020                            if (r.isErrCall())
1021                                    return null;
1022                                    
1023                            int oid = 0;
1024                            Message message = null;
1025                            oid = r.GetOid(1);
1026                            if (oid != AbstractDecoder.NULL_VALUE) {
1027                                    message = (Message)skype.factory(Message.moduleID(), oid, skype);
1028                            }
1029                            return message;
1030                    }
1031                    
1032                    /**
1033                     *Takes a list of Contacts as an argument and posts the list into the Conversation. The purpose of this feature is to enable sharing contacts between users, without resorting to contact search. Instead, if user A has contacts B and C, he can post contact C into chat with contact B. At this point, Contact B can add contact C to his contact list. From remote side, the posted contacts will appear as messages with type Message.POSTED_CONTACTS appearing in the conversation. The UI should allow adding these contacts from messages with this type into the contact list. <br><br>The list of posted contacts can be retrieved with the Message.GetContacts method.  <br><br>Additionally, the UI then can parse the posted Contact data out of the Message.P_BODY_XML property. The list of contacts is wrapped between <contacts ..> </contacts> tags. Each contact item in the xml has following format: <br> - t - contact type. "s" - skype contact; "p" - phone number; <br> - s - skypename, present only in skypename contacts (t="s") <br> - p - phone number, present only in phone number contacts (t="p") <br> - f - contact's full name, if available <br> - d - contact's display name, if available <br><br>Note that only the type (t) field is mandatory. Depending on type, either skypename (s) or phone number (p) fields are always present. Full name and display name fields are optional. <br><br>Example BODY_XML with skypname contact:  <br>@code <br><contacts alt="alt text"><c t="s" s="skypename" f="full name"/></contacts> <br></CODE> <br><br>Example BODY_XML with PSTN contact:  <br>@code <br><contacts alt="alt text"><c t="p" p="+37212345678" d="Some PSTN number"/></contacts> <br></CODE>  <br><br>Example BODY_XML with multiple contacts:  <br>@code <br><contacts alt="alt text"><c t="p" p="+37212345678" d="Some PSTN number"/><c t="s" s="someskypename"/></contacts> <br></CODE> <br>
1034                     * @param contacts List of Contact objects, to be posted in the conversation. <br>
1035                     */
1036                    public void PostContacts( Contact [] contacts) {
1037                    
1038                            Request request = null;
1039                            try {
1040                                    request = new XCallRequest(18,20);
1041                            } catch (IOException e) {
1042                                    e.printStackTrace();
1043                                    if (skype.errorListener != null)
1044                                            skype.errorListener.OnSkypeKitFatalError();
1045                            }
1046                            request.addParm('O',0,mObjectId);
1047                            request.addListStart(1);
1048                            for (int i=0;i<contacts.length;i++) {
1049                                    request.addParm('O',contacts[i].getOid());
1050                            }
1051                            
1052                            skype.XCall((XCallRequest)request);
1053                    }
1054                    
1055                    /**
1056                     *Takes a list of fully-qualified filenames and initiates corresponding file transfers in the conversation. From the remote side, incoming file transfers will appear as a conversation message with type POSTED_FILES. Once such a message is detected, the list of file transfer objects can be retrieved with Message.GetTransfers. At that point, remote participants will need to accept or decline those transfers. <br>
1057                     * @param paths list of fully-qualified filenames to be transferred <br>
1058                     * @param body Optional BODY_XML property for POSTED_FILES type messages that show up in remote UI. <br>
1059                     * @return PostFilesResult
1060                     */
1061                    public PostFilesResult PostFiles( String [] paths, String body) {
1062                    
1063                            Request request = null;
1064                            try {
1065                                    request = new XCallRequest(18,21);
1066                            } catch (IOException e) {
1067                                    e.printStackTrace();
1068                                    if (skype.errorListener != null)
1069                                            skype.errorListener.OnSkypeKitFatalError();
1070                            }
1071                            request.addParm('O',0,mObjectId);
1072                            request.addListStart(1);
1073                            for (int i=0;i<paths.length;i++) {
1074                                    request.addParm('f',paths[i]);
1075                            }
1076                            request.addParm('S',2,body);
1077                            
1078                            Response r = skype.XCall((XCallRequest)request);
1079                            
1080                            if (r.isErrCall())
1081                                    return null;
1082                                    
1083                            PostFilesResult result = new PostFilesResult();
1084                            
1085                            Skype.TRANSFER_SENDFILE_ERROR error_code = null;
1086                            error_code = Skype.TRANSFER_SENDFILE_ERROR.get(r.GetAsInt(1));
1087                            result.error_code = error_code;
1088                            
1089                            String error_file = null;
1090                            error_file = r.GetAsString(2);
1091                            result.error_file = error_file;
1092                            
1093                            return result;
1094                    }
1095                    
1096                    public class PostFilesResult {
1097                            public Skype.TRANSFER_SENDFILE_ERROR error_code; /** Error code, possible values come from the TRANSFER_SENDFILE_ERROR enumerator. This will be set for the first failed fail. The failed file is identified in the error_file return argument. <br> */
1098                            public String error_file; /** Filename of the file that triggered error. <br> */
1099                    }
1100                    
1101                    /**
1102                     * Stop recording a voice mail for this conversation's remote participant and send it. Applies to conversations of type DIALOG only. <br>
1103                     *Stops the active voicemail recording and sends it (dialog only)
1104                     * @param voicemail This argument is deprecated as of SDK version 3.2. Instead of manually constructing Voicemail object, you can call Conversation.StartVoiceMessage method to start recording a voicemail in context of a dialog. PostVoiceMessage will stop recording this voicemail and post it in the dialog. If instead of sending Voicemail, the user decides to cancel it, you should use Conversation.LeaveLiveSession method (Voicemail.Cancel is deprecated). <br>
1105                     * @param body Optional text message that remote UI can display in conversation, to notify the user of a new voicemail. <br>
1106                     */
1107                    public void PostVoiceMessage( Voicemail voicemail, String body) {
1108                    
1109                            Request request = null;
1110                            try {
1111                                    request = new XCallRequest(18,22);
1112                            } catch (IOException e) {
1113                                    e.printStackTrace();
1114                                    if (skype.errorListener != null)
1115                                            skype.errorListener.OnSkypeKitFatalError();
1116                            }
1117                            request.addParm('O',0,mObjectId);
1118                            request.addParm('O',1,voicemail.getOid());
1119                            request.addParm('S',2,body);
1120                            
1121                            skype.XCall((XCallRequest)request);
1122                    }
1123                    
1124                    /**
1125                     *Takes an SMS instance created by Skype.CreateOutgoingSms and posts it in the conversation. Note that you will need to set both Sms body text (Sms.SetBody) and recipient list (Sms.SetTargets) before you can post the object. <br>
1126                     * @param sms SMS object. <br>
1127                     * @param body This argument is currently ignored. The message text needs to be set with Sms.SetBody method, prior to passing the Sms object to this method <br>
1128                     */
1129                    public void PostSMS( Sms sms, String body) {
1130                    
1131                            Request request = null;
1132                            try {
1133                                    request = new XCallRequest(18,23);
1134                            } catch (IOException e) {
1135                                    e.printStackTrace();
1136                                    if (skype.errorListener != null)
1137                                            skype.errorListener.OnSkypeKitFatalError();
1138                            }
1139                            request.addParm('O',0,mObjectId);
1140                            request.addParm('O',1,sms.getOid());
1141                            request.addParm('S',2,body);
1142                            
1143                            skype.XCall((XCallRequest)request);
1144                    }
1145                    
1146                    /**
1147                     *Retrieves a binary join blob for joining public conversations, which are always of type CONFERENCE. If called for a dialog, the blob argument will contain the empty string. The best way to create a Public Chat is to first create a fresh conversation with Skype class CreateConference, then minimally apply the public chat options OPT_JOINING_ENABLED and OPT_ENTRY_LEVEL_RANK - options, like this (C++):  <br>@code <br>C->SetOption(Conversation.OPT_JOINING_ENABLED, true); <br></CODE> <br><br>When that is done, you can call GetJoinBlob to retrieve the blob string. Use the blob string to generate and post an HTML link whose href attribute looks like this: href="skype:?chat&blob=_BLOB_GOES_HERE" A person running Skype desktop client can click this link to join the conversation and have that conversation opened in his UI. Note that the conversation host (creator) needs to be online for new joiners-via-link to start participating in the Public Chat.
1148                     * @return blob Returns the public conversation join blob. <br>
1149                     */
1150                    public String GetJoinBlob() {
1151                    
1152                            Request request = null;
1153                            try {
1154                                    request = new XCallRequest(18,24);
1155                            } catch (IOException e) {
1156                                    e.printStackTrace();
1157                                    if (skype.errorListener != null)
1158                                            skype.errorListener.OnSkypeKitFatalError();
1159                            }
1160                            request.addParm('O',0,mObjectId);
1161                            
1162                            Response r = skype.XCall((XCallRequest)request);
1163                            
1164                            if (r.isErrCall())
1165                                    return null;
1166                                    
1167                            String blob = null;
1168                            blob = r.GetAsString(1);
1169                            return blob;
1170                    }
1171                    
1172                    /**
1173                     *Tries to join a public conversation (aka public chat). This method is only useful if you have used Skype.GetConversationByBlob method with alsoJoin argument set to false. <br>
1174                     */
1175                    public void Join() {
1176                    
1177                            Request request = null;
1178                            try {
1179                                    request = new XCallRequest(18,25);
1180                            } catch (IOException e) {
1181                                    e.printStackTrace();
1182                                    if (skype.errorListener != null)
1183                                            skype.errorListener.OnSkypeKitFatalError();
1184                            }
1185                            request.addParm('O',0,mObjectId);
1186                            
1187                            skype.XCall((XCallRequest)request);
1188                    }
1189                    
1190                    /**
1191                     *Submits password for joining password-protected conversation. <br>
1192                     * @param password Password string. <br>
1193                     */
1194                    public void EnterPassword( String password) {
1195                    
1196                            Request request = null;
1197                            try {
1198                                    request = new XCallRequest(18,26);
1199                            } catch (IOException e) {
1200                                    e.printStackTrace();
1201                                    if (skype.errorListener != null)
1202                                            skype.errorListener.OnSkypeKitFatalError();
1203                            }
1204                            request.addParm('O',0,mObjectId);
1205                            request.addParm('S',1,password);
1206                            
1207                            skype.XCall((XCallRequest)request);
1208                    }
1209                    
1210                    /**
1211                     *Sets password protection/new password for the conversation. <br>
1212                     * @param password New password. <br>
1213                     * @param hint Password hint. <br>
1214                     */
1215                    public void SetPassword( String password, String hint) {
1216                    
1217                            Request request = null;
1218                            try {
1219                                    request = new XCallRequest(18,27);
1220                            } catch (IOException e) {
1221                                    e.printStackTrace();
1222                                    if (skype.errorListener != null)
1223                                            skype.errorListener.OnSkypeKitFatalError();
1224                            }
1225                            request.addParm('O',0,mObjectId);
1226                            request.addParm('S',1,password);
1227                            request.addParm('S',2,hint);
1228                            
1229                            skype.XCall((XCallRequest)request);
1230                    }
1231                    
1232                    /**
1233                     *Leaves the conference. Not applicable to dialogs. <br>
1234                     */
1235                    public void RetireFrom() {
1236                    
1237                            Request request = null;
1238                            try {
1239                                    request = new XCallRequest(18,28);
1240                            } catch (IOException e) {
1241                                    e.printStackTrace();
1242                                    if (skype.errorListener != null)
1243                                            skype.errorListener.OnSkypeKitFatalError();
1244                            }
1245                            request.addParm('O',0,mObjectId);
1246                            
1247                            skype.XCall((XCallRequest)request);
1248                    }
1249                    
1250                    /**
1251                     *Deletes this conversation, which must be of type CONFERENCE - dialogs between local user and any of his contacts are always persistant. Note that this also removes corresponding Message and Participant objects. <br>
1252                     */
1253                    public void Delete() {
1254                    
1255                            Request request = null;
1256                            try {
1257                                    request = new XCallRequest(18,47);
1258                            } catch (IOException e) {
1259                                    e.printStackTrace();
1260                                    if (skype.errorListener != null)
1261                                            skype.errorListener.OnSkypeKitFatalError();
1262                            }
1263                            request.addParm('O',0,mObjectId);
1264                            
1265                            skype.XCall((XCallRequest)request);
1266                    }
1267                    
1268                    /**
1269                     *Changes the META_NAME property of the conversation. Note that unlike topic and guidelines, this rename is just local - remote participants can have their own private names for conversations. <br>
1270                     * @param name New name for the conversation. Passing an empty string in this argument causes the META_NAME to unset. <br>
1271                     */
1272                    public void RenameTo( String name) {
1273                    
1274                            Request request = null;
1275                            try {
1276                                    request = new XCallRequest(18,29);
1277                            } catch (IOException e) {
1278                                    e.printStackTrace();
1279                                    if (skype.errorListener != null)
1280                                            skype.errorListener.OnSkypeKitFatalError();
1281                            }
1282                            request.addParm('O',0,mObjectId);
1283                            request.addParm('S',1,name);
1284                            
1285                            skype.XCall((XCallRequest)request);
1286                    }
1287                    
1288                    /**
1289                     *Setter for Conversation class IS_BOOKMARKED. <br>
1290                     * @param bookmark Set true to set the bookmark, false to remove the bookmark. <br>
1291                     */
1292                    public void SetBookmark( boolean bookmark) {
1293                    
1294                            Request request = null;
1295                            try {
1296                                    request = new XCallRequest(18,30);
1297                            } catch (IOException e) {
1298                                    e.printStackTrace();
1299                                    if (skype.errorListener != null)
1300                                            skype.errorListener.OnSkypeKitFatalError();
1301                            }
1302                            request.addParm('O',0,mObjectId);
1303                            request.addParm('b',1,bookmark);
1304                            
1305                            skype.XCall((XCallRequest)request);
1306                    }
1307                    
1308                    /**
1309                     *Setter for Conversation class ALERT_STRING property. The main use of this property is checking bodies of incoming messages in the conversation for the alert string and producing notifications in UI for the user, when appropriate. <br>
1310                     * @param alertString Substring to check in BODY_XML property of incoming messages. <br>
1311                     */
1312                    public void SetAlertString( String alertString) {
1313                    
1314                            Request request = null;
1315                            try {
1316                                    request = new XCallRequest(18,31);
1317                            } catch (IOException e) {
1318                                    e.printStackTrace();
1319                                    if (skype.errorListener != null)
1320                                            skype.errorListener.OnSkypeKitFatalError();
1321                            }
1322                            request.addParm('O',0,mObjectId);
1323                            request.addParm('S',1,alertString);
1324                            
1325                            skype.XCall((XCallRequest)request);
1326                    }
1327                    
1328                    /**
1329                     *Removes conversation from Inbox. <br>
1330                     */
1331                    public void RemoveFromInbox() {
1332                    
1333                            Request request = null;
1334                            try {
1335                                    request = new XCallRequest(18,32);
1336                            } catch (IOException e) {
1337                                    e.printStackTrace();
1338                                    if (skype.errorListener != null)
1339                                            skype.errorListener.OnSkypeKitFatalError();
1340                            }
1341                            request.addParm('O',0,mObjectId);
1342                            
1343                            skype.XCall((XCallRequest)request);
1344                    }
1345                    
1346                    /**
1347                     *Sets Conversation inbox_timestamp property. If the timestamp argument is left empty or is greater than conversation consumption horizon, then the conversation will be restored to the inbox. <br>
1348                     * @param timestamp If left empty or set to 0, the inbox_timestamp property is set to current time. <br>
1349                     */
1350                    public void AddToInbox( int timestamp) {
1351                    
1352                            Request request = null;
1353                            try {
1354                                    request = new XCallRequest(18,33);
1355                            } catch (IOException e) {
1356                                    e.printStackTrace();
1357                                    if (skype.errorListener != null)
1358                                            skype.errorListener.OnSkypeKitFatalError();
1359                            }
1360                            request.addParm('O',0,mObjectId);
1361                            request.addParm('u',1,timestamp);
1362                            
1363                            skype.XCall((XCallRequest)request);
1364                    }
1365                    
1366                    /**
1367                     *This method can be used to set the consumption (read) status of messages in the conversation. It sets Message.CONSUMPTION_STATUS to Message.CONSUMED for all messages in the conversation, older than the given timestamp. If the second argument is set to true, it also modifies messages more recent than the timestamp, by marking them as unconsumed. <br>
1368                     * @param timestamp Consumption cutoff timestamp. Setting this to current time will mark all messages in the conversation as consumed. <br>
1369                     * @param also_unconsume If set to true, this also marks messages newer than the cutoff timestamp as unconsumed. For example, setting timestamp to 0 and also_unconsumed to true, will unconsume all messages in the conversation. <br>
1370                     */
1371                    public void SetConsumedHorizon( int timestamp, boolean also_unconsume) {
1372                    
1373                            Request request = null;
1374                            try {
1375                                    request = new XCallRequest(18,34);
1376                            } catch (IOException e) {
1377                                    e.printStackTrace();
1378                                    if (skype.errorListener != null)
1379                                            skype.errorListener.OnSkypeKitFatalError();
1380                            }
1381                            request.addParm('O',0,mObjectId);
1382                            request.addParm('u',1,timestamp);
1383                            request.addParm('b',2,also_unconsume);
1384                            
1385                            skype.XCall((XCallRequest)request);
1386                    }
1387                    
1388                    /**
1389                     *sets consumption horizon to last inbox message id timestamp
1390                     */
1391                    public void MarkUnread() {
1392                    
1393                            Request request = null;
1394                            try {
1395                                    request = new XCallRequest(18,35);
1396                            } catch (IOException e) {
1397                                    e.printStackTrace();
1398                                    if (skype.errorListener != null)
1399                                            skype.errorListener.OnSkypeKitFatalError();
1400                            }
1401                            request.addParm('O',0,mObjectId);
1402                            
1403                            skype.XCall((XCallRequest)request);
1404                    }
1405                    
1406                    /**
1407                     *Checks if the conversation is a member of the given ContactGroup <br>
1408                     * @param group ContactGroup <br>
1409                     * @return result True if this conversation is a member of the ContactGroup specified by the group argument contains the conversation <br>
1410                     */
1411                    public boolean IsMemberOf( ContactGroup group) {
1412                    
1413                            Request request = null;
1414                            try {
1415                                    request = new XCallRequest(18,37);
1416                            } catch (IOException e) {
1417                                    e.printStackTrace();
1418                                    if (skype.errorListener != null)
1419                                            skype.errorListener.OnSkypeKitFatalError();
1420                            }
1421                            request.addParm('O',0,mObjectId);
1422                            request.addParm('O',1,group.getOid());
1423                            
1424                            Response r = skype.XCall((XCallRequest)request);
1425                            
1426                            if (r.isErrCall())
1427                                    return false;
1428                                    
1429                            boolean result = false;
1430                            result = r.GetAsBoolean(1);
1431                            return result;
1432                    }
1433                    
1434                    /**
1435                     */
1436                    public enum PARTICIPANTFILTER {
1437                    
1438                            /** All participants (may included some that are RETIRED or OUTLAW, but not all of them)*/
1439                            ALL(0),
1440                            
1441                            /** Participants that can receive messages, including myself*/
1442                            CONSUMERS(1),
1443                            
1444                            /** Only people who are applying to join the conversation*/
1445                            APPLICANTS(2),
1446                            
1447                            /** Consumers and applicants*/
1448                            CONSUMERS_AND_APPLICANTS(3),
1449                            
1450                            /** Myself*/
1451                            MYSELF(4),
1452                            
1453                            /** All consumers except myself*/
1454                            OTHER_CONSUMERS(5);
1455                            
1456                            private static final Map<Integer,PARTICIPANTFILTER> lookup = new HashMap<Integer,PARTICIPANTFILTER>();
1457                            
1458                            static {
1459                                    for(PARTICIPANTFILTER s : EnumSet.allOf(PARTICIPANTFILTER.class))
1460                                            lookup.put(s.getId(), s);
1461                            }
1462                            
1463                            private final int id;
1464                            
1465                            private PARTICIPANTFILTER(int value) {
1466                                    this.id = value;
1467                            }
1468                            
1469                            public int getId() { return id; }
1470                            
1471                            public static PARTICIPANTFILTER get(int code) {
1472                                    return lookup.get(code);
1473                            }
1474                            
1475                            public static PARTICIPANTFILTER fromString(String s) {
1476                                    for (PARTICIPANTFILTER p : lookup.values()) {
1477                                            if (p.toString() == s) {
1478                                                    return p;
1479                                            }
1480                                    }
1481                                    return null;
1482                            }
1483                    }
1484                    
1485                    /**
1486                     *Retrieves the list of this conversation's current participants, which you can optionally request to be filtered. If no Participants pass the filter, an empty list will be returned (the method itself still returns true). <br>
1487                     * @param filter Conversation.PARTICIPANTFILTER - defaults to Conversation.ALL <br>
1488                     * @return participants List of conversation Participant objects that passed the filter. <br>
1489                     */
1490                    public Participant [] GetParticipants( Conversation.PARTICIPANTFILTER filter) {
1491                    
1492                            Request request = null;
1493                            try {
1494                                    request = new XCallRequest(18,38);
1495                            } catch (IOException e) {
1496                                    e.printStackTrace();
1497                                    if (skype.errorListener != null)
1498                                            skype.errorListener.OnSkypeKitFatalError();
1499                            }
1500                            request.addParm('O',0,mObjectId);
1501                            request.addParm('e',1,filter.getId());
1502                            
1503                            Response r = skype.XCall((XCallRequest)request);
1504                            
1505                            if (r.isErrCall())
1506                                    return null;
1507                                    
1508                            Vector<Participant> participants = new Vector<Participant>();
1509                            while (r.HasMore(1))
1510                            {
1511                                    int oid = 0;
1512                                    Participant participant = null;
1513                                    oid = r.GetOid(1);
1514                                    if (oid != AbstractDecoder.NULL_VALUE) { 
1515                                            participant = (Participant)skype.factory(Participant.moduleID(), oid, skype);
1516                                    }
1517                                    participants.add(participant);
1518                            }
1519                            return participants.toArray(new Participant[participants.size()]);
1520                            
1521                    }
1522                    
1523                    /**
1524                     *Returns recent messages. The messages are returned in two lists - new messages (unconsumed) and recent message history (context messages). The context message list contains messages that are already above the consumption horizon but are fairly recent, making it likely that displaying them in UI would be good default behaviour. <br>
1525                     * @param requireTimestamp If set to a non-zero value, includes messages no earlier than this timestamp, if not, includes messages from the last 24 hours only <br>
1526                     * @return GetLastMessagesResult
1527                     */
1528                    public GetLastMessagesResult GetLastMessages( int requireTimestamp) {
1529                    
1530                            Request request = null;
1531                            try {
1532                                    request = new XCallRequest(18,39);
1533                            } catch (IOException e) {
1534                                    e.printStackTrace();
1535                                    if (skype.errorListener != null)
1536                                            skype.errorListener.OnSkypeKitFatalError();
1537                            }
1538                            request.addParm('O',0,mObjectId);
1539                            request.addParm('u',1,requireTimestamp);
1540                            
1541                            Response r = skype.XCall((XCallRequest)request);
1542                            
1543                            if (r.isErrCall())
1544                                    return null;
1545                                    
1546                            GetLastMessagesResult result = new GetLastMessagesResult();
1547                            
1548                            Vector<Message> contextMessages = new Vector<Message>();
1549                            while (r.HasMore(1))
1550                            {
1551                                    int oid = 0;
1552                                    Message message = null;
1553                                    oid = r.GetOid(1);
1554                                    if (oid != AbstractDecoder.NULL_VALUE) { 
1555                                            message = (Message)skype.factory(Message.moduleID(), oid, skype);
1556                                    }
1557                                    contextMessages.add(message);
1558                            }
1559                            result.contextMessages = contextMessages.toArray(new Message[contextMessages.size()]);
1560                            
1561                            Vector<Message> unconsumedMessages = new Vector<Message>();
1562                            while (r.HasMore(2))
1563                            {
1564                                    int oid = 0;
1565                                    Message message = null;
1566                                    oid = r.GetOid(2);
1567                                    if (oid != AbstractDecoder.NULL_VALUE) { 
1568                                            message = (Message)skype.factory(Message.moduleID(), oid, skype);
1569                                    }
1570                                    unconsumedMessages.add(message);
1571                            }
1572                            result.unconsumedMessages = unconsumedMessages.toArray(new Message[unconsumedMessages.size()]);
1573                            
1574                            return result;
1575                    }
1576                    
1577                    public class GetLastMessagesResult {
1578                            public Message [] contextMessages; /** Already consumed messages, provided for context */
1579                            public Message [] unconsumedMessages; /** Unconsumed messages */
1580                    }
1581                    
1582                    /**
1583                     *Finds the most recent Message object in the conversation that contains the substring specified by the text argument. If no matching messages are found, this method will return false. The search proceeds backwards in time, starting from the timestamp argument. To continue searching, you can start with timestamp=MAX_UINT, retrieve the TIMESTAMP property of the matching message, decrement it by one, and submit it as timestamp for the next FindMessage call. <br>
1584                     * @param text Substring to search for. <br>
1585                     * @param fromTimestampUp
1586                     * @return message Returns matching message or 0 if there was no match. As the likelihood of this object being invalid is quite high, you should always check for method return value before you start calling methods of this object. <br>
1587                     */
1588                    public Message FindMessage( String text, int fromTimestampUp) {
1589                    
1590                            Request request = null;
1591                            try {
1592                                    request = new XCallRequest(18,41);
1593                            } catch (IOException e) {
1594                                    e.printStackTrace();
1595                                    if (skype.errorListener != null)
1596                                            skype.errorListener.OnSkypeKitFatalError();
1597                            }
1598                            request.addParm('O',0,mObjectId);
1599                            request.addParm('S',1,text);
1600                            request.addParm('u',2,fromTimestampUp);
1601                            
1602                            Response r = skype.XCall((XCallRequest)request);
1603                            
1604                            if (r.isErrCall())
1605                                    return null;
1606                                    
1607                            int oid = 0;
1608                            Message message = null;
1609                            oid = r.GetOid(1);
1610                            if (oid != AbstractDecoder.NULL_VALUE) {
1611                                    message = (Message)skype.factory(Message.moduleID(), oid, skype);
1612                            }
1613                            return message;
1614                    }
1615                    
1616                    /**
1617                     */
1618                    public enum LIST_TYPE {
1619                    
1620                            /** bookmarked or in_inbox or live or with_meta_info or activity in last 30 days*/
1621                            ALL_CONVERSATIONS(0),
1622                            
1623                            /** only last 6 months conversations are kept there*/
1624                            INBOX_CONVERSATIONS(1),
1625                            
1626                            /** is_bookmarked is set*/
1627                            BOOKMARKED_CONVERSATIONS(2),
1628                            
1629                            /** local_livestatus is different from NONE*/
1630                            LIVE_CONVERSATIONS(3),
1631                            
1632                            /** all conversations, without any of the limits of ALL_CONVERSATIONS*/
1633                            REALLY_ALL_CONVERSATIONS(5);
1634                            
1635                            private static final Map<Integer,LIST_TYPE> lookup = new HashMap<Integer,LIST_TYPE>();
1636                            
1637                            static {
1638                                    for(LIST_TYPE s : EnumSet.allOf(LIST_TYPE.class))
1639                                            lookup.put(s.getId(), s);
1640                            }
1641                            
1642                            private final int id;
1643                            
1644                            private LIST_TYPE(int value) {
1645                                    this.id = value;
1646                            }
1647                            
1648                            public int getId() { return id; }
1649                            
1650                            public static LIST_TYPE get(int code) {
1651                                    return lookup.get(code);
1652                            }
1653                            
1654                            public static LIST_TYPE fromString(String s) {
1655                                    for (LIST_TYPE p : lookup.values()) {
1656                                            if (p.toString() == s) {
1657                                                    return p;
1658                                            }
1659                                    }
1660                                    return null;
1661                            }
1662                    }
1663                    
1664            
1665            }