--- a/libpurple/protocols/mxit/actions.c Sat Aug 13 21:57:35 2011 +0000
+++ b/libpurple/protocols/mxit/actions.c Sat Aug 13 22:11:50 2011 +0000
@@ -84,13 +84,6 @@
g_string_append( attributes, attrib );
- /* force hidden if disabled */
- if ( profile->hidden == FALSE ) {
- g_snprintf( attrib, sizeof( attrib ), "\01%s\01%i\01%s", CP_PROFILE_HIDENUMBER, CP_PROFILE_TYPE_BOOL, "1" );
- g_string_append( attributes, attrib );
g_strlcpy( profile->birthday, bday, sizeof( profile->birthday ) );
g_snprintf( attrib, sizeof( attrib ), "\01%s\01%i\01%s", CP_PROFILE_BIRTHDATE, CP_PROFILE_TYPE_UTF8, profile->birthday );
--- a/libpurple/protocols/mxit/cipher.c Sat Aug 13 21:57:35 2011 +0000
+++ b/libpurple/protocols/mxit/cipher.c Sat Aug 13 22:11:50 2011 +0000
@@ -34,6 +34,7 @@
/* password encryption */
#define INITIAL_KEY "6170383452343567"
#define SECRET_HEADER "<mxit/>"
+#define ENCRYPT_HEADER "<mxitencrypted ver=\"5.2\"/>" /*------------------------------------------------------------------------
@@ -106,3 +107,67 @@
+/*------------------------------------------------------------------------ + * Decrypt a transport-layer encryptede message. + * @param session The MXit session object + * @param message The encrypted message data. + * @return The decrypted message. Must be g_free'd when no longer needed. +char* mxit_decrypt_message( struct MXitSession* session, char* message ) + int pwdlen = strlen( session->acc->password ); + GString* decoded = NULL; + /* remove optional header: <mxitencrypted ver="5.2"/> */ + if ( strncmp( message, ENCRYPT_HEADER, strlen( ENCRYPT_HEADER ) ) == 0 ) + message += strlen( ENCRYPT_HEADER ); + /* base64 decode the message */ + raw_message = purple_base64_decode( message, &raw_len ); + /* build the key - Client key, appended with last 8 characters of the PIN. (no padding) */ + memset( key, 0x00, sizeof( key ) ); + memcpy( key, session->clientkey, strlen( session->clientkey ) ); + strcat( key, session->acc->password ); + strncat( key, session->acc->password + ( pwdlen - 8 ), 8 ); + ExpandKey( (unsigned char*) key, (unsigned char*) exkey ); + /* decode each block */ + decoded = g_string_sized_new( raw_len ); + for ( i = 0; i < raw_len; i += 16 ) { + Decrypt( (unsigned char*) raw_message + i, (unsigned char*) exkey, (unsigned char*) block ); + g_string_append_len( decoded, block, 16 ); + purple_debug_info( MXIT_PLUGIN_ID, "decrypted: '%s'\n", decoded->str ); + /* check that the decrypted message starts with header: <mxit/> */ + if ( strncmp( decoded->str, SECRET_HEADER, strlen( SECRET_HEADER ) != 0 ) ) { + g_string_free( decoded, TRUE ); + return NULL; /* message could not be decoded */ + /* remove ISO10126 padding */ + /* last byte indicates the number of padding bytes */ + unsigned int padding = decoded->str[decoded->len - 1]; + g_string_truncate( decoded, decoded->len - padding ); + /* remove encryption header */ + g_string_erase( decoded, 0, strlen( SECRET_HEADER ) ); + return g_string_free( decoded, FALSE ); --- a/libpurple/protocols/mxit/cipher.h Sat Aug 13 21:57:35 2011 +0000
+++ b/libpurple/protocols/mxit/cipher.h Sat Aug 13 22:11:50 2011 +0000
@@ -32,5 +32,7 @@
char* mxit_encrypt_password( struct MXitSession* session );
+char* mxit_decrypt_message( struct MXitSession* session, char* message ); #endif /* _MXIT_CIPHER_H_ */
--- a/libpurple/protocols/mxit/formcmds.c Sat Aug 13 21:57:35 2011 +0000
+++ b/libpurple/protocols/mxit/formcmds.c Sat Aug 13 22:11:50 2011 +0000
@@ -253,8 +253,8 @@
/*------------------------------------------------------------------------
* Process a Reply MXit command.
- * [::op=cmd|type=reply|replymsg=back|selmsg=b) Back|id=12345:]
- * [::op=cmd|nm=rep|type=reply|replymsg=back|selmsg=b) Back|id=12345:]
+ * [::op=cmd|type=reply|replymsg=back|selmsg=b) Back|displaymsg=Processing|id=12345:] + * [::op=cmd|nm=rep|type=reply|replymsg=back|selmsg=b) Back|displaymsg=Processing|id=12345:] * @param mx The received message data object
* @param hash The MXit command <key,value> map
@@ -265,22 +265,26 @@
- selmsg = g_hash_table_lookup(hash, "selmsg"); /* find the selection message */
- replymsg = g_hash_table_lookup(hash, "replymsg"); /* find the reply message */
+ selmsg = g_hash_table_lookup(hash, "selmsg"); /* selection message */ + replymsg = g_hash_table_lookup(hash, "replymsg"); /* reply message */ nm = g_hash_table_lookup(hash, "nm"); /* name parameter */
- if ((selmsg) && (replymsg) && (nm)) {
+ if ((selmsg == NULL) || (replymsg == NULL)) + return; /* these parameters are required */ + if (nm) { /* indicates response must be a structured response */ gchar* seltext = g_markup_escape_text(purple_url_decode(selmsg), -1);
- gchar* replycmd = g_strdup_printf("::type=reply|nm=%s|res=%s|err=0:", nm, replymsg);
+ gchar* replycmd = g_strdup_printf("type=reply|nm=%s|res=%s|err=0", nm, replymsg); - mxit_add_html_link( mx, replycmd, seltext );
+ mxit_add_html_link( mx, replycmd, TRUE, seltext ); - else if ((selmsg) && (replymsg)) {
gchar* seltext = g_markup_escape_text(purple_url_decode(selmsg), -1);
- mxit_add_html_link( mx, purple_url_decode(replymsg), seltext );
+ mxit_add_html_link( mx, purple_url_decode(replymsg), FALSE, seltext ); @@ -317,6 +321,7 @@
/*------------------------------------------------------------------------
* Process an inline image MXit command.
+ * [::op=img|dat=ASDF23408asdflkj2309flkjsadf%3d%3d|algn=1|w=120|h=12|t=100|replymsg=text:] * @param mx The received message data object
* @param hash The MXit command <key,value> map
@@ -372,7 +377,7 @@
reply = g_hash_table_lookup(hash, "replymsg");
g_string_append_printf(msg, "\n");
- mxit_add_html_link(mx, reply, _( "click here" ));
+ mxit_add_html_link(mx, reply, FALSE, _( "click here" )); --- a/libpurple/protocols/mxit/markup.c Sat Aug 13 21:57:35 2011 +0000
+++ b/libpurple/protocols/mxit/markup.c Sat Aug 13 22:11:50 2011 +0000
@@ -124,10 +124,11 @@
* Adds a link to a message
* @param mx The Markup message object
- * @param linkname This is the what will be returned when the link gets clicked
- * @param displayname This is the name for the link which will be displayed in the UI
+ * @param replydata This is the what will be returned when the link gets clicked + * @param isStructured Indicates that the reply is a structured reply + * @param displaytext This is the text for the link which will be displayed in the UI -void mxit_add_html_link( struct RXMsgData* mx, const char* linkname, const char* displayname )
+void mxit_add_html_link( struct RXMsgData* mx, const char* replydata, gboolean isStructured, const char* displaytext ) @@ -135,15 +136,24 @@
- len = g_snprintf( retstr, sizeof( retstr ), "%s|%s|%s|%s|%s", MXIT_LINK_KEY, purple_account_get_username( mx->session->acc ),
- purple_account_get_protocol_id( mx->session->acc ), mx->from, linkname );
+ * The link content is encoded as follows: + * MXIT_LINK_KEY | ACCOUNT_USER | ACCOUNT_PROTO | REPLY_TO | REPLY_FORMAT | REPLY_DATA + len = g_snprintf( retstr, sizeof( retstr ), "%s|%s|%s|%s|%i|%s", + purple_account_get_username( mx->session->acc ), + purple_account_get_protocol_id( mx->session->acc ), retstr64 = purple_base64_encode( (const unsigned char*) retstr, len );
g_snprintf( link, sizeof( link ), "%s%s", MXIT_LINK_PREFIX, retstr64 );
- g_string_append_printf( mx->msg, "<a href=\"%s\">%s</a>", link, displayname );
+ g_string_append_printf( mx->msg, "<a href=\"%s\">%s</a>", link, displaytext ); - g_string_append_printf( mx->msg, "<b>%s</b>", linkname );
+ g_string_append_printf( mx->msg, "<b>%s</b>", replydata ); @@ -735,6 +745,7 @@
gboolean tag_bold = FALSE;
gboolean tag_under = FALSE;
gboolean tag_italic = FALSE;
purple_debug_info( MXIT_PLUGIN_ID, "Markup RX (original): '%s'\n", message );
@@ -823,7 +834,7 @@
- mxit_add_html_link( mx, &message[i + 1], &message[i + 1] );
+ mxit_add_html_link( mx, &message[i + 1], FALSE, &message[i + 1] ); i += ( ch - &message[i + 1] ) + 1;
@@ -862,59 +873,54 @@
- if ( !( msgflags & CP_MSG_EMOTICON ) ) {
- g_string_append_c( mx->msg, message[i] );
- else if ( i + 1 >= len ) {
g_string_append_c( mx->msg, '.' );
- switch ( message[i+1] ) {
- /* increment text size */
- g_string_append( mx->msg, "<font size=\"+1\">" );
- /* decrement text size */
- g_string_append( mx->msg, "<font size=\"-1\">" );
- /* message too short */
- g_string_append_c( mx->msg, '.' );
+ if ( ( msgflags & CP_MSG_EMOTICON ) && ( message[i+1] == '{' ) ) { + /* message too short */ + g_string_append_c( mx->msg, '.' ); + parse_emoticon_str( &message[i+2], tmpstr1 ); + if ( tmpstr1[0] != '\0' ) { + if ( g_hash_table_lookup( mx->session->iimages, tmpstr1 ) ) { + /* emoticon found in the cache, so we do not have to request it from the WAPsite */ + /* request emoticon from the WAPsite */ + emoticon_request( mx, tmpstr1 ); - parse_emoticon_str( &message[i+2], tmpstr1 );
- if ( tmpstr1[0] != '\0' ) {
+ g_string_append_printf( mx->msg, MXIT_II_TAG"%s>", tmpstr1 ); + i += strlen( tmpstr1 ) + 2; + g_string_append_c( mx->msg, '.' ); + else if ( ( msgflags & CP_MSG_MARKUP ) && ( message[i+1] == '+' ) ) { + /* increment text size */ + g_string_append_printf( mx->msg, "<font size=\"%+i\">", font_size ); + else if ( ( msgflags & CP_MSG_MARKUP ) && ( message[i+1] == '-' ) ) { + /* decrement text size */ + g_string_append_printf( mx->msg, "<font size=\"%+i\">", font_size ); + g_string_append_c( mx->msg, '.' ); - if ( g_hash_table_lookup( mx->session->iimages, tmpstr1 ) ) {
- /* emoticon found in the cache, so we do not have to request it from the WAPsite */
- /* request emoticon from the WAPsite */
- emoticon_request( mx, tmpstr1 );
- g_string_append_printf( mx->msg, MXIT_II_TAG"%s>", tmpstr1 );
- i += strlen( tmpstr1 ) + 2;
- g_string_append_c( mx->msg, '.' );
- g_string_append_c( mx->msg, '.' );
--- a/libpurple/protocols/mxit/markup.h Sat Aug 13 21:57:35 2011 +0000
+++ b/libpurple/protocols/mxit/markup.h Sat Aug 13 22:11:50 2011 +0000
@@ -31,7 +31,7 @@
void mxit_parse_markup( struct RXMsgData* mx, char* message, int len, short msgtype, int msgflags );
char* mxit_convert_markup_tx( const char* message, int* msgtype );
-void mxit_add_html_link( struct RXMsgData* mx, const char* linkname, const char* displayname );
+void mxit_add_html_link( struct RXMsgData* mx, const char* replydata, gboolean isStructured, const char* displaytext ); void mxit_show_message( struct RXMsgData* mx );
void mxit_free_emoticon_cache( struct MXitSession* session );
--- a/libpurple/protocols/mxit/multimx.c Sat Aug 13 21:57:35 2011 +0000
+++ b/libpurple/protocols/mxit/multimx.c Sat Aug 13 22:11:50 2011 +0000
@@ -277,7 +277,11 @@
struct multimx* multimx = NULL;
- purple_debug_info(MXIT_PLUGIN_ID, "Groupchat invite to '%s' by '%s'\n", contact->alias, creator);
+ purple_debug_info(MXIT_PLUGIN_ID, "Groupchat invite to '%s' (roomid='%s') by '%s'\n", contact->alias, contact->username, creator); + /* Check if the room already exists (ie, already joined or invite pending) */ + if (find_room_by_username(session, contact->username) != NULL) multimx = room_create(session, contact->username, contact->alias, STATE_INVITED);
@@ -307,7 +311,7 @@
multimx = find_room_by_username(session, contact->username);
multimx = room_create(session, contact->username, contact->alias, TRUE);
else if (multimx->state == STATE_INVITED) {
/* After successfully accepting an invitation */
multimx->state = STATE_JOINED;
--- a/libpurple/protocols/mxit/mxit.c Sat Aug 13 21:57:35 2011 +0000
+++ b/libpurple/protocols/mxit/mxit.c Sat Aug 13 22:11:50 2011 +0000
@@ -75,10 +75,10 @@
link = (gchar*) purple_base64_decode( link64 + strlen( MXIT_LINK_PREFIX ), &len );
purple_debug_info( MXIT_PLUGIN_ID, "Clicked Link: '%s'\n", link );
- parts = g_strsplit( link, "|", 5 );
+ parts = g_strsplit( link, "|", 6 ); /* check if this is a valid mxit link */
- if ( ( !parts ) || ( !parts[0] ) || ( !parts[1] ) || ( !parts[2] ) || ( !parts[3] ) || ( !parts[4] ) ) {
+ if ( ( !parts ) || ( !parts[0] ) || ( !parts[1] ) || ( !parts[2] ) || ( !parts[3] ) || ( !parts[4] ) || ( !parts[5] ) ) { @@ -96,10 +96,10 @@
/* determine if it's a command-response to send */
- is_command = g_str_has_prefix( parts[4], "::type=reply|" );
+ is_command = ( atoi( parts[4] ) == 1 ); /* send click message back to MXit */
- mxit_send_message( con->proto_data, parts[3], parts[4], FALSE, is_command );
+ mxit_send_message( con->proto_data, parts[3], parts[5], FALSE, is_command ); @@ -309,19 +309,18 @@
char* mxit_status_text( PurpleBuddy* buddy )
struct contact* contact = purple_buddy_get_protocol_data(buddy);
- if ( contact->statusMsg ) {
- return g_strdup( contact-> statusMsg );
- return g_strdup( mxit_convert_mood_to_name( contact->mood ) );
+ if ( contact->statusMsg ) /* status message */ + text = g_strdup( contact-> statusMsg ); + else if ( contact->mood != MXIT_MOOD_NONE ) /* mood */ + text = g_strdup( mxit_convert_mood_to_name( contact->mood ) ); @@ -358,10 +357,6 @@
if ( ( contact->subtype == MXIT_SUBTYPE_REJECTED ) && ( contact->msg != NULL ) )
purple_notify_user_info_add_pair( info, _( "Rejection Message" ), contact->msg );
- if ( contact->flags & MXIT_CFLAG_HIDDEN )
- purple_notify_user_info_add_pair( info, _( "Hidden Number" ), _( "Yes" ) );
--- a/libpurple/protocols/mxit/profile.c Sat Aug 13 21:57:35 2011 +0000
+++ b/libpurple/protocols/mxit/profile.c Sat Aug 13 22:11:50 2011 +0000
@@ -215,9 +215,6 @@
purple_notify_user_info_add_pair( info, _( "Subscription" ), mxit_convert_subtype_to_name( contact->subtype ) );
- purple_notify_user_info_add_pair( info, _( "Hidden Number" ), ( contact->flags & MXIT_CFLAG_HIDDEN ) ? _( "Yes" ) : _( "No" ) );
--- a/libpurple/protocols/mxit/profile.h Sat Aug 13 21:57:35 2011 +0000
+++ b/libpurple/protocols/mxit/profile.h Sat Aug 13 22:11:50 2011 +0000
@@ -50,7 +50,6 @@
int flags; /* user's profile flags */
gint64 lastonline; /* user's last-online timestamp */
- gboolean hidden; /* set if the user's mxitid should remain hidden */
--- a/libpurple/protocols/mxit/protocol.c Sat Aug 13 21:57:35 2011 +0000
+++ b/libpurple/protocols/mxit/protocol.c Sat Aug 13 22:11:50 2011 +0000
@@ -1448,7 +1448,7 @@
- const char* profilelist[] = { CP_PROFILE_BIRTHDATE, CP_PROFILE_GENDER, CP_PROFILE_HIDENUMBER, CP_PROFILE_FULLNAME,
+ const char* profilelist[] = { CP_PROFILE_BIRTHDATE, CP_PROFILE_GENDER, CP_PROFILE_FULLNAME, CP_PROFILE_TITLE, CP_PROFILE_FIRSTNAME, CP_PROFILE_LASTNAME, CP_PROFILE_EMAIL,
CP_PROFILE_MOBILENR, CP_PROFILE_WHEREAMI, CP_PROFILE_ABOUTME, CP_PROFILE_FLAGS };
@@ -1516,6 +1516,7 @@
struct RXMsgData* mx = NULL;
@@ -1529,10 +1530,11 @@
msglen = strlen( message );
/* strip off dummy domain */
- mxit_strip_domain( records[0]->fields[0]->data );
+ sender = records[0]->fields[0]->data; + mxit_strip_domain( sender ); - purple_debug_info( MXIT_PLUGIN_ID, "Message received from '%s'\n", records[0]->fields[0]->data );
+ purple_debug_info( MXIT_PLUGIN_ID, "Message received from '%s'\n", sender ); /* decode message flags (if any) */
@@ -1540,33 +1542,42 @@
msgflags = atoi( records[0]->fields[4]->data );
msgtype = atoi( records[0]->fields[2]->data );
- if ( msgflags & CP_MSG_ENCRYPTED ) {
- /* this is an encrypted message. we do not currently support those so ignore it */
+ if ( msgflags & CP_MSG_PWD_ENCRYPTED ) { + /* this is a password encrypted message. we do not currently support those so ignore it */ - buddy = purple_find_buddy( session->acc, records[0]->fields[0]->data );
+ buddy = purple_find_buddy( session->acc, sender ); name = purple_buddy_get_alias( buddy );
- name = records[0]->fields[0]->data;
g_snprintf( msg, sizeof( msg ), _( "%s sent you an encrypted message, but it is not supported on this client." ), name );
mxit_popup( PURPLE_NOTIFY_MSG_WARNING, _( "Message Error" ), msg );
+ else if ( msgflags & CP_MSG_TL_ENCRYPTED ) { + /* this is a transport-layer encrypted message. */ + message = mxit_decrypt_message( session, message ); + /* could not be decrypted */ + serv_got_im( session->con, sender, _( "An encrypted message was received which could not be decrypted." ), PURPLE_MESSAGE_ERROR, time( NULL ) ); if ( msgflags & CP_MSG_NOTIFY_DELIVERY ) {
/* delivery notification is requested */
if ( records[0]->fcount >= 4 )
- mxit_send_msgevent( session, records[0]->fields[0]->data, records[0]->fields[3]->data, CP_MSGEVENT_DELIVERED );
+ mxit_send_msgevent( session, sender, records[0]->fields[3]->data, CP_MSGEVENT_DELIVERED ); /* create and initialise new markup struct */
mx = g_new0( struct RXMsgData, 1 );
mx->msg = g_string_sized_new( msglen );
- mx->from = g_strdup( records[0]->fields[0]->data );
+ mx->from = g_strdup( sender ); mx->timestamp = atoi( records[0]->fields[1]->data );
@@ -1597,6 +1608,10 @@
* so the image received callback function will eventually display
+ if ( msgflags & CP_MSG_TL_ENCRYPTED ) @@ -1810,10 +1825,6 @@
profile->male = ( fvalue[0] == '1' );
- else if ( strcmp( CP_PROFILE_HIDENUMBER, fname ) == 0 ) {
- profile->hidden = ( fvalue[0] == '1' );
else if ( strcmp( CP_PROFILE_FULLNAME, fname ) == 0 ) {
g_strlcpy( profile->nickname, fvalue, sizeof( profile->nickname ) );
--- a/libpurple/protocols/mxit/protocol.h Sat Aug 13 21:57:35 2011 +0000
+++ b/libpurple/protocols/mxit/protocol.h Sat Aug 13 22:11:50 2011 +0000
@@ -155,7 +155,10 @@
#define CP_MSG_NOTIFY_DELIVERY 0x0002 /* request delivery notification */
#define CP_MSG_NOTIFY_READ 0x0004 /* request read notification */
-#define CP_MSG_ENCRYPTED 0x0010 /* message is encrypted */
+#define CP_MSG_PWD_ENCRYPTED 0x0010 /* message is password encrypted */ +#define CP_MSG_TL_ENCRYPTED 0x0020 /* message is transport encrypted */ +#define CP_MSG_RPLY_PWD_ENCRYPT 0x0040 /* reply should be password encrypted */ +#define CP_MSG_RPLY_TL_ENCRYPT 0x0080 /* reply should be transport encrypted */ #define CP_MSG_MARKUP 0x0200 /* message may contain markup */
#define CP_MSG_EMOTICON 0x0400 /* message may contain custom emoticons */
@@ -179,7 +182,7 @@
/* extended profile attribute fields */
#define CP_PROFILE_BIRTHDATE "birthdate" /* Birthdate (String - ISO 8601 format) */
#define CP_PROFILE_GENDER "gender" /* Gender (Boolean - 0=female, 1=male) */
-#define CP_PROFILE_HIDENUMBER "hidenumber" /* Hide Number (Boolean - 0=false, 1=true) */
+// #define CP_PROFILE_HIDENUMBER "hidenumber" /* Hide Number (Boolean - 0=false, 1=true) (DEPRECATED) */ #define CP_PROFILE_FULLNAME "fullname" /* Fullname (UTF8 String) */
#define CP_PROFILE_STATUS "statusmsg" /* Status Message (UTF8 String) */
#define CP_PROFILE_PREVSTATUS "prevstatusmsgs" /* Previous Status Messages (UTF8 String) */
--- a/libpurple/protocols/mxit/roster.h Sat Aug 13 21:57:35 2011 +0000
+++ b/libpurple/protocols/mxit/roster.h Sat Aug 13 22:11:50 2011 +0000
@@ -74,7 +74,7 @@
-#define MXIT_CFLAG_HIDDEN 0x02
+//#define MXIT_CFLAG_HIDDEN 0x02 /* (DEPRECATED) */ #define MXIT_CFLAG_GATEWAY 0x04
#define MXIT_CFLAG_FOCUS_SEND_BLANK 0x20000
@@ -96,7 +96,7 @@
/* client protocol constants */
#define MXIT_CP_MAX_JID_LEN 64
#define MXIT_CP_MAX_GROUP_LEN 32
-#define MXIT_CP_MAX_ALIAS_LEN 48
+#define MXIT_CP_MAX_ALIAS_LEN 100 #define MXIT_DEFAULT_GROUP "MXit"
@@ -106,8 +106,8 @@
char username[MXIT_CP_MAX_JID_LEN+1]; /* unique contact name (with domain) */
- char alias[MXIT_CP_MAX_GROUP_LEN+1]; /* contact alias (what will be seen) */
- char groupname[MXIT_CP_MAX_ALIAS_LEN+1]; /* contact group name */
+ char alias[MXIT_CP_MAX_ALIAS_LEN+1]; /* contact alias (what will be seen) */ + char groupname[MXIT_CP_MAX_GROUP_LEN+1]; /* contact group name */ short type; /* contact type */
short mood; /* contact current mood */
--- a/libpurple/protocols/mxit/voicevideo.c Sat Aug 13 21:57:35 2011 +0000
+++ b/libpurple/protocols/mxit/voicevideo.c Sat Aug 13 22:11:50 2011 +0000
@@ -95,7 +95,7 @@
/* and only when they're online */
if (contact->presence == MXIT_PRESENCE_OFFLINE)
- return MXIT_PRESENCE_OFFLINE;
+ return PURPLE_MEDIA_CAPS_NONE; /* they support voice-only */
if (contact->capabilities & MXIT_PFLAG_VOICE)