adium/adium
Clone
Summary
Browse
Changes
Graph
Fix libjson-glib manually.
adium-1.5.10.2
2016-03-09, Thijs Alkemade
a23057ce854d
Fix libjson-glib manually.
/*
* Adium is the legal property of its developers, whose names are listed in the copyright file included
* with this source distribution.
*
* This program is free software; you can redistribute it and/or modify it under the terms of the GNU
* General Public License as published by the Free Software Foundation; either version 2 of the License,
* or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program; if not,
* write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#import "adiumPurpleSignals.h"
#import <AIUtilities/AIObjectAdditions.h>
#import <AIUtilities/AIAttributedStringAdditions.h>
#import <Adium/AIChatControllerProtocol.h>
#import <Adium/AIChat.h>
#import <Adium/AIListContact.h>
#import <Adium/ESFileTransfer.h>
static
void
buddy_status_changed_cb
(
PurpleBuddy
*
buddy
,
PurpleStatus
*
oldstatus
,
PurpleStatus
*
status
,
PurpleBuddyEvent
event
);
static
void
buddy_idle_changed_cb
(
PurpleBuddy
*
buddy
,
gboolean
old_idle
,
gboolean
idle
,
PurpleBuddyEvent
event
);
static
void
buddy_event_cb
(
PurpleBuddy
*
buddy
,
PurpleBuddyEvent
event
)
{
NSAutoreleasePool
*
pool
=
[[
NSAutoreleasePool
alloc
]
init
];
if
(
buddy
)
{
SEL
updateSelector
=
nil
;
id
data
=
nil
;
BOOL
letAccountHandleUpdate
=
YES
;
CBPurpleAccount
*
account
=
accountLookup
(
purple_buddy_get_account
(
buddy
));
AIListContact
*
theContact
=
contactLookupFromBuddy
(
buddy
);
switch
(
event
)
{
case
PURPLE_BUDDY_SIGNON
:
{
updateSelector
=
@selector
(
updateSignon
:
withData
:
);
break
;
}
case
PURPLE_BUDDY_SIGNOFF
:
{
updateSelector
=
@selector
(
updateSignoff
:
withData
:
);
break
;
}
case
PURPLE_BUDDY_SIGNON_TIME
:
{
PurplePresence
*
presence
=
purple_buddy_get_presence
(
buddy
);
time_t
loginTime
=
purple_presence_get_login_time
(
presence
);
updateSelector
=
@selector
(
updateSignonTime
:
withData
:
);
data
=
(
loginTime
?
[
NSDate
dateWithTimeIntervalSince1970
:
loginTime
]
:
nil
);
break
;
}
case
PURPLE_BUDDY_EVIL
:
{
updateSelector
=
@selector
(
updateEvil
:
withData
:
);
//This is an update of the AIM Warning Level. We really, really don't care.
/*
if (buddy->evil) {
data = [NSNumber numberWithInt:buddy->evil];
}
*/
break
;
}
case
PURPLE_BUDDY_ICON
:
{
PurpleBuddyIcon
*
buddyIcon
=
purple_buddy_get_icon
(
buddy
);
updateSelector
=
@selector
(
updateIcon
:
withData
:
);
AILog
(
@"Buddy icon update for %s"
,
purple_buddy_get_name
(
buddy
));
if
(
buddyIcon
)
{
const
guchar
*
iconData
;
size_t
len
;
iconData
=
purple_buddy_icon_get_data
(
buddyIcon
,
&
len
);
if
(
iconData
&&
len
)
{
data
=
[
NSData
dataWithBytes
:
iconData
length
:
len
];
AILog
(
@"[buddy icon: %s got data]"
,
purple_buddy_get_name
(
buddy
));
}
}
break
;
}
case
PURPLE_BUDDY_NAME
:
{
updateSelector
=
@selector
(
renameContact
:
toUID
:
);
data
=
[
NSString
stringWithUTF8String
:
purple_buddy_get_name
(
buddy
)];
AILog
(
@"Renaming %@ to %@"
,
theContact
,
data
);
break
;
}
default
:
{
data
=
[
NSNumber
numberWithInteger
:
event
];
break
;
}
}
if
(
letAccountHandleUpdate
)
{
if
(
updateSelector
)
{
[
account
performSelector
:
updateSelector
withObject
:
theContact
withObject
:
data
];
}
else
{
[
account
updateContact
:
theContact
forEvent
:
data
];
}
}
/* If a status event didn't change from its previous value, we won't be notified of it.
* That's generally a good thing, but we clear some values when a contact signs off, including
* status, idle time, and signed-on time. Manually update these as appropriate when we're informed of
* a signon.
*/
if
((
event
==
PURPLE_BUDDY_SIGNON
)
||
(
event
==
PURPLE_BUDDY_SIGNOFF
))
{
PurplePresence
*
presence
=
purple_buddy_get_presence
(
buddy
);
PurpleStatus
*
status
=
purple_presence_get_active_status
(
presence
);
buddy_status_changed_cb
(
buddy
,
NULL
,
status
,
event
);
if
(
event
==
PURPLE_BUDDY_SIGNON
)
{
buddy_idle_changed_cb
(
buddy
,
FALSE
,
purple_presence_is_idle
(
presence
),
event
);
buddy_event_cb
(
buddy
,
PURPLE_BUDDY_SIGNON_TIME
);
}
}
}
[
pool
release
];
}
static
void
buddy_status_changed_cb
(
PurpleBuddy
*
buddy
,
PurpleStatus
*
oldstatus
,
PurpleStatus
*
status
,
PurpleBuddyEvent
event
)
{
NSAutoreleasePool
*
pool
=
[[
NSAutoreleasePool
alloc
]
init
];
CBPurpleAccount
*
account
=
accountLookup
(
purple_buddy_get_account
(
buddy
));
AIListContact
*
theContact
=
contactLookupFromBuddy
(
buddy
);
NSNumber
*
statusTypeNumber
;
NSString
*
statusName
;
NSAttributedString
*
statusMessage
;
BOOL
isAvailable
,
isMobile
;
isAvailable
=
((
purple_status_type_get_primitive
(
purple_status_get_type
(
status
))
==
PURPLE_STATUS_AVAILABLE
)
||
(
purple_status_type_get_primitive
(
purple_status_get_type
(
status
))
==
PURPLE_STATUS_OFFLINE
));
isMobile
=
purple_presence_is_status_primitive_active
(
purple_buddy_get_presence
(
buddy
),
PURPLE_STATUS_MOBILE
);
statusTypeNumber
=
[
NSNumber
numberWithInteger
:
(
isAvailable
?
AIAvailableStatusType
:
AIAwayStatusType
)];
statusName
=
[
account
statusNameForPurpleBuddy
:
buddy
];
statusMessage
=
[
account
statusMessageForPurpleBuddy
:
buddy
];
//Will also notify
[
account
updateStatusForContact
:
theContact
toStatusType
:
statusTypeNumber
statusName
:
statusName
statusMessage
:
statusMessage
isMobile
:
isMobile
];
[
pool
release
];
}
static
void
buddy_idle_changed_cb
(
PurpleBuddy
*
buddy
,
gboolean
old_idle
,
gboolean
idle
,
PurpleBuddyEvent
event
)
{
NSAutoreleasePool
*
pool
=
[[
NSAutoreleasePool
alloc
]
init
];
CBPurpleAccount
*
account
=
accountLookup
(
purple_buddy_get_account
(
buddy
));
AIListContact
*
theContact
=
contactLookupFromBuddy
(
buddy
);
PurplePresence
*
presence
=
purple_buddy_get_presence
(
buddy
);
if
(
idle
)
{
time_t
idleTime
=
purple_presence_get_idle_time
(
presence
);
[
account
updateWentIdle
:
theContact
withData
:(
idleTime
?
[
NSDate
dateWithTimeIntervalSince1970
:
idleTime
]
:
nil
)];
}
else
{
[
account
updateIdleReturn
:
theContact
withData
:
nil
];
}
[
pool
release
];
}
//This is called when a buddy is added or changes groups
static
void
buddy_added_cb
(
PurpleBuddy
*
buddy
)
{
NSAutoreleasePool
*
pool
=
[[
NSAutoreleasePool
alloc
]
init
];
PurpleAccount
*
purpleAccount
=
purple_buddy_get_account
(
buddy
);
if
(
purple_account_is_connected
(
purpleAccount
))
{
CBPurpleAccount
*
account
=
accountLookup
(
purpleAccount
);
PurpleGroup
*
g
=
purple_buddy_get_group
(
buddy
);
NSString
*
groupName
=
((
g
&&
purple_group_get_name
(
g
))
?
[
NSString
stringWithUTF8String
:
purple_group_get_name
(
g
)]
:
nil
);
AIListContact
*
listContact
=
contactLookupFromBuddy
(
buddy
);
/* We pass in purple_buddy_get_name(buddy) directly (without filtering or normalizing it) as it may indicate a
* formatted version of the UID. We have a signal for when a rename occurs, but passing here lets us get
* formatted names which are originally formatted in a way which differs from the results of normalization.
* For example, TekJew will normalize to tekjew in AIM; we want to use tekjew internally but display TekJew.
*/
[
account
addContact
:
listContact
toGroupName
:
groupName
contactName
:[
NSString
stringWithUTF8String
:
purple_buddy_get_name
(
buddy
)]];
/* We won't get an initial alias update for this buddy if one is already set, so check and update appropriately.
*
* This will give us an alias we've set serverside (the "private server alias") if possible.
* Failing that, we will get an alias specified remotely (either by the server or by the buddy).
*/
const
char
*
alias
=
purple_buddy_get_alias_only
(
buddy
);
if
(
alias
)
{
[
account
updateContact
:
listContact
toAlias
:[
NSString
stringWithUTF8String
:
alias
]];
}
// Force a status update for the user. Useful for things like XMPP which might display an error message for an offline contact.
buddy_status_changed_cb
(
buddy
,
NULL
,
purple_presence_get_active_status
(
purple_buddy_get_presence
(
buddy
)),
PURPLE_BUDDY_NONE
);
}
[
pool
release
];
}
static
void
buddy_removed_cb
(
PurpleBuddy
*
buddy
)
{
NSAutoreleasePool
*
pool
=
[[
NSAutoreleasePool
alloc
]
init
];
PurpleAccount
*
purpleAccount
=
purple_buddy_get_account
(
buddy
);
if
(
purple_account_is_connected
(
purpleAccount
))
{
CBPurpleAccount
*
account
=
accountLookup
(
purpleAccount
);
PurpleGroup
*
g
=
purple_buddy_get_group
(
buddy
);
NSString
*
groupName
=
((
g
&&
purple_group_get_name
(
g
))
?
[
NSString
stringWithUTF8String
:
purple_group_get_name
(
g
)]
:
nil
);
AIListContact
*
listContact
=
contactLookupFromBuddy
(
buddy
);
/* We pass in purple_buddy_get_name(buddy) directly (without filtering or normalizing it) as it may indicate a
* formatted version of the UID. We have a signal for when a rename occurs, but passing here lets us get
* formatted names which are originally formatted in a way which differs from the results of normalization.
* For example, TekJew will normalize to tekjew in AIM; we want to use tekjew internally but display TekJew.
*/
[
account
removeContact
:
listContact
fromGroupName
:
groupName
];
}
[
pool
release
];
}
static
void
connection_signed_on_cb
(
PurpleConnection
*
gc
)
{
NSAutoreleasePool
*
pool
=
[[
NSAutoreleasePool
alloc
]
init
];
GSList
*
buddies
=
purple_find_buddies
(
purple_connection_get_account
(
gc
),
/* buddy_name */
NULL
);
GSList
*
cur
;
for
(
cur
=
buddies
;
cur
;
cur
=
cur
->
next
)
{
buddy_added_cb
((
PurpleBuddy
*
)
cur
->
data
);
}
g_slist_free
(
buddies
);
[
pool
release
];
}
static
void
node_aliased_cb
(
PurpleBlistNode
*
node
,
char
*
old_alias
)
{
NSAutoreleasePool
*
pool
=
[[
NSAutoreleasePool
alloc
]
init
];
if
(
PURPLE_BLIST_NODE_IS_BUDDY
(
node
))
{
PurpleBuddy
*
buddy
=
(
PurpleBuddy
*
)
node
;
CBPurpleAccount
*
account
=
accountLookup
(
purple_buddy_get_account
(
buddy
));
const
char
*
alias
;
/* This will give us an alias we've set serverside (the "private server alias") if possible.
* Failing that, we will get an alias specified remotely (either by the server or by the buddy).
*/
alias
=
purple_buddy_get_alias_only
(
buddy
);
AILogWithSignature
(
@"%@ -> %s"
,
contactLookupFromBuddy
(
buddy
),
alias
);
[
account
updateContact
:
contactLookupFromBuddy
(
buddy
)
toAlias
:(
alias
?
[
NSString
stringWithUTF8String
:
alias
]
:
nil
)];
}
[
pool
release
];
}
static
NSDictionary
*
dictionaryFromHashTable
(
GHashTable
*
data
)
{
NSMutableDictionary
*
dict
=
[
NSMutableDictionary
dictionary
];
GList
*
l
=
g_hash_table_get_keys
(
data
);
GList
*
ll
;
for
(
ll
=
l
;
ll
;
ll
=
ll
->
next
)
{
void
*
key
=
ll
->
data
;
void
*
value
=
g_hash_table_lookup
(
data
,
key
);
if
(
!
key
||
!
value
)
continue
;
NSString
*
keyString
=
[
NSString
stringWithUTF8String
:
key
];
NSString
*
valueString
=
[
NSString
stringWithUTF8String
:
value
];
if
([
valueString
integerValue
])
{
[
dict
setValue
:
[
NSNumber
numberWithInteger
:
[
valueString
integerValue
]]
forKey
:
keyString
];
}
else
{
[
dict
setValue
:
valueString
forKey
:
keyString
];
}
}
return
dict
;
}
static
void
chat_join_failed_cb
(
PurpleConnection
*
gc
,
GHashTable
*
components
)
{
NSAutoreleasePool
*
pool
=
[[
NSAutoreleasePool
alloc
]
init
];
CBPurpleAccount
*
account
=
accountLookup
(
purple_connection_get_account
(
gc
));
NSDictionary
*
componentDict
=
dictionaryFromHashTable
(
components
);
for
(
AIChat
*
chat
in
adium
.
chatController
.
openChats
)
{
if
((
chat
.
account
==
account
)
&&
[
account
chatCreationDictionary
:
chat
.
chatCreationDictionary
isEqualToDictionary
:
componentDict
])
{
[
account
chatJoinDidFail
:
chat
];
break
;
}
}
[
pool
release
];
}
static
void
typing_changed
(
PurpleAccount
*
account
,
const
char
*
name
,
AITypingState
typingState
)
{
NSAutoreleasePool
*
pool
=
[[
NSAutoreleasePool
alloc
]
init
];
CBPurpleAccount
*
cbaccount
=
accountLookup
(
account
);
AIListContact
*
contact
=
contactLookupFromBuddy
(
purple_find_buddy
(
account
,
name
));
// Don't do anything for those who aren't on our contact list.
if
(
contact
.
isStranger
)
{
[
pool
release
];
return
;
}
AIChat
*
chat
=
[
adium
.
chatController
existingChatWithContact
:
contact
];
if
(
typingState
!=
AINotTyping
&&
!
chat
)
{
chat
=
[
adium
.
chatController
chatWithContact
:
contact
];
AILogWithSignature
(
@"Made a chat for %s: %i"
,
name
,
typingState
);
}
if
(
chat
)
[
cbaccount
typingUpdateForIMChat
:
chat
typing
:
[
NSNumber
numberWithInteger
:
typingState
]];
[
pool
release
];
}
static
void
conversation_created_cb
(
PurpleConversation
*
conv
,
void
*
data
)
{
NSAutoreleasePool
*
pool
=
[[
NSAutoreleasePool
alloc
]
init
];
if
(
purple_conversation_get_type
(
conv
)
==
PURPLE_CONV_TYPE_IM
)
{
AIChat
*
chat
=
imChatLookupFromConv
(
conv
);
//When a conversation is created, we must clear the typing flag, as libpurple won't notify us properly
[
accountLookup
(
purple_conversation_get_account
(
conv
))
typingUpdateForIMChat
:
chat
typing
:
[
NSNumber
numberWithInteger
:
AINotTyping
]];
}
[
pool
release
];
}
/* The buddy-typing, buddy-typed, and buddy-typing-stopped signals will only be sent
* when there isn't an open conversation, so we're not duplicating typing information here.
*
* adiumPurpleConversation has the typing code for open conversations.
*/
static
void
buddy_typing_cb
(
PurpleAccount
*
account
,
const
char
*
name
,
void
*
data
)
{
typing_changed
(
account
,
name
,
AITyping
);
}
static
void
buddy_typed_cb
(
PurpleAccount
*
account
,
const
char
*
name
,
void
*
data
)
{
typing_changed
(
account
,
name
,
AIEnteredText
);
}
static
void
buddy_typing_stopped_cb
(
PurpleAccount
*
account
,
const
char
*
name
,
void
*
data
)
{
typing_changed
(
account
,
name
,
AINotTyping
);
}
static
void
chat_joined_cb
(
PurpleConversation
*
conv
,
void
*
data
)
{
NSAutoreleasePool
*
pool
=
[[
NSAutoreleasePool
alloc
]
init
];
//Pass chats along to the account
if
(
purple_conversation_get_type
(
conv
)
==
PURPLE_CONV_TYPE_CHAT
)
{
AIChat
*
chat
=
groupChatLookupFromConv
(
conv
);
[
accountLookup
(
purple_conversation_get_account
(
conv
))
addChat
:
chat
];
}
[
pool
release
];
}
static
void
file_recv_request_cb
(
PurpleXfer
*
xfer
)
{
NSAutoreleasePool
*
pool
=
[[
NSAutoreleasePool
alloc
]
init
];
ESFileTransfer
*
fileTransfer
;
//Purple doesn't return normalized user id, so it should be normalized manually
char
*
who
=
g_strdup
(
purple_normalize
(
xfer
->
account
,
xfer
->
who
));
//Ask the account for an ESFileTransfer* object
fileTransfer
=
[
accountLookup
(
xfer
->
account
)
newFileTransferObjectWith
:
[
NSString
stringWithUTF8String
:
who
]
size
:
purple_xfer_get_size
(
xfer
)
remoteFilename
:[
NSString
stringWithUTF8String
:
purple_xfer_get_filename
(
xfer
)]];
g_free
(
who
);
//Configure the new object for the transfer
[
fileTransfer
setAccountData
:
[
NSValue
valueWithPointer
:
xfer
]];
xfer
->
ui_data
=
[
fileTransfer
retain
];
/* Set a fake local filename to convince libpurple that we are handling the request. We are, but
* the code expects a synchronous response, and we rock out asynchronously.
*/
purple_xfer_set_local_filename
(
xfer
,
""
);
//Tell the account that we are ready to request the reception
[
accountLookup
(
purple_xfer_get_account
(
xfer
))
requestReceiveOfFileTransfer
:
fileTransfer
];
[
pool
release
];
}
void
configureAdiumPurpleSignals
(
void
)
{
NSAutoreleasePool
*
pool
=
[[
NSAutoreleasePool
alloc
]
init
];
void
*
blist_handle
=
purple_blist_get_handle
();
void
*
handle
=
adium_purple_get_handle
();
//Idle
purple_signal_connect
(
blist_handle
,
"buddy-idle-changed"
,
handle
,
PURPLE_CALLBACK
(
buddy_idle_changed_cb
),
GINT_TO_POINTER
(
0
));
//Status
purple_signal_connect
(
blist_handle
,
"buddy-status-changed"
,
handle
,
PURPLE_CALLBACK
(
buddy_status_changed_cb
),
GINT_TO_POINTER
(
0
));
//Icon
purple_signal_connect
(
blist_handle
,
"buddy-icon-changed"
,
handle
,
PURPLE_CALLBACK
(
buddy_event_cb
),
GINT_TO_POINTER
(
PURPLE_BUDDY_ICON
));
//Signon / Signoff
purple_signal_connect
(
blist_handle
,
"buddy-signed-on"
,
handle
,
PURPLE_CALLBACK
(
buddy_event_cb
),
GINT_TO_POINTER
(
PURPLE_BUDDY_SIGNON
));
purple_signal_connect
(
blist_handle
,
"buddy-signed-off"
,
handle
,
PURPLE_CALLBACK
(
buddy_event_cb
),
GINT_TO_POINTER
(
PURPLE_BUDDY_SIGNOFF
));
purple_signal_connect
(
blist_handle
,
"buddy-got-login-time"
,
handle
,
PURPLE_CALLBACK
(
buddy_event_cb
),
GINT_TO_POINTER
(
PURPLE_BUDDY_SIGNON_TIME
));
purple_signal_connect
(
blist_handle
,
"buddy-got-login-time"
,
handle
,
PURPLE_CALLBACK
(
buddy_event_cb
),
GINT_TO_POINTER
(
PURPLE_BUDDY_SIGNON_TIME
));
purple_signal_connect
(
blist_handle
,
"buddy-added"
,
handle
,
PURPLE_CALLBACK
(
buddy_added_cb
),
NULL
);
purple_signal_connect
(
blist_handle
,
"buddy-removed"
,
handle
,
PURPLE_CALLBACK
(
buddy_removed_cb
),
NULL
);
purple_signal_connect
(
blist_handle
,
"blist-node-aliased"
,
handle
,
PURPLE_CALLBACK
(
node_aliased_cb
),
NULL
);
purple_signal_connect
(
purple_connections_get_handle
(),
"signed-on"
,
handle
,
PURPLE_CALLBACK
(
connection_signed_on_cb
),
NULL
);
purple_signal_connect
(
purple_conversations_get_handle
(),
"conversation-created"
,
handle
,
PURPLE_CALLBACK
(
conversation_created_cb
),
NULL
);
purple_signal_connect
(
purple_conversations_get_handle
(),
"chat-joined"
,
handle
,
PURPLE_CALLBACK
(
chat_joined_cb
),
NULL
);
purple_signal_connect
(
purple_conversations_get_handle
(),
"chat-join-failed"
,
handle
,
PURPLE_CALLBACK
(
chat_join_failed_cb
),
NULL
);
purple_signal_connect
(
purple_conversations_get_handle
(),
"buddy-typing"
,
handle
,
PURPLE_CALLBACK
(
buddy_typing_cb
),
NULL
);
purple_signal_connect
(
purple_conversations_get_handle
(),
"buddy-typed"
,
handle
,
PURPLE_CALLBACK
(
buddy_typed_cb
),
NULL
);
purple_signal_connect
(
purple_conversations_get_handle
(),
"buddy-typing-stopped"
,
handle
,
PURPLE_CALLBACK
(
buddy_typing_stopped_cb
),
NULL
);
purple_signal_connect
(
purple_xfers_get_handle
(),
"file-recv-request"
,
handle
,
PURPLE_CALLBACK
(
file_recv_request_cb
),
NULL
);
[
pool
release
];
}