Beispiel #1
0
static void
steam_cb_friends(SteamApiReq *req, gpointer data)
{
    bee_user_t *bu;
    gchar sid[STEAM_ID_STRMAX];
    GList *l;
    SteamData *sata = data;
    SteamUser *user;
    SteamUserInfo *info;
    struct im_connection *ic = sata->ic;

    if (steam_req_error(sata, req, TRUE)) {
        return;
    }

    if (!(ic->flags & BEE_USER_ONLINE)) {
        imcb_connected(ic);
    }

    for (l = req->infs->head; l != NULL; l = l->next) {
        info = l->data;
        STEAM_ID_STR(info->id, sid);

        /* Attempt to grab the buddy before adding */
        bu = bee_user_by_handle(sata->ic->bee, sata->ic, sid);

        if (bu == NULL) {
            imcb_add_buddy(sata->ic, sid, NULL);
            imcb_buddy_nick_hint(sata->ic, sid, info->nick);
            imcb_rename_buddy(sata->ic, sid, info->fullname);
        }

        bu = bee_user_by_handle(sata->ic->bee, sata->ic, sid);

        if (G_UNLIKELY(bu == NULL)) {
            continue;
        }

        user = bu->data;
        user->vtime = info->vtime;

        switch (info->rel) {
        case STEAM_USER_REL_FRIEND:
            steam_user_status(sata, info, bu);
            break;

        case STEAM_USER_REL_IGNORE:
            ic->deny = g_slist_prepend(ic->deny, g_strdup(bu->handle));
            break;
        }

        if (info->unread > 0) {
            req = steam_api_req_new(req->api, steam_cb_msgs, sata);
            steam_api_req_msgs(req, info->id, info->vtime);
        }
    }

    req = steam_api_req_new(req->api, steam_cb_poll, sata);
    steam_api_req_poll(req);
}
Beispiel #2
0
bee_user_t *bee_user_new(bee_t *bee, struct im_connection *ic, const char *handle, bee_user_flags_t flags)
{
	bee_user_t *bu;

	if (bee_user_by_handle(bee, ic, handle) != NULL) {
		return NULL;
	}

	bu = g_new0(bee_user_t, 1);
	bu->bee = bee;
	bu->ic = ic;
	bu->flags = flags;
	bu->handle = g_strdup(handle);
	bee->users = g_slist_prepend(bee->users, bu);

	if (bee->ui->user_new) {
		bee->ui->user_new(bee, bu);
	}
	if (ic->acc->prpl->buddy_data_add) {
		ic->acc->prpl->buddy_data_add(bu);
	}

	/* Offline by default. This will set the right flags. */
	imcb_buddy_status(ic, handle, 0, NULL, NULL);

	return bu;
}
Beispiel #3
0
/**
 * Implemented #SteamApiFunc for #steam_api_req_user_chatlog().
 *
 * @param req  The #SteamApiReq.
 * @param data The user defined data, which is #SteamData.
 **/
static void steam_cb_user_chatlog(SteamApiReq *req, gpointer data)
{
    SteamData     *sata = data;
    SteamUser     *user;
    SteamUserInfo *info;
    SteamUserMsg  *msg;
    bee_user_t    *bu;
    GList         *l;
    gchar          sid[STEAM_ID_STR_MAX];

    if (steam_req_error(sata, req, TRUE))
        return;

    for (bu = NULL, l = req->msgs->head; l != NULL; l = l->next) {
        msg  = l->data;
        info = msg->info;
        STEAM_ID_STR(info->id, sid);

        if ((bu == NULL) || (g_strcmp0(sid, bu->handle) != 0)) {
            bu = bee_user_by_handle(sata->ic->bee, sata->ic, sid);

            if (G_UNLIKELY(bu == NULL))
                continue;

            user = bu->data;
        }

        if (msg->time > user->vtime)
            steam_user_msg(sata, msg, msg->time);
    }
}
Beispiel #4
0
static xt_status jabber_iq_version_response( struct im_connection *ic,
	struct xt_node *node, struct xt_node *orig )
{
	struct xt_node *query;
	GString *rets;
	char *s;
	char *ret[2] = {};
	bee_user_t *bu;
	struct jabber_buddy *bud = NULL;
	
