    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                    /**Deprecated: Use the other OnMessage*/
    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                    /** name assigned via GiveDisplayname, 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 (doesn't apply to dialogs), 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                    /** user-set name, separate from topic (doesn't apply to dialogs), 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            }