001    package com.skype.api;
002    
003    import com.skype.ipc.SidRoot;
004    import com.skype.ipc.SidObject;
005    import com.skype.ipc.EnumConverting;
006    import com.skype.ipc.PropertyEnumConverting;
007    import com.skype.ipc.Decoding;
008    import com.skype.ipc.Encoding;
009    import com.skype.ipc.Encoding;
010    import java.io.IOException;
011    import com.skype.ipc.PropertyEnumConverting;
012    import com.skype.ipc.SidGetResponding;
013    
014    /**
015     * Wrapper class that includes voicemail-specific methods and properties. In the Skype Conversation API, Voicemail is actually something of a misnomer for what would be more accurately called Voice Message. 
016     * 
017     * The traditional Voicemail use case involves recording a voice message when an incoming call does not get answered in a pre-determined amount of time. In the Skype Conversation API, voicemail does not depend on a call going unanswered - you can post a voice message asynchronously into any dialog conversation at any time. 
018     * 
019     * In fact, a high-level action flow directing unanswered incoming live sessions to voicemail is not something provided by the Conversation API - implementation of this use case is largely up to your UI. 
020     * 
021     * The fact that your UI must retrieve incoming Voicemails by monitoring changes to a Conversation instance's Messages illustrates this conceptual difference between traditional voicemail and voice messages. The message type Message.POSTED_VOICE_MESSAGE indicates that a Message instance should be handled as a voice message instead of by displaying its body text in the Conversation UI. Message.GetVoiceMessage enables you to retrieve the associated Voicemail instance; Voicemail.StartPlayback enables you to listen to the message audio. 
022     * 
023     * To put it another way, the object chain goes like this:  
024     * @code 
025     * Contact->Conversation->Message->Voicemail  
026     * </CODE>  
027     * 
028     * There are three basic types of Voicemail objects: 
029     *  - INCOMING - received voice messages that can be retrieved from Message objects; 
030     *  - OUTGOING - outbound voice messages that can be created with Conversation.StartVoiceMessage; 
031     *  - GREETING - voice messages that represent auto-answer greetings, either recorded by the user (CUSTOM_GREETING) or included as part of SkypeKit (DEFAULT_GREETING). This is the audio that gets played back to sender of the voice message before he can start recording his voice message. 
032     * 
033     * Before trying to send out a voicemail, you should ensure that target Contact has the capability to receive them. Use Contact.GetCapabilityStatus to check for Contact.CAPABILITY_CAN_BE_SENT_VM. 
034     * 
035     * Recording and Sending a Voice Message 
036     * 
037     * The first step is to obtain a dialog Conversation with the target Contact. In that conversation, you can initiate the outgoing voice message with Conversation.StartVoiceMessage 
038     * 
039     * Note that this call does not return an actual Voicemail object. To catch when an object gets created, you will need to check Conversation.P_ACTIVE_VM_ID property updates. 
040     * 
041     * After invoking Conversation.StartVoiceMessage, SkypeKit instantiates a Voicemail instance for the target Contact's greeting (with type CUSTOM_GREETING or DEFAULT_GREETING). At this point, the Conversation.P_ACTIVE_VM_ID property update fires, newVM contains a reference to the greeting, and playback of the greeting for the sender starts automatically.  
042     * 
043     * Once the greeting playback finishes, SkypeKit instantiates a second Voicemail instance for the outgoing voice message. At this point, the Conversation.P_ACTIVE_VM_ID property update fires again, newVM now contains a reference to the outgoing message, and recording starts automatically. If you want to include notification and/or error handling for whether this message was sent successfully, you should make a copy of newVM now. 
044     * 
045     * Once the user finishes (or abandons) recording of their message, they want to either send the message or to cancel it. To send the message, use Conversation.PostVoiceMessage; to cancel the message, use Conversation.LeaveLiveSession. 
046     * 
047     * Both of these actions results in the Conversation.P_ACTIVE_VM_ID property update firing for a third time, setting the value to NULL. However, the Voicemail object will actually continue its existence past this point. Saving a reference to the message's Voicemail object when you start recording it enables you to keep receiving Voicemail property updates. This in turn enables your UI to check whether voice message send succeeded or failed. 
048     * 
049     * The relevant terminal state Voicemail.P_STATUS property values are: 
050     *  - Voicemail.CANCELLED - recording and/or sending of this message was cancelled 
051     *  - Voicemail.UPLOADED - message sent 
052     *  - Voicemail.FAILED - message could not be sent 
053     * 
054     * Receiving and Playing Back a Voice Message 
055     * 
056     * On the remote side, the Voicemail appears as a Message object of type Message.POSTED_VOICE_MESSAGE. The message's author property contains the Skype Name of the Voicemail originator, and its BodyXml property contains the message length and title text in following format: 
057     * 
058     * @code 
059     * <voicemail alt="Sent voicemail to people in this conversation."><message length="5" ></message></voicemail>  
060     * </CODE> 
061     * 
062     * Receiver side UI can then retrieve the Voicemail object from the message with Message.GetVoiceMessage and 
063     * start local playback with Message.StartPlayback. 
064     */
065    public final class Voicemail extends SidObject {
066            public enum Type implements EnumConverting {
067                    INCOMING        (1),
068                    DEFAULT_GREETING(4),
069                    CUSTOM_GREETING (2),
070                    OUTGOING        (3);
071                    private final int key;
072                    Type(int key) {
073                            this.key = key;
074                    };
075                    public int getId()   { return key; }
076                    public EnumConverting getDefault() { return INCOMING; }
077                    public EnumConverting convert(int from) { return Type.get(from); }
078                    public EnumConverting[] getArray(final int size) { return new Type[size]; }
079                    public static Type get(int from) {
080                            switch (from) {
081                            case 1: return INCOMING;
082                            case 4: return DEFAULT_GREETING;
083                            case 2: return CUSTOM_GREETING;
084                            case 3: return OUTGOING;
085                            }
086                            return INCOMING;
087                    }
088                    public static final int INCOMING_VALUE         = 1;
089                    public static final int DEFAULT_GREETING_VALUE = 4;
090                    public static final int CUSTOM_GREETING_VALUE  = 2;
091                    public static final int OUTGOING_VALUE         = 3;
092            }
093            public enum Status implements EnumConverting {
094                    NOTDOWNLOADED  (1),
095                    DOWNLOADING    (2),
096                    UNPLAYED       (3),
097                    BUFFERING      (4),
098                    PLAYING        (5),
099                    PLAYED         (6),
100                    BLANK          (7),
101                    RECORDING      (8),
102                    RECORDED       (9),
103                    UPLOADING      (10),
104                    UPLOADED       (11),
105                    DELETING       (12),
106                    FAILED         (13),
107                    DELETING_FAILED(14),
108                    CHECKING       (15),
109                    CANCELLED      (16);
110                    private final int key;
111                    Status(int key) {
112                            this.key = key;
113                    };
114                    public int getId()   { return key; }
115                    public EnumConverting getDefault() { return NOTDOWNLOADED; }
116                    public EnumConverting convert(int from) { return Status.get(from); }
117                    public EnumConverting[] getArray(final int size) { return new Status[size]; }
118                    public static Status get(int from) {
119                            switch (from) {
120                            case  1: return NOTDOWNLOADED;
121                            case  2: return DOWNLOADING;
122                            case  3: return UNPLAYED;
123                            case  4: return BUFFERING;
124                            case  5: return PLAYING;
125                            case  6: return PLAYED;
126                            case  7: return BLANK;
127                            case  8: return RECORDING;
128                            case  9: return RECORDED;
129                            case 10: return UPLOADING;
130                            case 11: return UPLOADED;
131                            case 12: return DELETING;
132                            case 13: return FAILED;
133                            case 14: return DELETING_FAILED;
134                            case 15: return CHECKING;
135                            case 16: return CANCELLED;
136                            }
137                            return NOTDOWNLOADED;
138                    }
139                    public static final int NOTDOWNLOADED_VALUE   =  1;
140                    public static final int DOWNLOADING_VALUE     =  2;
141                    public static final int UNPLAYED_VALUE        =  3;
142                    public static final int BUFFERING_VALUE       =  4;
143                    public static final int PLAYING_VALUE         =  5;
144                    public static final int PLAYED_VALUE          =  6;
145                    public static final int BLANK_VALUE           =  7;
146                    public static final int RECORDING_VALUE       =  8;
147                    public static final int RECORDED_VALUE        =  9;
148                    public static final int UPLOADING_VALUE       = 10;
149                    public static final int UPLOADED_VALUE        = 11;
150                    public static final int DELETING_VALUE        = 12;
151                    public static final int FAILED_VALUE          = 13;
152                    public static final int DELETING_FAILED_VALUE = 14;
153                    public static final int CHECKING_VALUE        = 15;
154                    public static final int CANCELLED_VALUE       = 16;
155            }
156            public enum FailureReason implements EnumConverting {
157                    MISC_ERROR                 (1),
158                    CONNECT_ERROR              (2),
159                    NO_VOICEMAIL_CAPABILITY    (3),         NO_SUCH_VOICEMAIL          (4),
160                    FILE_READ_ERROR            (5),
161                    FILE_WRITE_ERROR           (6),
162                    RECORDING_ERROR            (7),
163                    PLAYBACK_ERROR             (8),
164                    NO_PERMISSION              (9),
165                    /** receiver turned off voicemail */
166                    RECEIVER_DISABLED_VOICEMAIL(10),
167                    /** receiver has not authorized you and privacy is not set to anyone */
168                    SENDER_NOT_AUTHORIZED      (11),
169                    /** receiver blocked sender */
170                    SENDER_BLOCKED             (12);
171                    private final int key;
172                    FailureReason(int key) {
173                            this.key = key;
174                    };
175                    public int getId()   { return key; }
176                    public EnumConverting getDefault() { return MISC_ERROR; }
177                    public EnumConverting convert(int from) { return FailureReason.get(from); }
178                    public EnumConverting[] getArray(final int size) { return new FailureReason[size]; }
179                    public static FailureReason get(int from) {
180                            switch (from) {
181                            case  1: return MISC_ERROR;
182                            case  2: return CONNECT_ERROR;
183                            case  3: return NO_VOICEMAIL_CAPABILITY;
184                            case  4: return NO_SUCH_VOICEMAIL;
185                            case  5: return FILE_READ_ERROR;
186                            case  6: return FILE_WRITE_ERROR;
187                            case  7: return RECORDING_ERROR;
188                            case  8: return PLAYBACK_ERROR;
189                            case  9: return NO_PERMISSION;
190                            case 10: return RECEIVER_DISABLED_VOICEMAIL;
191                            case 11: return SENDER_NOT_AUTHORIZED;
192                            case 12: return SENDER_BLOCKED;
193                            }
194                            return MISC_ERROR;
195                    }
196                    public static final int MISC_ERROR_VALUE                  =  1;
197                    public static final int CONNECT_ERROR_VALUE               =  2;
198                    public static final int NO_VOICEMAIL_CAPABILITY_VALUE     =  3;
199                    public static final int NO_SUCH_VOICEMAIL_VALUE           =  4;
200                    public static final int FILE_READ_ERROR_VALUE             =  5;
201                    public static final int FILE_WRITE_ERROR_VALUE            =  6;
202                    public static final int RECORDING_ERROR_VALUE             =  7;
203                    public static final int PLAYBACK_ERROR_VALUE              =  8;
204                    public static final int NO_PERMISSION_VALUE               =  9;
205                    public static final int RECEIVER_DISABLED_VOICEMAIL_VALUE = 10;
206                    public static final int SENDER_NOT_AUTHORIZED_VALUE       = 11;
207                    public static final int SENDER_BLOCKED_VALUE              = 12;
208            }
209            private final static byte[] P_TYPE_req = {(byte) 90,(byte) 71,(byte) 100,(byte) 93,(byte) 7};
210            private final static byte[] P_PARTNER_HANDLE_req = {(byte) 90,(byte) 71,(byte) 101,(byte) 93,(byte) 7};
211            private final static byte[] P_PARTNER_DISPLAY_NAME_req = {(byte) 90,(byte) 71,(byte) 102,(byte) 93,(byte) 7};
212            private final static byte[] P_STATUS_req = {(byte) 90,(byte) 71,(byte) 103,(byte) 93,(byte) 7};
213            private final static byte[] P_FAILURE_REASON_req = {(byte) 90,(byte) 71,(byte) 104,(byte) 93,(byte) 7};
214            private final static byte[] P_SUBJECT_req = {(byte) 90,(byte) 71,(byte) 105,(byte) 93,(byte) 7};
215            private final static byte[] P_TIMESTAMP_req = {(byte) 90,(byte) 71,(byte) 106,(byte) 93,(byte) 7};
216            private final static byte[] P_DURATION_req = {(byte) 90,(byte) 71,(byte) 107,(byte) 93,(byte) 7};
217            private final static byte[] P_ALLOWED_DURATION_req = {(byte) 90,(byte) 71,(byte) 108,(byte) 93,(byte) 7};
218            private final static byte[] P_PLAYBACK_PROGRESS_req = {(byte) 90,(byte) 71,(byte) 109,(byte) 93,(byte) 7};
219            private final static byte[] P_CONVERSATION_req = {(byte) 90,(byte) 71,(byte) 190,(byte) 6,(byte) 93,(byte) 7};
220            private final static byte[] P_CHAT_MSG_GUID_req = {(byte) 90,(byte) 71,(byte) 191,(byte) 6,(byte) 93,(byte) 7};
221            /** Properties of the Voicemail class */
222            public enum Property implements PropertyEnumConverting {
223                    P_UNKNOWN             (0,0,null,0,null),
224                    P_TYPE                (100, 1, P_TYPE_req, 0, Type.get(0)),
225                    P_PARTNER_HANDLE      (101, 2, P_PARTNER_HANDLE_req, 0, null),
226                    P_PARTNER_DISPLAY_NAME(102, 3, P_PARTNER_DISPLAY_NAME_req, 0, null),
227                    P_STATUS              (103, 4, P_STATUS_req, 0, Status.get(0)),
228                    P_FAILURE_REASON      (104, 5, P_FAILURE_REASON_req, 0, FailureReason.get(0)),
229                    P_SUBJECT             (105, 6, P_SUBJECT_req, 0, null),
230                    P_TIMESTAMP           (106, 7, P_TIMESTAMP_req, 0, null),
231                    P_DURATION            (107, 8, P_DURATION_req, 0, null),
232                    P_ALLOWED_DURATION    (108, 9, P_ALLOWED_DURATION_req, 0, null),
233                    P_PLAYBACK_PROGRESS   (109, 10, P_PLAYBACK_PROGRESS_req, 0, null),
234                    P_CONVERSATION        (830, 11, P_CONVERSATION_req, 18, null),
235                    P_CHAT_MSG_GUID       (831, 12, P_CHAT_MSG_GUID_req, 0, null);
236                    private final int    key;
237                    private final int    idx;
238                    private final byte[] req;
239                    private final int    mod;
240                    private final EnumConverting enumConverter;
241                    Property(int key, int idx, byte[] req, int mod, EnumConverting converter) {
242                            this.key = key;
243                            this.idx = idx;
244                            this.req = req;
245                            this.mod = mod;
246                            this.enumConverter = converter;
247                    };
248                    public boolean  isCached()    { return idx > 0;   }
249                    public int      getIdx()      { return idx;       }
250                    public int      getId()       { return key;       }
251                    public byte[]   getRequest()  { return req;       }
252                    public EnumConverting getDefault()  { return P_UNKNOWN; }
253                    public int      getModuleId() { return mod;       }
254                    public EnumConverting getEnumConverter()    { return enumConverter;   }
255                    public EnumConverting convert(final int from) { return Property.get(from); }
256                    public EnumConverting[] getArray(final int size) { return new Property[size]; }
257                    public static Property get(final int from) {
258                            switch (from) {
259                            case 100: return P_TYPE;
260                            case 101: return P_PARTNER_HANDLE;
261                            case 102: return P_PARTNER_DISPLAY_NAME;
262                            case 103: return P_STATUS;
263                            case 104: return P_FAILURE_REASON;
264                            case 105: return P_SUBJECT;
265                            case 106: return P_TIMESTAMP;
266                            case 107: return P_DURATION;
267                            case 108: return P_ALLOWED_DURATION;
268                            case 109: return P_PLAYBACK_PROGRESS;
269                            case 830: return P_CONVERSATION;
270                            case 831: return P_CHAT_MSG_GUID;
271                            }
272                            return P_UNKNOWN;
273                    }
274                    public static final int P_TYPE_VALUE                 = 100;
275                    public static final int P_PARTNER_HANDLE_VALUE       = 101;
276                    public static final int P_PARTNER_DISPLAY_NAME_VALUE = 102;
277                    public static final int P_STATUS_VALUE               = 103;
278                    public static final int P_FAILURE_REASON_VALUE       = 104;
279                    public static final int P_SUBJECT_VALUE              = 105;
280                    public static final int P_TIMESTAMP_VALUE            = 106;
281                    public static final int P_DURATION_VALUE             = 107;
282                    public static final int P_ALLOWED_DURATION_VALUE     = 108;
283                    public static final int P_PLAYBACK_PROGRESS_VALUE    = 109;
284                    public static final int P_CONVERSATION_VALUE         = 830;
285                    public static final int P_CHAT_MSG_GUID_VALUE        = 831;
286            }
287            private final static byte[] startRecording_req = {(byte) 90,(byte) 82,(byte) 7,(byte) 3};
288            /** Start recording your own auto-answer greeting message (leave message after the beep...) only. Recording of outgoing Voicemail messages start automatically (using Conversation.StartVoiceMessage) after playback of the remote side greeting message has finished.  */
289            public void startRecording() {
290                    try {
291                            sidDoRequest(startRecording_req)
292                            .endOneWay();
293                    } catch(IOException e) {
294                            mSidRoot.sidOnFatalError(e);
295                    }
296            }
297            private final static byte[] stopRecording_req = {(byte) 90,(byte) 82,(byte) 7,(byte) 4};
298            /** Stop recording of your own auto-answer greeting message only. To stop recording of and send an outgoing Voicemail, use Conversation.PostVoiceMessage.  */
299            public void stopRecording() {
300                    try {
301                            sidDoRequest(stopRecording_req)
302                            .endOneWay();
303                    } catch(IOException e) {
304                            mSidRoot.sidOnFatalError(e);
305                    }
306            }
307            private final static byte[] startPlayback_req = {(byte) 90,(byte) 82,(byte) 7,(byte) 5};
308            /** Initiates playback of a voice message  */
309            public void startPlayback() {
310                    try {
311                            sidDoRequest(startPlayback_req)
312                            .endOneWay();
313                    } catch(IOException e) {
314                            mSidRoot.sidOnFatalError(e);
315                    }
316            }
317            private final static byte[] stopPlayback_req = {(byte) 90,(byte) 82,(byte) 7,(byte) 6};
318            /** Terminates playback of a voice message  */
319            public void stopPlayback() {
320                    try {
321                            sidDoRequest(stopPlayback_req)
322                            .endOneWay();
323                    } catch(IOException e) {
324                            mSidRoot.sidOnFatalError(e);
325                    }
326            }
327            private final static byte[] delete_req = {(byte) 90,(byte) 82,(byte) 7,(byte) 7};
328            /** first from server, and then the local copy */
329            public void delete() {
330                    try {
331                            sidDoRequest(delete_req)                        .endOneWay();
332                    } catch(IOException e) {
333                            mSidRoot.sidOnFatalError(e);
334                    }
335            }
336            private final static byte[] cancel_req = {(byte) 90,(byte) 82,(byte) 7,(byte) 8};
337            /** Canceling recording of your own auto-answer greeting message. To stop recording of and cancel an outgoing Voicemail, use Conversation.LeaveLiveSession.  */
338            public void cancel() {
339                    try {
340                            sidDoRequest(cancel_req)
341                            .endOneWay();
342                    } catch(IOException e) {
343                            mSidRoot.sidOnFatalError(e);
344                    }
345            }
346            private final static byte[] checkPermission_req = {(byte) 90,(byte) 82,(byte) 7,(byte) 13};
347            /** check if we can send voicemail (unauth,blocked,no priv etc cases). only OUTGOING * @return result
348             */
349            public boolean checkPermission() {
350                    try {
351                            return sidDoRequest(checkPermission_req)
352                            .endRequest().getBoolParm(1, true);
353                    } catch(IOException e) {
354                            mSidRoot.sidOnFatalError(e);
355                            return false
356                    ;}
357            }
358            /***
359             * generic multiget of a list of Property
360             * @param requested the list of requested properties of Voicemail
361             * @return SidGetResponding
362             */
363            public SidGetResponding sidMultiGet(Property[] requested) {
364                    return super.sidMultiGet(requested);
365            }
366            /***
367             * generic multiget of list of Property for a list of Voicemail
368             * @param requested the list of requested properties
369             * @return SidGetResponding[] can be casted to (Voicemail[]) if all properties are cached
370             */
371            static public SidGetResponding[] sidMultiGet(Property[] requested, Voicemail[] objects) {
372                    return SidObject.sidMultiGet(requested, objects);
373            }
374            public Type getType() {
375                    synchronized(this) {
376                            if ((mSidCached & 0x1) != 0)
377                                    return mType;
378                    }
379                    return (Type) sidRequestEnumProperty(Property.P_TYPE);
380            }
381            /** registered username of the other party */
382            public String getPartnerHandle() {
383                    synchronized(this) {
384                            if ((mSidCached & 0x2) != 0)
385                                    return mPartnerHandle;
386                    }
387                    return sidRequestStringProperty(Property.P_PARTNER_HANDLE);
388            }
389            /** user's display name of the other party */
390            public String getPartnerDisplayName() {
391                    synchronized(this) {
392                            if ((mSidCached & 0x4) != 0)
393                                    return mPartnerDisplayName;
394                    }
395                    return sidRequestStringProperty(Property.P_PARTNER_DISPLAY_NAME);
396            }
397            public Status getStatus() {
398                    synchronized(this) {
399                            if ((mSidCached & 0x8) != 0)
400                                    return mStatus;
401                    }
402                    return (Status) sidRequestEnumProperty(Property.P_STATUS);
403            }
404            public FailureReason getFailureReason() {
405                    synchronized(this) {
406                            if ((mSidCached & 0x10) != 0)
407                                    return mFailureReason;
408                    }
409                    return (FailureReason) sidRequestEnumProperty(Property.P_FAILURE_REASON);
410            }
411            /** DEPRECATED: subject line */
412            public String getSubject() {
413                    synchronized(this) {
414                            if ((mSidCached & 0x20) != 0)
415                                    return mSubject;
416                    }
417                    return sidRequestStringProperty(Property.P_SUBJECT);
418            }
419            /** timestamp of creation */
420            public int getTimestamp() {
421                    synchronized(this) {
422                            if ((mSidCached & 0x40) != 0)
423                                    return mTimestamp;
424                    }
425                    return sidRequestUintProperty(Property.P_TIMESTAMP);
426            }
427            /** duration in seconds */
428            public int getDuration() {
429                    synchronized(this) {
430                            if ((mSidCached & 0x80) != 0)
431                                    return mDuration;
432                    }
433                    return sidRequestUintProperty(Property.P_DURATION);
434            }
435            /** max allowed duration in seconds */
436            public int getAllowedDuration() {
437                    synchronized(this) {
438                            if ((mSidCached & 0x100) != 0)
439                                    return mAllowedDuration;
440                    }
441                    return sidRequestUintProperty(Property.P_ALLOWED_DURATION);
442            }
443            /** VM playback progress in seconds */
444            public int getPlaybackProgress() {
445                    synchronized(this) {
446                            if ((mSidCached & 0x200) != 0)
447                                    return mPlaybackProgress;
448                    }
449                    return sidRequestUintProperty(Property.P_PLAYBACK_PROGRESS);
450            }
451            /** CONVERSATION_ID of corresponding conversation */
452            public Conversation getConversation() {
453                    synchronized(this) {
454                            if ((mSidCached & 0x400) != 0)
455                                    return mConversation;
456                    }
457                    return (Conversation) sidRequestObjectProperty(Property.P_CONVERSATION);
458            }
459            /** GUID of the message that the VM is tied to */
460            public byte[] getChatMsgGuid() {
461                    synchronized(this) {
462                            if ((mSidCached & 0x800) != 0)
463                                    return mChatMsgGuid;
464                    }
465                    return sidRequestBinaryProperty(Property.P_CHAT_MSG_GUID);
466            }
467            public String sidGetStringProperty(final PropertyEnumConverting prop) {
468                    switch(prop.getId()) {
469                    case 101:
470                            return mPartnerHandle;
471                    case 102:
472                            return mPartnerDisplayName;
473                    case 105:
474                            return mSubject;
475                    }
476                    return "";
477            }
478            public SidObject sidGetObjectProperty(final PropertyEnumConverting prop) {
479                    assert(prop.getId() == 830);
480                    return mConversation;
481            }
482            public int sidGetIntProperty(final PropertyEnumConverting prop) {
483                    switch(prop.getId()) {
484                    case 106:
485                            return mTimestamp;
486                    case 107:
487                            return mDuration;
488                    case 108:
489                            return mAllowedDuration;
490                    case 109:
491                            return mPlaybackProgress;
492                    }
493                    return 0;
494            }
495            public EnumConverting sidGetEnumProperty(final PropertyEnumConverting prop) {
496                    switch(prop.getId()) {
497                    case 100:
498                            return mType;
499                    case 103:
500                            return mStatus;
501                    case 104:
502                            return mFailureReason;
503                    }
504                    return null;
505            }
506            public byte[] sidGetBinaryProperty(final PropertyEnumConverting prop) {
507                    assert(prop.getId() == 831);
508                    return mChatMsgGuid;
509            }
510            public String getPropertyAsString(final int prop) {
511                    switch (prop) {
512                    case 100: return getType().toString();
513                    case 101: return getPartnerHandle();
514                    case 102: return getPartnerDisplayName();
515                    case 103: return getStatus().toString();
516                    case 104: return getFailureReason().toString();
517                    case 105: return getSubject();
518                    case 106: return Integer.toString(getTimestamp());
519                    case 107: return Integer.toString(getDuration());
520                    case 108: return Integer.toString(getAllowedDuration());
521                    case 109: return Integer.toString(getPlaybackProgress());
522                    case 830: return Integer.toString(getConversation().getOid());
523                    case 831: return "<binary>";
524                    }
525                    return "<unkown>";
526            }
527            public String getPropertyAsString(final Property prop) {
528                    return getPropertyAsString(prop.getId());
529            }
530            protected void sidOnChangedProperty(final int propertyId, final int value, final String svalue) {
531                    final Property property = Property.get(propertyId);
532                    if (property == Property.P_UNKNOWN) return;
533                    final int idx = property.getIdx();
534                    if (idx != 0) {
535                            int bit  = 1<<((idx-1)%32);
536                            synchronized (this) {
537                                    mSidCached|=bit;
538                                    switch (propertyId) {
539                                    case 100: mType = Type.get(value); break;
540                                    case 101:
541                                            if (svalue != null) mPartnerHandle = svalue;
542                                            else mSidCached &=~bit;
543                                            break;
544                                    case 102:
545                                            if (svalue != null) mPartnerDisplayName = svalue;
546                                            else mSidCached &=~bit;
547                                            break;
548                                    case 103: mStatus = Status.get(value); break;
549                                    case 104: mFailureReason = FailureReason.get(value); break;
550                                    case 105:
551                                            if (svalue != null) mSubject = svalue;
552                                            else mSidCached &=~bit;
553                                            break;
554                                    case 106: mTimestamp = value; break;
555                                    case 107: mDuration = value; break;
556                                    case 108: mAllowedDuration = value; break;
557                                    case 109: mPlaybackProgress = value; break;
558                                    default: mSidCached|=bit; break;
559                                    }
560                            }
561                    }
562                    VoicemailListener listener = ((Skype) mSidRoot).getVoicemailListener();
563                    if (listener != null)
564                            listener.onPropertyChange(this, property, value, svalue);
565            }
566            public void sidSetProperty(final PropertyEnumConverting prop, final String newValue) {
567                    final int propId = prop.getId();
568                    switch(propId) {
569                    case 101:
570                            mSidCached |= 0x2;
571                            mPartnerHandle=  newValue;
572                            break;
573                    case 102:
574                            mSidCached |= 0x4;
575                            mPartnerDisplayName=  newValue;
576                            break;
577                    case 105:
578                            mSidCached |= 0x20;
579                            mSubject=  newValue;
580                            break;
581                    }
582            }
583            public void sidSetProperty(final PropertyEnumConverting prop, final SidObject newValue) {
584                    final int propId = prop.getId();
585                    assert(propId == 830);
586                    mSidCached |= 0x400;
587                    mConversation= (Conversation) newValue;
588            }
589            public void sidSetProperty(final PropertyEnumConverting prop, final int newValue) {
590                    final int propId = prop.getId();
591                    switch(propId) {
592                    case 100:
593                            mSidCached |= 0x1;
594                            mType= Type.get(newValue);
595                            break;
596                    case 103:
597                            mSidCached |= 0x8;
598                            mStatus= Status.get(newValue);
599                            break;
600                    case 104:
601                            mSidCached |= 0x10;
602                            mFailureReason= FailureReason.get(newValue);
603                            break;
604                    case 106:
605                            mSidCached |= 0x40;
606                            mTimestamp=  newValue;
607                            break;
608                    case 107:
609                            mSidCached |= 0x80;
610                            mDuration=  newValue;
611                            break;
612                    case 108:
613                            mSidCached |= 0x100;                    mAllowedDuration=  newValue;
614                            break;
615                    case 109:
616                            mSidCached |= 0x200;
617                            mPlaybackProgress=  newValue;
618                            break;
619                    }
620            }
621            public void sidSetProperty(final PropertyEnumConverting prop, final byte[] newValue) {
622                    final int propId = prop.getId();
623                    assert(propId == 831);
624                    mSidCached |= 0x800;
625                    mChatMsgGuid=  newValue;
626            }
627            public Type          mType;
628            public String        mPartnerHandle;
629            public String        mPartnerDisplayName;
630            public Status        mStatus;
631            public FailureReason mFailureReason;
632            public String        mSubject;
633            public int           mTimestamp;
634            public int           mDuration;
635            public int           mAllowedDuration;
636            public int           mPlaybackProgress;
637            public Conversation  mConversation;
638            public byte[]        mChatMsgGuid;
639            public int moduleId() {
640                    return 7;
641            }
642            
643            public Voicemail(final int oid, final SidRoot root) {
644                    super(oid, root, 12);
645            }
646    }