	if( ( s = xt_find_attr( node, "from" ) ) &&
	    ( bud = jabber_buddy_by_jid( ic, s, 0 ) ) &&
	    ( query = xt_find_node( node->children, "query" ) ) &&
	    ( bu = bee_user_by_handle( ic->bee, ic, bud->bare_jid ) ) )
	{
		rets = g_string_new( "Resource " );
		g_string_append( rets, bud->resource );
	}
	else
		return XT_HANDLED;
	
	for( query = query->children; query; query = query->next )
		if( query->text_len > 0 )
			g_string_append_printf( rets, " %s: %s,", query->name, query->text );
	
	g_string_truncate( rets, rets->len - 1 );
	ret[0] = rets->str;
	imcb_buddy_action_response( bu, "VERSION", ret, NULL );
	g_string_free( rets, TRUE );
	
	return XT_HANDLED;
}
Beispiel #5
0
static int msn_buddy_msg( struct im_connection *ic, char *who, char *message, int away )
{
	struct bee_user *bu = bee_user_by_handle( ic->bee, ic, who );
	struct msn_buddy_data *bd = bu ? bu->data : NULL;
	struct msn_switchboard *sb;
	
#ifdef DEBUG
	if( strcmp( who, "raw" ) == 0 )
	{
		msn_ns_write( ic, -1, "%s\r\n", message );
	}
	else
#endif
	if( bd && bd->flags & MSN_BUDDY_FED )
	{
		msn_ns_sendmessage( ic, bu, message );
	}
	else if( ( sb = msn_sb_by_handle( ic, who ) ) )
	{
		return( msn_sb_sendmessage( sb, message ) );
	}
	else
	{
		struct msn_message *m;
		
		/* Create a message. We have to arrange a usable switchboard, and send the message later. */
		m = g_new0( struct msn_message, 1 );
		m->who = g_strdup( who );
		m->text = g_strdup( message );
		
		return msn_sb_write_msg( ic, m );
	}
	
	return( 0 );
}
Beispiel #6
0
static void msn_add_buddy( struct im_connection *ic, char *who, char *group )
{
	struct bee_user *bu = bee_user_by_handle( ic->bee, ic, who );
	
	msn_buddy_list_add( ic, MSN_BUDDY_FL, who, who, group );
	if( bu && bu->group )
		msn_buddy_list_remove( ic, MSN_BUDDY_FL, who, bu->group->name );
}
Beispiel #7
0
void imcb_buddy_typing(struct im_connection *ic, const char *handle, uint32_t flags)
{
	bee_user_t *bu;

	if (ic->bee->ui->user_typing &&
	    (bu = bee_user_by_handle(ic->bee, ic, handle))) {
		ic->bee->ui->user_typing(ic->bee, bu, flags);
	}
}
Beispiel #8
0
static int msn_send_typing( struct im_connection *ic, char *who, int typing )
{
	struct bee_user *bu = bee_user_by_handle( ic->bee, ic, who );
	
	if( !( bu->flags & BEE_USER_ONLINE ) )
		return 0;
	else if( typing & OPT_TYPING )
		return( msn_buddy_msg( ic, who, TYPING_NOTIFICATION_MESSAGE, 0 ) );
	else
		return 1;
}
Beispiel #9
0
void imcb_buddy_times(struct im_connection *ic, const char *handle, time_t login, time_t idle)
{
	bee_t *bee = ic->bee;
	bee_user_t *bu;

	if (!(bu = bee_user_by_handle(bee, ic, handle))) {
		return;
	}

	bu->login_time = login;
	bu->idle_time = idle;
}
Beispiel #10
0
static void jabber_xmlconsole_enable(struct im_connection *ic)
{
	struct jabber_data *jd = ic->proto_data;
	const char *handle = JABBER_XMLCONSOLE_HANDLE;
	bee_user_t *bu;
	
	jd->flags |= JFLAG_XMLCONSOLE;

	if (!(bu = bee_user_by_handle(ic->bee, ic, handle))) {
		bu = bee_user_new(ic->bee, ic, handle, 0);
		bu->flags |= BEE_USER_NOOTR;
	}
}
Beispiel #11
0
static void cmd_allow(irc_t *irc, char **cmd)
{
	struct im_connection *ic;
	account_t *a;

	if (!cmd[2] && (a = account_get(irc->b, cmd[1])) && a->ic) {
		char *format;
		GSList *l;

		if (strchr(irc->umode, 'b') != NULL) {
			format = "%s\t%s";
		} else {
			format = "%-32.32s  %-16.16s";
		}

		irc_rootmsg(irc, format, "Handle", "Nickname");
		for (l = a->ic->permit; l; l = l->next) {
			bee_user_t *bu = bee_user_by_handle(irc->b, a->ic, l->data);
			irc_user_t *iu = bu ? bu->ui_data : NULL;
			irc_rootmsg(irc, format, l->data, iu ? iu->nick : "(none)");
		}
		irc_rootmsg(irc, "End of list.");

		return;
	} else if (!cmd[2]) {
		irc_user_t *iu = irc_user_by_name(irc, cmd[1]);
		if (!iu || !iu->bu) {
			irc_rootmsg(irc, "Nick `%s' does not exist", cmd[1]);
			return;
		}
		ic = iu->bu->ic;
		cmd[2] = iu->bu->handle;
	} else if (!(a = account_get(irc->b, cmd[1]))) {
		irc_rootmsg(irc, "Invalid account");
		return;
	} else if (!((ic = a->ic) && (a->ic->flags & OPT_LOGGED_IN))) {
		irc_rootmsg(irc, "That account is not on-line");
		return;
	}

	if (!ic->acc->prpl->rem_deny || !ic->acc->prpl->add_permit) {
		irc_rootmsg(irc, "Command `%s' not supported by this protocol", cmd[0]);
	} else {
		imc_rem_block(ic, cmd[2]);
		imc_add_allow(ic, cmd[2]);

		irc_rootmsg(irc, "Buddy `%s' moved from block- to allow-list", cmd[2]);
	}
}
Beispiel #12
0
/* IM->UI callbacks */
void imcb_buddy_status(struct im_connection *ic, const char *handle, int flags, const char *state, const char *message)
{
	bee_t *bee = ic->bee;
	bee_user_t *bu, *old;

	if (!(bu = bee_user_by_handle(bee, ic, handle))) {
		if (g_strcasecmp(set_getstr(&ic->bee->set, "handle_unknown"), "add") == 0) {
			bu = bee_user_new(bee, ic, handle, BEE_USER_LOCAL);
		} else {
			if (g_strcasecmp(set_getstr(&ic->bee->set, "handle_unknown"), "ignore") != 0) {
				imcb_log(ic, "imcb_buddy_status() for unknown handle %s:\n"
				         "flags = %d, state = %s, message = %s", handle, flags,
				         state ? state : "NULL", message ? message : "NULL");
			}

			return;
		}
	}

	/* May be nice to give the UI something to compare against. */
	old = g_memdup(bu, sizeof(bee_user_t));

	/* TODO(wilmer): OPT_AWAY, or just state == NULL ? */
	bu->flags = flags;
	bu->status_msg = g_strdup(message);
	if (state && *state) {
		bu->status = g_strdup(state);
	} else if (flags & OPT_AWAY) {
		bu->status = g_strdup("Away");
	} else {
		bu->status = NULL;
	}

	if (bu->status == NULL && (flags & OPT_MOBILE) &&
	    set_getbool(&bee->set, "mobile_is_away")) {
		bu->flags |= BEE_USER_AWAY;
		bu->status = g_strdup("Mobile");
	}

	if (bee->ui->user_status) {
		bee->ui->user_status(bee, bu, old);
	}

	g_free(old->status_msg);
	g_free(old->status);
	g_free(old);
}
Beispiel #13
0
int msn_buddy_list_remove( struct im_connection *ic, msn_buddy_flags_t list, const char *who, const char *group )
{
	struct msn_data *md = ic->proto_data;
	char groupid[8];
	bee_user_t *bu;
	struct msn_buddy_data *bd;
	char *adl;
	
	*groupid = '\0';
#if 0
	if( group )
	{
		int i;
		for( i = 0; i < md->groupcount; i ++ )
			if( g_strcasecmp( md->grouplist[i], group ) == 0 )
			{
				g_snprintf( groupid, sizeof( groupid ), " %d", i );
				break;
			}
	}
#endif
	
	if( !( bu = bee_user_by_handle( ic->bee, ic, who ) ) ||
	    !( bd = bu->data ) || !( bd->flags & list ) )
		return 1;
	
	bd->flags &= ~list;
	
	if( list == MSN_BUDDY_FL )
		msn_soap_ab_contact_del( ic, bu );
	else
		msn_soap_memlist_edit( ic, who, FALSE, list );
	
	if( ( adl = adlrml_entry( who, list ) ) )
	{
		int st = msn_ns_write( ic, -1, "RML %d %zd\r\n%s",
		                       ++md->trId, strlen( adl ), adl );
		g_free( adl );
		
		return st;
	}
	
	return 1;
}
Beispiel #14
0
static void omegle_add_permit(struct im_connection *ic, char *who)
{
	struct bee_user *bu = bee_user_by_handle(ic->bee, ic, who);
	struct omegle_buddy_data *bd = bu->data;
	account_t *acc = ic->acc;
	char *host = set_getstr(&acc->set, "host");

	if (bd->connecting || bd->session_id)
		return;

	bd->connecting = TRUE;

	if (host) {
		omegle_normal_start_convo(ic, who, g_strdup(host));
	}
	else {
		omegle_get(bu, "omegle.com", "/status", omegle_normal_chose_server);
	}
}
Beispiel #15
0
/* Same, but only change the away/status message, not any away/online state info. */
void imcb_buddy_status_msg(struct im_connection *ic, const char *handle, const char *message)
{
	bee_t *bee = ic->bee;
	bee_user_t *bu, *old;

	if (!(bu = bee_user_by_handle(bee, ic, handle))) {
		return;
	}

	old = g_memdup(bu, sizeof(bee_user_t));

	bu->status_msg = message && *message ? g_strdup(message) : NULL;

	if (bee->ui->user_status) {
		bee->ui->user_status(bee, bu, old);
	}

	g_free(old->status_msg);
	g_free(old);
}
Beispiel #16
0
/**
 * Add a buddy if it is not already added, set the status to logged in.
 */
