Пример #1
0
static void _elim_status_changed ( PurpleAccount *account ,
                                   PurpleStatus  *status  )
{
    xmlnode              *alist = xnode_new( "alist" );
    char                 *ID    = new_elim_id();
    fprintf( stderr, "(_elim_status_changed)\n" );

    PurpleStatusType     *type  = purple_status_get_type( status );
    PurpleStatusPrimitive statp = purple_status_type_get_primitive( type ); 

    AL_PTR ( alist, "account-uid" , account );
    AL_STR ( alist, "account-name", purple_account_get_username   ( account ) );
    AL_STR ( alist, "im-protocol" , purple_account_get_protocol_id( account ) );
    AL_STR ( alist, "status-name" , purple_status_get_name        ( status  ) );
    AL_ENUM( alist, "status-type" , statp, ":status-primitive" );
    AL_BOOL( alist, "connected"   , purple_account_is_connected   ( account ) );

    xmlnode *mcall = func_call( "elim-account-status-changed", ID, alist );

    g_free( ID );
    add_outbound_sexp( mcall );
}
Пример #2
0
xmlnode * _h_elim_add_buddy ( const char *name ,
                              const char *id   ,
                              SEXP_VALUE *args ,
                              gpointer data    )
{
    ASSERT_ALISTP( args, id, name );

    elim_ping();
    
    int         loopc = 0;
    const char *aname = ALIST_VAL_STR( args, "account-name" );
    const char *proto = ALIST_VAL_STR( args, "im-protocol"  );
    gpointer    auid  = ALIST_VAL_PTR( args, "account-uid"  );

    PurpleAccount *acct = 
      auid ? find_acct_by_uid( auid ) : purple_accounts_find( aname, proto );

    if( !acct )
    {
        sexp_val_free( args );
        return response_error( ENXIO, id, name, "unknown account" );
    }

    const char *b_arg = ALIST_VAL_STRING( args, "bnode-name" );
    const char *bname = purple_normalize( acct, b_arg        );
    const char *gname = ALIST_VAL_STRING( args, "group"      );
    if( !gname || !*gname ) gname = "Buddies";

    PurpleGroup *group = purple_group_new( gname );
    PurpleBuddy *buddy = purple_buddy_new( acct, bname, b_arg );
    PurpleBuddy *clone = NULL;
    //fprintf( stderr, "add-buddy( b: %p, g: %p )\n", buddy, group );
    // remove other references to this buddy
    purple_blist_add_buddy  ( buddy, NULL, group, NULL );
    purple_account_add_buddy( acct , buddy );
    while( ( clone = (PurpleBuddy*)find_blist_node_clone( buddy ) ) )
    {
        if( loopc++ > 99   ) 
        {
            fprintf( stderr, "ARGH! clone reaping looped: %d\n", loopc );
            break;
        }
        if( clone == buddy ) 
        { 
            fprintf( stderr, "ARGH! %p not a clone of %p\n", buddy, clone );
            break;
        }
        fprintf( stderr, "(removing clone %p %ld (of buddy: %p)\n", 
                 clone, (long)clone, buddy );
        fprintf( stderr, "   name : %s\n", purple_buddy_get_name(clone) );
        fprintf( stderr, "   group: %s)\n", 
                 purple_group_get_name( purple_buddy_get_group(clone) ) );
        purple_blist_remove_buddy( clone );
    }

    xmlnode *rval = xnode_new( "alist" );
    AL_PTR( rval, "account-uid" , acct  );
    AL_PTR( rval, "bnode-uid"   , buddy );
    AL_PTR( rval, "group-uid"   , group );
    AL_STR( rval, "bnode-name"  , purple_buddy_get_name         ( buddy ) );
    AL_STR( rval, "bnode-alias" , purple_buddy_get_alias        ( buddy ) );
    AL_STR( rval, "account-name", purple_account_get_username   ( acct  ) );
    AL_STR( rval, "im-protocol" , purple_account_get_protocol_id( acct  ) );
    AL_STR( rval, "group-name"  , purple_group_get_name         ( group ) );

    sexp_val_free( args );
    return response_value( 0, id, name, rval );
}
Пример #3
0
xmlnode * _h_elim_message ( const char *name ,
                            const char *id   ,
                            SEXP_VALUE *args ,
                            gpointer data    )
{
    fprintf(stderr, "(elim-debug entered _h_elim_message)");
    ASSERT_ALISTP( args, id, name );
    
    elim_ping();

    const char *aname = ALIST_VAL_STR( args, "account-name" );
    const char *proto = ALIST_VAL_STR( args, "im-protocol"  );
    gpointer    auid  = ALIST_VAL_PTR( args, "account-uid"  );

    PurpleAccount *acct = 
      auid ? find_acct_by_uid( auid ) : purple_accounts_find( aname, proto );

    if( !acct )
    {
        sexp_val_free( args );
        return response_error( ENXIO, id, name, "unknown account" );
    }

    PurpleConversationType pt = PURPLE_CONV_TYPE_UNKNOWN;
    gpointer             cuid = ALIST_VAL_PTR( args, "conv-uid"  );
    const char         *cname = ALIST_VAL_STR( args, "conv-name" );
    PurpleConversation    *pc = find_conv_by_acct_uid( acct, cuid );

    if  ( pc ) pt = purple_conversation_get_type( pc );
    else
    {
        pt = PURPLE_CONV_TYPE_ANY;
        pc = purple_find_conversation_with_account( pt, cname, acct );
        if( !pc )
        {
            pt = PURPLE_CONV_TYPE_IM;
            pc = purple_conversation_new( pt, acct, cname );
        }
        else { pt = purple_conversation_get_type( pc ); }
    }

    if( !pc )
    {
        sexp_val_free( args );
        return response_error( ENXIO, id, name, "new conversation failed" );
    }

    PurpleConvIm   *pci = NULL;
    PurpleConvChat *pcc = NULL;
    const char     *msg = ALIST_VAL_STRING( args, "text" );
    char           *esc = g_markup_escape_text( msg, -1 );
    int             len = strlen( esc );

    switch( pt )
    {
      case PURPLE_CONV_TYPE_IM:
        pci = purple_conversation_get_im_data( pc );
        purple_conv_im_send( pci, esc );
        break;
      case PURPLE_CONV_TYPE_CHAT:
        pcc = purple_conversation_get_chat_data( pc );
        purple_conv_chat_send( pcc, esc );
        break;
      default:
        g_free       ( esc  );
        sexp_val_free( args );
        return response_error( EINVAL, id, name, "unknown conversation type" );
    }

    xmlnode *rval = xnode_new( "alist" );
    AL_INT( rval, "bytes"    , len     );
    AL_PTR( rval, "conv-uid" , pc      );
    AL_STR( rval, "conv-name", purple_conversation_get_name(pc) );

    g_free       ( esc  );
    sexp_val_free( args );
    fprintf(stderr, "(elim-debug leaving _h_elim_message)");
    return response_value( 0, id, name, rval );
}
Пример #4
0
xmlnode * _h_elim_remove_buddy ( const char *name ,
                                 const char *id   ,
                                 SEXP_VALUE *args ,
                                 gpointer data    )
{
    ASSERT_ALISTP( args, id, name );

    fprintf( stderr, "(elim-remove-buddy)\n" );

    elim_ping();
    
    const char    *aname = ALIST_VAL_STR( args, "account-name" );
    const char    *proto = ALIST_VAL_STR( args, "im-protocol"  );
    gpointer       auid  = ALIST_VAL_PTR( args, "account-uid"  );
    PurpleAccount *acct  = NULL;

    gpointer       b_uid = ALIST_VAL_PTR( args, "bnode-uid" );
    const char    *b_arg = NULL;
    const char    *bname = NULL;
    const char    *gname = NULL; 
    PurpleGroup   *group = NULL; 
    PurpleBuddy   *buddy = NULL;
    gboolean       gone  = FALSE;

    if( b_uid )
    {
        PurpleBlistNodeType type = PURPLE_BLIST_OTHER_NODE;
        PurpleBlistNode    *node = find_blist_node_by_uid( b_uid , TRUE );

        if( !node )
        {
            sexp_val_free( args );
            return response_error( EINVAL, id, name, "rogue buddy pointer" );
        }
        type = purple_blist_node_get_type( node );

        // ===========================================================
        // groups, contacts and chats can safely be removed here:
        // buddies should instead be noted for removal in the next
        // block of code as they require client<->server interaction:
        switch( type )
        {
          case PURPLE_BLIST_GROUP_NODE  :
            purple_blist_remove_group  ( (PurpleGroup   *)node );
            gone = TRUE;
            break;
          case PURPLE_BLIST_CONTACT_NODE:
            purple_blist_remove_contact( (PurpleContact *)node );
            gone = TRUE;
            break;
          case PURPLE_BLIST_CHAT_NODE   :
            FIND_ACCOUNT( args, id, name, acct, auid, aname, proto );
            BNODE_ACCOUNT_CHECK(chat,(PurpleChat *)node, acct, args, id, name);
            purple_blist_remove_chat   ( (PurpleChat    *)node );
            gone = TRUE;
            break;
          case PURPLE_BLIST_BUDDY_NODE  :
            buddy = (PurpleBuddy *)node;
            FIND_ACCOUNT( args, id, name, acct, auid, aname, proto );
            BNODE_ACCOUNT_CHECK( buddy, buddy, acct, args, id, name );
            b_arg = purple_buddy_get_name( buddy );
            bname = purple_normalize( acct, b_arg );
            break;
          default:
            sexp_val_free( args );
            return response_error( EINVAL, id, name, 
                                   "Unknown buddy list node type" );
        }

        if( gone )
        {
            xmlnode *rval = xnode_new( "alist" );
            if( acct )
            {
                AL_STR( rval, "account-name", aname );
                AL_STR( rval, "im-protocol" , proto );
                AL_PTR( rval, "account-uid" , acct  );
            }
            AL_PTR ( rval, "bnode-uid" , buddy );
            AL_ENUM( rval, "bnode-type", type  , ":blist-node-type" );

            sexp_val_free( args );
            return response_value( 0, id, name, rval );
        }
    }
    else
    {
        b_arg = ALIST_VAL_STRING( args, "bnode-name" );
        FIND_ACCOUNT( args, id, name, acct, auid, aname, proto );

        if( b_arg )
        {
            bname = purple_normalize( acct, b_arg   );
            gname = ALIST_VAL_STRING( args, "group" );
            group = ( gname && *gname ) ? purple_find_group( gname ) : NULL;
            buddy = ( group ?
                      purple_find_buddy_in_group( acct, bname, group ) :
                      purple_find_buddy         ( acct, bname        ) );
        }
    }

    if( !b_arg || !*b_arg )
    {
        sexp_val_free( args );
        return response_error( EINVAL, id, name, "buddy not specified" );
    }

    // buddy must be in our local list or libpurple won't remove it from the
    // server list ( determined empirically, confirmed by inspecting code ):
    if( !buddy )
    {
        buddy = purple_buddy_new( acct, bname, bname );
        purple_blist_add_buddy  ( buddy, NULL, NULL, NULL );
    }

    if( buddy )
    {
        // the order of the remove operations is important: it has to be
        // this way round, as noted above: account buddy removal won't 
        // happen if the buddy is not in the blist when we try:
        if( !group ) group = purple_buddy_get_group( buddy );
        // is this correct? what if we have more than one copy of said buddy?
        // potentially confusing. dunno what the right thing to do is here.
        purple_account_remove_buddy( acct, buddy, group );
        purple_blist_remove_buddy( buddy );
    }
    else 
    {
        sexp_val_free( args );
        return response_error( ENXIO, id, name, "no such buddy" );
    }
    
    xmlnode *rval = xnode_new( "alist" );
    AL_STR ( rval, "account-name", purple_account_get_username   ( acct ) );
    AL_STR ( rval, "im-protocol" , purple_account_get_protocol_id( acct ) );
    AL_PTR ( rval, "account-uid" , acct  );
    AL_PTR ( rval, "bnode-uid"   , buddy );
    AL_ENUM( rval, "bnode-type", PURPLE_BLIST_BUDDY_NODE, ":blist-node-type" );
    sexp_val_free( args );
    return response_value( 0, id, name, rval );
}
Пример #5
0
xmlnode * _h_elim_command ( const char *name ,
                            const char *id   ,
                            SEXP_VALUE *args ,
                            gpointer data    )
{
    fprintf(stderr, "(elim-debug entered _h_elim_command)");
    ASSERT_ALISTP( args, id, name );
    
    elim_ping();

    const char *aname = ALIST_VAL_STR( args, "account-name" );
    const char *proto = ALIST_VAL_STR( args, "im-protocol"  );
    gpointer    auid  = ALIST_VAL_PTR( args, "account-uid"  );

    PurpleAccount *acct = 
      auid ? find_acct_by_uid( auid ) : purple_accounts_find( aname, proto );

    if( !acct )
    {
        sexp_val_free( args );
        return response_error( ENXIO, id, name, "unknown account" );
    }

    PurpleConversationType pt = PURPLE_CONV_TYPE_UNKNOWN;
    gpointer             cuid = ALIST_VAL_PTR( args, "conv-uid"  );
    const char         *cname = ALIST_VAL_STR( args, "conv-name" );
    PurpleConversation    *pc = find_conv_by_acct_uid( acct, cuid );

    if  ( pc ) pt = purple_conversation_get_type( pc );
    else
    {
        pt = PURPLE_CONV_TYPE_ANY;
        pc = purple_find_conversation_with_account( pt, cname, acct );
        if( !pc )
        {
            sexp_val_free( args );
            return response_error( ENOENT, id, name, "conversation not found" );
        }
        else { pt = purple_conversation_get_type( pc ); }
    }

    PurpleCmdStatus c_s = PURPLE_CMD_STATUS_FAILED;
    const char     *cmd = ALIST_VAL_STRING( args, "command" );
    char           *esc = g_markup_escape_text( cmd, -1 );
    char           *err = NULL;
    const char   *error = NULL;
    c_s = purple_cmd_do_command( pc, cmd, esc, &err );

    if( c_s != PURPLE_CMD_STATUS_OK && (!err || !*err) )
        switch( c_s )
        {
          case PURPLE_CMD_STATUS_FAILED    :
            error = "Command failed";
            break;
          case PURPLE_CMD_STATUS_NOT_FOUND :
            error = "Command not found";
            break;
          case PURPLE_CMD_STATUS_WRONG_ARGS:
            error = "Bad command arguments";
            break;
          case PURPLE_CMD_STATUS_WRONG_PRPL:
            error = "Command not valid for this IM protocol";
            break;
          case PURPLE_CMD_STATUS_WRONG_TYPE:
            error = "Command not valid in this conversation";
            break;
          default:
            error = "Unknown command error";
        }

    xmlnode *rval = xnode_new( "alist" );
    AL_PTR ( rval, "conv-uid"      , pc  );
    AL_STR ( rval, "conv-name"     , purple_conversation_get_name(pc) );

    AL_ENUM( rval, "command-status", c_s , ":cmd-status" );
    AL_STR ( rval, "command-error" , err ? err : error   );
    AL_STR ( rval, "command-line"  , cmd );

    g_free       ( err  );
    g_free       ( esc  );
    sexp_val_free( args );

    fprintf(stderr, "(elim-debug leaving _h_elim_command)");
    return response_value( 0, id, name, rval );
}
Пример #6
0
xmlnode * _h_elim_add_chat( const char *name , 
                            const char *id   ,
                            SEXP_VALUE *args , 
                            gpointer    data )
{
    ASSERT_ALISTP( args, id, name );

    elim_ping();

    const char *aname   = ALIST_VAL_STR  ( args, "account-name" );
    const char *proto   = ALIST_VAL_STR  ( args, "im-protocol"  );
    const char *alias   = ALIST_VAL_STR  ( args, "chat-alias"   );
    gpointer    auid    = ALIST_VAL_PTR  ( args, "account-uid"  );
    GHashTable *opts    = ALIST_VAL_ALIST( args, "chat-options" );
    GHashTable *options = __ghash_str_sexp__str_str( opts );
    PurpleAccount *acct = 
      auid ? find_acct_by_uid( auid ) : purple_accounts_find( aname, proto );

    if( !acct )
    {
        sexp_val_free( args );
        return response_error( ENXIO, id, name, "unknown account" );
    }

    // cook up a chat node. if it's already on our buddy list, uncook it
    // and use the old one instead (name should be unique per account
    // so the operation is reasonable - we cannot supply a name as this
    // parameter can be delegated to the plugin to generate automatically):
    // this will trigger a new_node call, and possibly a remove call 
    PurpleChat *chat = purple_chat_new( acct, alias, options );
    const char *chn  = purple_chat_get_name( chat );
    PurpleChat *ch_2 = purple_blist_find_chat( acct, chn );
    if( ch_2 )
    {
        fprintf( stderr, "(elim-debug chat already exists)\n" );
        purple_blist_remove_chat( chat );
        chat = ch_2;
        chn  = purple_chat_get_name( chat );
        purple_blist_alias_chat( chat, alias );
    }

    fprintf( stderr, "(elim-debug adding chat to blist)\n" );
    purple_blist_add_chat( chat, NULL, NULL );

    // if we have a conversation already, prod the client to show it
    fprintf( stderr, "(elim-debug looking for conversation)\n" );
    PurpleConversation *conv =
      purple_find_conversation_with_account( PURPLE_CONV_TYPE_CHAT, chn, acct );
    if( conv )
        purple_conversation_present( conv );

    xmlnode *rval = xnode_new( "alist" );

    AL_STR( rval, "account-name", purple_account_get_username   (acct) );
    AL_STR( rval, "im-protocol" , purple_account_get_protocol_id(acct) );
    AL_PTR( rval, "account-uid" , acct );
    AL_STR( rval, "chat-name"   , chn  );

    if( conv )
    {
        PurpleConversationType pct = purple_conversation_get_type    ( conv );
        PurpleConnectionFlags  pcf = purple_conversation_get_features( conv );

        AL_PTR ( rval, "conv-uid"     , conv );
        AL_STR ( rval, "conv-name"    , purple_conversation_get_name (conv) );
        AL_STR ( rval, "conv-title"   , purple_conversation_get_title(conv) );
        AL_ENUM( rval, "conv-type"    , pct, ":conversation-type" );
        AL_ENUM( rval, "conv-features", pcf, ":connection-flags"  );
    }

    sexp_val_free( args );
    return response_value( 0, id, name, rval );
}