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