static void twitter_add_buddy(struct im_connection *ic, char *name, const char *fullname)
{
    struct twitter_data *td = ic->proto_data;

    // Check if the buddy is already in the buddy list.
    if (!bee_user_by_handle(ic->bee, ic, name)) {
        char *mode = set_getstr(&ic->acc->set, "mode");

        // The buddy is not in the list, add the buddy and set the status to logged in.
        imcb_add_buddy(ic, name, NULL);
        imcb_rename_buddy(ic, name, fullname);
        if (g_strcasecmp(mode, "chat") == 0) {
            /* Necessary so that nicks always get translated to the
               exact Twitter username. */
            imcb_buddy_nick_hint(ic, name, name);
            imcb_chat_add_buddy(td->timeline_gc, name);
        } else if (g_strcasecmp(mode, "many") == 0)
            imcb_buddy_status(ic, name, OPT_LOGGED_IN, NULL, NULL);
    }
}
Beispiel #17
0
static void torchat_parse_latency(struct im_connection *ic, char *address, char* line)
{
	bee_user_t *bu = bee_user_by_handle(ic->bee, ic, address);
	int size = 1;
	char** argv = g_realloc_n(NULL, size, sizeof(char*));

	char **pieces, **pieceptr, *piece;

	pieceptr = pieces = g_strsplit(line, " ", 0);

	while ((piece = *pieceptr++) && strlen(piece)) {
		argv = g_realloc_n(argv, ++size, sizeof(char*));
		argv[size - 2] = piece;
	}

	argv[size - 1] = 0;

	imcb_buddy_action_response(bu, "PING", argv, NULL);

	g_free(argv);
	g_strfreev(pieces);
}
Beispiel #18
0
static xt_status jabber_add_to_roster_callback( struct im_connection *ic, struct xt_node *node, struct xt_node *orig )
{
	char *s, *jid = NULL;
	struct xt_node *c;
	
	if( ( c = xt_find_node( orig->children, "query" ) ) &&
	    ( c = xt_find_node( c->children, "item" ) ) &&
	    ( jid = xt_find_attr( c, "jid" ) ) &&
	    ( s = xt_find_attr( node, "type" ) ) &&
	    strcmp( s, "result" ) == 0 )
	{
		if( bee_user_by_handle( ic->bee, ic, jid ) == NULL )
			imcb_add_buddy( ic, jid, NULL );
	}
	else
	{
		imcb_log( ic, "Error while adding `%s' to your contact list.",
		          jid ? jid : "(unknown handle)" );
	}
	
	return XT_HANDLED;
}
Beispiel #19
0
void imcb_buddy_msg(struct im_connection *ic, const char *handle, const char *msg, uint32_t flags, time_t sent_at)
{
	bee_t *bee = ic->bee;
	bee_user_t *bu;

	bu = bee_user_by_handle(bee, ic, handle);

	if (!bu && !(ic->flags & OPT_LOGGING_OUT)) {
		char *h = set_getstr(&bee->set, "handle_unknown");

		if (g_strcasecmp(h, "ignore") == 0) {
			return;
		} else if (g_strncasecmp(h, "add", 3) == 0) {
			bu = bee_user_new(bee, ic, handle, BEE_USER_LOCAL);
		}
	}

	if (bee->ui->user_msg && bu) {
		bee->ui->user_msg(bee, bu, msg, sent_at);
	} else {
		imcb_log(ic, "Message from unknown handle %s:\n%s", handle, msg);
	}
}
Beispiel #20
0
int msn_buddy_list_add( struct im_connection *ic, msn_buddy_flags_t list, const char *who, const char *realname, const char *group )
{
	struct msn_data *md = ic->proto_data;
	char groupid[8];
	bee_user_t *bu;
	struct msn_buddy_data *bd;
	char *adl;
	
	*groupid = '\0';
#if 0
	if( group )
	{
		int i;
		for( i = 0; i < md->groupcount; i ++ )
			if( g_strcasecmp( md->grouplist[i], group ) == 0 )
			{
				g_snprintf( groupid, sizeof( groupid ), " %d", i );
				break;
			}
		
		if( *groupid == '\0' )
		{
			/* Have to create this group, it doesn't exist yet. */
			struct msn_groupadd *ga;
			GSList *l;
			
			for( l = md->grpq; l; l = l->next )
			{
				ga = l->data;
				if( g_strcasecmp( ga->group, group ) == 0 )
					break;
			}
			
			ga = g_new0( struct msn_groupadd, 1 );
			ga->who = g_strdup( who );
			ga->group = g_strdup( group );
			md->grpq = g_slist_prepend( md->grpq, ga );
			
			if( l == NULL )
			{
				char groupname[strlen(group)+1];
				strcpy( groupname, group );
				http_encode( groupname );
				g_snprintf( buf, sizeof( buf ), "ADG %d %s %d\r\n", ++md->trId, groupname, 0 );
				return msn_write( ic, buf, strlen( buf ) );
			}
			else
			{
				/* This can happen if the user's doing lots of adds to a
				   new group at once; we're still waiting for the server
				   to confirm group creation. */
				return 1;
			}
		}
	}
#endif
	
	if( !( ( bu = bee_user_by_handle( ic->bee, ic, who ) ) ||
	       ( bu = bee_user_new( ic->bee, ic, who, 0 ) ) ) ||
	    !( bd = bu->data ) || bd->flags & list )
		return 1;
	
	bd->flags |= list;
	
	if( list == MSN_BUDDY_FL )
		msn_soap_ab_contact_add( ic, bu );
	else
		msn_soap_memlist_edit( ic, who, TRUE, list );
	
	if( ( adl = adlrml_entry( who, list ) ) )
	{
		int st = msn_ns_write( ic, -1, "ADL %d %zd\r\n%s",
		                       ++md->trId, strlen( adl ), adl );
		g_free( adl );
		
		return st;
	}
	
	return 1;
}
Beispiel #21
0
static void skype_parse_user(struct im_connection *ic, char *line)
{
	int flags = 0;
	char *ptr;
	struct skype_data *sd = ic->proto_data;
	char *user = strchr(line, ' ');
	char *status = strrchr(line, ' ');

	status++;
	ptr = strchr(++user, ' ');
	if (!ptr)
		return;
	*ptr = '\0';
	ptr++;
	if (!strncmp(ptr, "ONLINESTATUS ", 13)) {
		if (!strlen(user) || !strcmp(user, sd->username))
			return;
		if (!set_getbool(&ic->acc->set, "test_join")
				&& !strcmp(user, "echo123"))
			return;
		ptr = g_strdup_printf("*****@*****.**", user);
		imcb_add_buddy(ic, ptr, skype_group_by_username(ic, user));
		if (strcmp(status, "OFFLINE") && (strcmp(status, "SKYPEOUT") ||
			!set_getbool(&ic->acc->set, "skypeout_offline")))
			flags |= OPT_LOGGED_IN;
		if (strcmp(status, "ONLINE") && strcmp(status, "SKYPEME"))
			flags |= OPT_AWAY;
		imcb_buddy_status(ic, ptr, flags, NULL, NULL);
		g_free(ptr);
	} else if (!strncmp(ptr, "RECEIVEDAUTHREQUEST ", 20)) {
		char *message = ptr + 20;
		if (strlen(message))
			skype_buddy_ask(ic, user, message);
	} else if (!strncmp(ptr, "BUDDYSTATUS ", 12)) {
		char *st = ptr + 12;
		if (!strcmp(st, "3")) {
			char *buf = g_strdup_printf("*****@*****.**", user);
			imcb_add_buddy(ic, buf, skype_group_by_username(ic, user));
			g_free(buf);
		}
	} else if (!strncmp(ptr, "MOOD_TEXT ", 10)) {
		char *buf = g_strdup_printf("*****@*****.**", user);
		bee_user_t *bu = bee_user_by_handle(ic->bee, ic, buf);
		g_free(buf);
		buf = ptr + 10;
		if (bu)
			imcb_buddy_status(ic, bu->handle, bu->flags, NULL,
					*buf ? buf : NULL);
		if (set_getbool(&ic->acc->set, "show_moods"))
			imcb_log(ic, "User `%s' changed mood text to `%s'", user, buf);
	} else if (!strncmp(ptr, "FULLNAME ", 9)) {
		char *name = ptr + 9;
		if (sd->is_info) {
			sd->is_info = FALSE;
			sd->info_fullname = g_strdup(name);
		} else {
			char *buf = g_strdup_printf("*****@*****.**", user);
			imcb_rename_buddy(ic, buf, name);
			g_free(buf);
		}
	} else if (!strncmp(ptr, "PHONE_HOME ", 11))
		sd->info_phonehome = g_strdup(ptr + 11);
	else if (!strncmp(ptr, "PHONE_OFFICE ", 13))
		sd->info_phoneoffice = g_strdup(ptr + 13);
	else if (!strncmp(ptr, "PHONE_MOBILE ", 13))
		sd->info_phonemobile = g_strdup(ptr + 13);
	else if (!strncmp(ptr, "NROF_AUTHED_BUDDIES ", 20))
		sd->info_nrbuddies = g_strdup(ptr + 20);
	else if (!strncmp(ptr, "TIMEZONE ", 9))
		sd->info_tz = g_strdup(ptr + 9);
	else if (!strncmp(ptr, "LASTONLINETIMESTAMP ", 20))
		sd->info_seen = g_strdup(ptr + 20);
	else if (!strncmp(ptr, "SEX ", 4))
		sd->info_sex = g_strdup(ptr + 4);
	else if (!strncmp(ptr, "LANGUAGE ", 9))
		sd->info_language = g_strdup(ptr + 9);
	else if (!strncmp(ptr, "COUNTRY ", 8))
		sd->info_country = g_strdup(ptr + 8);
	else if (!strncmp(ptr, "PROVINCE ", 9))
		sd->info_province = g_strdup(ptr + 9);
	else if (!strncmp(ptr, "CITY ", 5))
		sd->info_city = g_strdup(ptr + 5);
	else if (!strncmp(ptr, "HOMEPAGE ", 9))
		sd->info_homepage = g_strdup(ptr + 9);
	else if (!strncmp(ptr, "ABOUT ", 6)) {
		/* Support multiple about lines. */
		if (!sd->info_about)
			sd->info_about = g_strdup(ptr + 6);
		else {
			GString *st = g_string_new(sd->info_about);
			g_string_append_printf(st, "\n%s", ptr + 6);
			g_free(sd->info_about);
			sd->info_about = g_strdup(st->str);
			g_string_free(st, TRUE);
		}
	} else if (!strncmp(ptr, "BIRTHDAY ", 9)) {
		sd->info_birthday = g_strdup(ptr + 9);

		GString *st = g_string_new("Contact Information\n");
		g_string_append_printf(st, "Skype Name: %s\n", user);
		if (sd->info_fullname) {
			if (strlen(sd->info_fullname))
				g_string_append_printf(st, "Full Name: %s\n",
					sd->info_fullname);
			g_free(sd->info_fullname);
			sd->info_fullname = NULL;
		}
		if (sd->info_phonehome) {
			if (strlen(sd->info_phonehome))
				g_string_append_printf(st, "Home Phone: %s\n",
					sd->info_phonehome);
			g_free(sd->info_phonehome);
			sd->info_phonehome = NULL;
		}
		if (sd->info_phoneoffice) {
			if (strlen(sd->info_phoneoffice))
				g_string_append_printf(st, "Office Phone: %s\n",
					sd->info_phoneoffice);
			g_free(sd->info_phoneoffice);
			sd->info_phoneoffice = NULL;
		}
		if (sd->info_phonemobile) {
			if (strlen(sd->info_phonemobile))
				g_string_append_printf(st, "Mobile Phone: %s\n",
					sd->info_phonemobile);
			g_free(sd->info_phonemobile);
			sd->info_phonemobile = NULL;
		}
		g_string_append_printf(st, "Personal Information\n");
		if (sd->info_nrbuddies) {
			if (strlen(sd->info_nrbuddies))
				g_string_append_printf(st,
					"Contacts: %s\n", sd->info_nrbuddies);
			g_free(sd->info_nrbuddies);
			sd->info_nrbuddies = NULL;
		}
		if (sd->info_tz) {
			if (strlen(sd->info_tz)) {
				char ib[256];
				time_t t = time(NULL);
				t += atoi(sd->info_tz)-(60*60*24);
				struct tm *gt = gmtime(&t);
				strftime(ib, 256, "%H:%M:%S", gt);
				g_string_append_printf(st,
					"Local Time: %s\n", ib);
			}
			g_free(sd->info_tz);
			sd->info_tz = NULL;
		}
		if (sd->info_seen) {
			if (strlen(sd->info_seen)) {
				char ib[256];
				time_t it = atoi(sd->info_seen);
				struct tm *tm = localtime(&it);
				strftime(ib, 256, ("%Y. %m. %d. %H:%M"), tm);
				g_string_append_printf(st,
					"Last Seen: %s\n", ib);
			}
			g_free(sd->info_seen);
			sd->info_seen = NULL;
		}
		if (sd->info_birthday) {
			if (strlen(sd->info_birthday) &&
				strcmp(sd->info_birthday, "0")) {
				char ib[256];
				struct tm tm;
				strptime(sd->info_birthday, "%Y%m%d", &tm);
				strftime(ib, 256, "%B %d, %Y", &tm);
				g_string_append_printf(st,
					"Birthday: %s\n", ib);

				strftime(ib, 256, "%Y", &tm);
				int year = atoi(ib);
				time_t t = time(NULL);
				struct tm *lt = localtime(&t);
				g_string_append_printf(st,
					"Age: %d\n", lt->tm_year+1900-year);
			}
			g_free(sd->info_birthday);
			sd->info_birthday = NULL;
		}
		if (sd->info_sex) {
			if (strlen(sd->info_sex)) {
				char *iptr = sd->info_sex;
				while (*iptr++)
					*iptr = tolower(*iptr);
				g_string_append_printf(st,
					"Gender: %s\n", sd->info_sex);
			}
			g_free(sd->info_sex);
			sd->info_sex = NULL;
		}
		if (sd->info_language) {
			if (strlen(sd->info_language)) {
				char *iptr = strchr(sd->info_language, ' ');
				if (iptr)
					iptr++;
				else
					iptr = sd->info_language;
				g_string_append_printf(st,
					"Language: %s\n", iptr);
			}
			g_free(sd->info_language);
			sd->info_language = NULL;
		}
		if (sd->info_country) {
			if (strlen(sd->info_country)) {
				char *iptr = strchr(sd->info_country, ' ');
				if (iptr)
					iptr++;
				else
					iptr = sd->info_country;
				g_string_append_printf(st,
					"Country: %s\n", iptr);
			}
			g_free(sd->info_country);
			sd->info_country = NULL;
		}
		if (sd->info_province) {
			if (strlen(sd->info_province))
				g_string_append_printf(st,
					"Region: %s\n", sd->info_province);
			g_free(sd->info_province);
			sd->info_province = NULL;
		}
		if (sd->info_city) {
			if (strlen(sd->info_city))
				g_string_append_printf(st,
					"City: %s\n", sd->info_city);
			g_free(sd->info_city);
			sd->info_city = NULL;
		}
		if (sd->info_homepage) {
			if (strlen(sd->info_homepage))
				g_string_append_printf(st,
					"Homepage: %s\n", sd->info_homepage);
			g_free(sd->info_homepage);
			sd->info_homepage = NULL;
		}
		if (sd->info_about) {
			if (strlen(sd->info_about))
				g_string_append_printf(st, "%s\n",
					sd->info_about);
			g_free(sd->info_about);
			sd->info_about = NULL;
		}
		imcb_log(ic, "%s", st->str);
		g_string_free(st, TRUE);
	}
}