Example #1
0
/**
 * Called after username is set.
 */
static void msim_username_is_set_cb(MsimSession *session, const MsimMessage *userinfo, gpointer data)
{
    gchar *username;
    const gchar *errmsg;
    MsimMessage *body;

    guint rid;
    gint cmd,dsn,uid,lid,code;
    /* \persistr\\cmd\258\dsn\9\uid\204084363\lid\14\rid\369\body\UserName=TheAlbinoRhino1.Code=0\final\ */

    purple_debug_info("msim","username_is_set made\n");

    g_return_if_fail(MSIM_SESSION_VALID(session));

    cmd = msim_msg_get_integer(userinfo, "cmd");
    dsn = msim_msg_get_integer(userinfo, "dsn");
    uid = msim_msg_get_integer(userinfo, "uid");
    lid = msim_msg_get_integer(userinfo, "lid");
    body = msim_msg_get_dictionary(userinfo, "body");
    /* XXX: Mark for translation */
    errmsg = ("An error occurred while trying to set the username.\n"
              "Please try again, or visit http://editprofile.myspace.com/index.cfm?"
              "fuseaction=profile.username to set your username.");

    if (!body) {
        purple_debug_info("msim_username_is_set_cb", "No body");
        /* Error: No body! */
        purple_connection_error_reason(session->gc, PURPLE_CONNECTION_ERROR_OTHER_ERROR, errmsg);
    }
    username = msim_msg_get_string(body, "UserName");
    code = msim_msg_get_integer(body,"Code");

    msim_msg_free(body);

    purple_debug_info("msim_username_is_set_cb",
                      "cmd = %d, dsn = %d, lid = %d, code = %d, username = %s\n",
                      cmd, dsn, lid, code, username);

    if (cmd == (MSIM_CMD_BIT_REPLY | MSIM_CMD_PUT)
            && dsn == MC_SET_USERNAME_DSN
            && lid == MC_SET_USERNAME_LID)
    {
        purple_debug_info("msim_username_is_set_cb", "Proper cmd,dsn,lid for username_is_set!\n");
        purple_debug_info("msim_username_is_set_cb", "Username Set with return code %d\n",code);
        if (code == 0) {
            /* Good! */
            session->username = username;
            msim_we_are_logged_on(session);
        } else {
            purple_debug_info("msim_username_is_set", "code is %d",code);
            /* TODO: what to do here? */
        }
    } else if (cmd == (MSIM_CMD_BIT_REPLY | MSIM_CMD_GET)
               && dsn == MG_MYSPACE_INFO_BY_STRING_DSN
               && lid == MG_MYSPACE_INFO_BY_STRING_LID) {
        /* Not quite done... ONE MORE STEP :) */
        rid = msim_new_reply_callback(session, msim_username_is_set_cb, data);
        body = msim_msg_new("UserName", MSIM_TYPE_STRING, g_strdup(username), NULL);
        if (!msim_send(session, "persist", MSIM_TYPE_INTEGER, 1,
                       "sesskey", MSIM_TYPE_INTEGER, session->sesskey,
                       "cmd", MSIM_TYPE_INTEGER, MSIM_CMD_PUT,
                       "dsn", MSIM_TYPE_INTEGER, MC_SET_USERNAME_DSN,
                       "uid", MSIM_TYPE_INTEGER, session->userid,
                       "lid", MSIM_TYPE_INTEGER, MC_SET_USERNAME_LID,
                       "rid", MSIM_TYPE_INTEGER, rid,
                       "body", MSIM_TYPE_DICTIONARY, body,
                       NULL)) {
            /* Error! */
            /* Can't set... Disconnect */
            purple_connection_error_reason(session->gc, PURPLE_CONNECTION_ERROR_OTHER_ERROR, errmsg);
        }

    } else {
        /* Error! */
        purple_debug_info("msim","username_is_set Error: Invalid cmd/dsn/lid combination");
        purple_connection_error_reason(session->gc, PURPLE_CONNECTION_ERROR_OTHER_ERROR, errmsg);
    }
}
static void
pb_socket_got_data(gpointer userdata, PurpleSslConnection *conn, PurpleInputCondition cond)
{
	PushBulletAccount *pba = userdata;
	gchar *frame;
	guchar packet_code, length_code;
	guint64 frame_len;
	int read_len = 0;
	gboolean done_some_reads = FALSE;
	
	
	if (G_UNLIKELY(!pba->websocket_header_received)) {
		// HTTP/1.1 101 Switching Protocols
		// Server: nginx
		// Date: Sun, 19 Jul 2015 23:44:27 GMT
		// Connection: upgrade
		// Upgrade: websocket
		// Sec-WebSocket-Accept: pUDN5Js0uDN5KhEWoPJGLyTqwME=
		// Expires: 0
		// Cache-Control: no-cache
		gint nlbr_count = 0;
		gchar nextchar;
		
		while(nlbr_count < 4 && purple_ssl_read(conn, &nextchar, 1)) {
			if (nextchar == '\r' || nextchar == '\n') {
				nlbr_count++;
			} else {
				nlbr_count = 0;
			}
		}
		
		pba->websocket_header_received = TRUE;
		done_some_reads = TRUE;
	}
	
	packet_code = 0;
	while((read_len = purple_ssl_read(conn, &packet_code, 1)) == 1) {
		done_some_reads = TRUE;
		if (packet_code != 129) {
			if (packet_code == 136) {
				purple_debug_error("pushbullet", "websocket closed\n");
				
				purple_ssl_close(conn);
				pba->websocket = NULL;
				pba->websocket_header_received = FALSE;
				
				// revert to polling
				pb_start_polling(pba);
				
				return;
			}
			purple_debug_error("pushbullet", "unknown websocket error %d\n", packet_code);
			return;
		}
		
		length_code = 0;
		purple_ssl_read(conn, &length_code, 1);
		if (length_code <= 125) {
			frame_len = length_code;
		} else if (length_code == 126) {
			guchar len_buf[2];
			purple_ssl_read(conn, len_buf, 2);
			frame_len = (len_buf[1] << 8) + len_buf[0];
		} else if (length_code == 127) {
			purple_ssl_read(conn, &frame_len, 8);
			frame_len = GUINT64_FROM_BE(frame_len);
		}
		purple_debug_info("pushbullet", "frame_len: %d\n", frame_len);
		
		frame = g_new0(gchar, frame_len + 1);
		purple_ssl_read(conn, frame, frame_len);
		
		pb_process_frame(pba, frame);
		
		g_free(frame);
		packet_code = 0;
	}
	
	if (done_some_reads == FALSE && read_len == 0) {
		purple_connection_error_reason(pba->pc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, "Lost connection to server");
	}
}
Example #3
0
static gboolean
flap_connection_destroy_cb(gpointer data)
{
	FlapConnection *conn;
	OscarData *od;
	PurpleAccount *account;
	aim_rxcallback_t userfunc;

	conn = data;
	/* Explicitly added for debugging #5927.  Don't re-order this, only
	 * consider removing it.
	 */
	purple_debug_info("oscar", "Destroying FLAP connection %p\n", conn);

	od = conn->od;
	account = purple_connection_get_account(od->gc);

	purple_debug_info("oscar", "Destroying oscar connection (%p) of "
			"type 0x%04hx.  Disconnect reason is %d\n", conn,
			conn->type, conn->disconnect_reason);

	od->oscar_connections = g_slist_remove(od->oscar_connections, conn);

	if ((userfunc = aim_callhandler(od, AIM_CB_FAM_SPECIAL, AIM_CB_SPECIAL_CONNERR)))
		userfunc(od, conn, NULL, conn->disconnect_code, conn->error_message);

	/*
	 * TODO: If we don't have a SNAC_FAMILY_LOCATE connection then
	 * we should try to request one instead of disconnecting.
	 */
	if (!account->disconnecting && ((od->oscar_connections == NULL)
			|| (!flap_connection_getbytype(od, SNAC_FAMILY_LOCATE))))
	{
		/* No more FLAP connections!  Sign off this PurpleConnection! */
		gchar *tmp;
		PurpleConnectionError reason = PURPLE_CONNECTION_ERROR_NETWORK_ERROR;

		if (conn->disconnect_code == 0x0001) {
			reason = PURPLE_CONNECTION_ERROR_NAME_IN_USE;
			tmp = g_strdup(_("You have signed on from another location"));
			if (!purple_account_get_remember_password(account))
				purple_account_set_password(account, NULL);
		} else if (conn->disconnect_reason == OSCAR_DISCONNECT_REMOTE_CLOSED)
			tmp = g_strdup(_("Server closed the connection"));
		else if (conn->disconnect_reason == OSCAR_DISCONNECT_LOST_CONNECTION)
			tmp = g_strdup_printf(_("Lost connection with server: %s"),
					conn->error_message);
		else if (conn->disconnect_reason == OSCAR_DISCONNECT_INVALID_DATA)
			tmp = g_strdup(_("Received invalid data on connection with server"));
		else if (conn->disconnect_reason == OSCAR_DISCONNECT_COULD_NOT_CONNECT)
			tmp = g_strdup_printf(_("Unable to connect: %s"),
					conn->error_message);
		else
			/*
			 * We shouldn't print a message for some disconnect_reasons.
			 * Like OSCAR_DISCONNECT_LOCAL_CLOSED.
			 */
			tmp = NULL;

		if (tmp != NULL)
		{
			purple_connection_error_reason(od->gc, reason, tmp);
			g_free(tmp);
		}
	}

	flap_connection_close(od, conn);

	g_free(conn->error_message);
	g_free(conn->cookie);

	/*
	 * Free conn->internal, if necessary
	 */
	if (conn->type == SNAC_FAMILY_CHAT)
		flap_connection_destroy_chat(od, conn);

	g_slist_free(conn->groups);
	while (conn->rateclasses != NULL)
	{
		g_free(conn->rateclasses->data);
		conn->rateclasses = g_slist_delete_link(conn->rateclasses, conn->rateclasses);
	}

	g_hash_table_destroy(conn->rateclass_members);

	if (conn->queued_snacs) {
		while (!g_queue_is_empty(conn->queued_snacs))
		{
			QueuedSnac *queued_snac;
			queued_snac = g_queue_pop_head(conn->queued_snacs);
			flap_frame_destroy(queued_snac->frame);
			g_free(queued_snac);
		}
		g_queue_free(conn->queued_snacs);
	}

	if (conn->queued_lowpriority_snacs) {
		while (!g_queue_is_empty(conn->queued_lowpriority_snacs))
		{
			QueuedSnac *queued_snac;
			queued_snac = g_queue_pop_head(conn->queued_lowpriority_snacs);
			flap_frame_destroy(queued_snac->frame);
			g_free(queued_snac);
		}
		g_queue_free(conn->queued_lowpriority_snacs);
	}

	if (conn->queued_timeout > 0)
		purple_timeout_remove(conn->queued_timeout);

	g_free(conn);

	return FALSE;
}
Example #4
0
/* Warning: qq_connect_later destory all connection
 *  Any function should be care of use qq_data after call this function
 *  Please conside tcp_pending and udp_pending */
gboolean qq_connect_later(gpointer data)
{
	PurpleConnection *gc;
	char *tmp_server;
	int port;
	gchar **segments;
	qq_data *qd;

	gc = (PurpleConnection *) data;
	g_return_val_if_fail(gc != NULL && gc->proto_data != NULL, FALSE);
	qd = (qq_data *) gc->proto_data;
	tmp_server = NULL;

	if (qd->check_watcher > 0) {
		purple_timeout_remove(qd->check_watcher);
		qd->check_watcher = 0;
	}
	qq_disconnect(gc);

	if (qd->redirect_ip.s_addr != 0) {
		/* redirect to new server */
		tmp_server = g_strdup_printf("%s:%d", inet_ntoa(qd->redirect_ip), qd->redirect_port);
		qd->servers = g_list_append(qd->servers, tmp_server);

		qd->curr_server = tmp_server;
		tmp_server = NULL;

		qd->redirect_ip.s_addr = 0;
		qd->redirect_port = 0;
		qd->connect_retry = QQ_CONNECT_MAX;
	}

	if (qd->curr_server == NULL || strlen (qd->curr_server) == 0 || qd->connect_retry <= 0) {
		if ( set_new_server(qd) != TRUE) {
			purple_connection_error_reason(gc,
					PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
					_("Unable to connect"));
			return FALSE;
		}
		qd->connect_retry = QQ_CONNECT_MAX;
	}

	segments = g_strsplit_set(qd->curr_server, ":", 0);
	tmp_server = g_strdup(segments[0]);
	if (NULL != segments[1]) {
		port = atoi(segments[1]);
		if (port <= 0) {
			purple_debug_info("QQ", "Port not define in %s, use default.\n", qd->curr_server);
			port = QQ_DEFAULT_PORT;
		}
	} else {
		purple_debug_info("QQ", "Error splitting server string: %s, setting port to default.\n", qd->curr_server);
		port = QQ_DEFAULT_PORT;
	}

	g_strfreev(segments);

	qd->connect_retry--;
	if ( !connect_to_server(gc, tmp_server, port) ) {
			purple_connection_error_reason(gc,
				PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
				_("Unable to connect"));
	}

	g_free(tmp_server);
	tmp_server = NULL;

	qd->check_watcher = purple_timeout_add_seconds(QQ_CONNECT_CHECK, connect_check, gc);
	return FALSE;	/* timeout callback stops */
}
Example #5
0
void fb_login_captcha_cancel_cb(PurpleConnection *pc, PurpleRequestFields *fields)
{
	purple_connection_error_reason(pc, PURPLE_CONNECTION_ERROR_OTHER_ERROR,
		"Could not authenticate captcha.  Logging into the Facebook website may fix this.");
}
Example #6
0
static void udp_host_resolved(GSList *hosts, gpointer data, const char *error_message) {
	PurpleConnection *gc;
	qq_data *qd;
	struct sockaddr server_addr;
	int addr_size;
	gint fd = -1;
	int flags;

	gc = (PurpleConnection *) data;
	g_return_if_fail(gc != NULL && gc->proto_data != NULL);

	qd = (qq_data *) gc->proto_data;

	/* udp_query_data must be set as NULL.
	 * Otherwise purple_dnsquery_destroy in qq_disconnect cause glib double free error */
	qd->udp_query_data = NULL;

	if (!hosts || !hosts->data) {
		purple_connection_error_reason(gc,
				PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
				_("Unable to resolve hostname"));
		return;
	}

	addr_size = GPOINTER_TO_INT(hosts->data);
	hosts = g_slist_remove(hosts, hosts->data);
	memcpy(&server_addr, hosts->data, addr_size);
	g_free(hosts->data);

	hosts = g_slist_remove(hosts, hosts->data);
	while(hosts) {
		hosts = g_slist_remove(hosts, hosts->data);
		g_free(hosts->data);
		hosts = g_slist_remove(hosts, hosts->data);
	}

	fd = socket(PF_INET, SOCK_DGRAM, 0);
	if (fd < 0) {
		purple_debug_error("QQ",
				"Unable to create socket: %s\n", g_strerror(errno));
		return;
	}

	/* we use non-blocking mode to speed up connection */
	flags = fcntl(fd, F_GETFL);
	fcntl(fd, F_SETFL, flags | O_NONBLOCK);
#ifndef _WIN32
	fcntl(fd, F_SETFD, FD_CLOEXEC);
#endif

	/* From Unix-socket-FAQ: http://www.faqs.org/faqs/unix-faq/socket/
	 *
	 * If a UDP socket is unconnected, which is the normal state after a
	 * bind() call, then send() or write() are not allowed, since no
	 * destination is available; only sendto() can be used to send data.
	 *
	 * Calling connect() on the socket simply records the specified address
	 * and port number as being the desired communications partner. That
	 * means that send() or write() are now allowed; they use the destination
	 * address and port given on the connect call as the destination of packets.
	 */
	if (connect(fd, &server_addr, addr_size) >= 0) {
		purple_debug_info("QQ", "Connected.\n");
		flags = fcntl(fd, F_GETFL);
		fcntl(fd, F_SETFL, flags & ~O_NONBLOCK);
		connect_cb(gc, fd, NULL);
		return;
	}

	/* [EINPROGRESS]
	 *    The socket is marked as non-blocking and the connection cannot be
	 *    completed immediately. It is possible to select for completion by
	 *    selecting the socket for writing.
	 * [EINTR]
	 *    A signal interrupted the call.
	 *    The connection is established asynchronously.
	 */
	if ((errno == EINPROGRESS) || (errno == EINTR)) {
			purple_debug_warning( "QQ", "Connect in asynchronous mode.\n");
			qd->udp_can_write_handler = purple_input_add(fd, PURPLE_INPUT_WRITE, udp_can_write, gc);
			return;
		}

	purple_debug_error("QQ", "Connection failed: %s\n", g_strerror(errno));
	close(fd);
}
Example #7
0
File: irc.c Project: dylex/pidgin
static void irc_login(PurpleAccount *account)
{
	PurpleConnection *gc;
	struct irc_conn *irc;
	char **userparts;
	const char *username = purple_account_get_username(account);

	gc = purple_account_get_connection(account);
	gc->flags |= PURPLE_CONNECTION_NO_NEWLINES;

	if (strpbrk(username, " \t\v\r\n") != NULL) {
		purple_connection_error_reason (gc,
			PURPLE_CONNECTION_ERROR_INVALID_SETTINGS,
			_("IRC nick and server may not contain whitespace"));
		return;
	}

	gc->proto_data = irc = g_new0(struct irc_conn, 1);
	irc->fd = -1;
	irc->account = account;
	irc->outbuf = purple_circ_buffer_new(512);

	userparts = g_strsplit(username, "@", 2);
	purple_connection_set_display_name(gc, userparts[0]);
	irc->server = g_strdup(userparts[1]);
	g_strfreev(userparts);

	irc->buddies = g_hash_table_new_full((GHashFunc)irc_nick_hash, (GEqualFunc)irc_nick_equal,
					     NULL, (GDestroyNotify)irc_buddy_free);
	irc->cmds = g_hash_table_new(g_str_hash, g_str_equal);
	irc_cmd_table_build(irc);
	irc->msgs = g_hash_table_new(g_str_hash, g_str_equal);
	irc_msg_table_build(irc);

	purple_connection_update_progress(gc, _("Connecting"), 1, 2);

	if (purple_account_get_bool(account, "ssl", FALSE)) {
		if (purple_ssl_is_supported()) {
			irc->gsc = purple_ssl_connect(account, irc->server,
					purple_account_get_int(account, "port", IRC_DEFAULT_SSL_PORT),
					irc_login_cb_ssl, irc_ssl_connect_failure, gc);
		} else {
			purple_connection_error_reason (gc,
				PURPLE_CONNECTION_ERROR_NO_SSL_SUPPORT,
				_("SSL support unavailable"));
			return;
		}
	}

	if (!irc->gsc) {

		if (purple_proxy_connect(gc, account, irc->server,
				 purple_account_get_int(account, "port", IRC_DEFAULT_PORT),
				 irc_login_cb, gc) == NULL)
		{
			purple_connection_error_reason (gc,
				PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
				_("Unable to connect"));
			return;
		}
	}
}
Example #8
0
gboolean read_cookie(gpointer sodata, PurpleSslConnection * source, gint con)
{
	gchar buf[10240];
	gchar *cur = NULL;
	gchar *end = NULL;
	const gchar *uri = NULL;
	xmlnode *isc, *item;
	gint len, rcv_len;
	PurpleSslConnection *gsc;
	struct fetion_account_data *sip;
	sip = sodata;
	purple_debug_info("fetion:", "read cookie\n");
	gsc = (PurpleSslConnection *) source;
	rcv_len = purple_ssl_read(gsc, buf, 10240);
	if (rcv_len > 0) {
		buf[rcv_len] = '\0';
		purple_debug_info("fetion:", "read_cookie:%s\n", buf);
		cur = strstr(buf, "Cookie: ssic=");
		if (cur != NULL) {
			cur += 13;
			end = strstr(cur, ";");
			sip->ssic = g_strndup(cur, end - cur);
			purple_debug_info("fetion:", "read_cookie:[%s]\n",
					  sip->ssic);
			//      end=purple_url_encode(sip->ssic);
			//      purple_debug_info("fetion:","read_cookie:[%s]\n",end);
		}

		if ((cur = strstr(buf, "\r\n\r\n"))) {
			if (((strncmp(buf, "HTTP/1.1 200 OK\r\n", 17) != 0) &&
			     (strncmp(buf, "HTTP/1.1 100 Continue\r\n", 23) !=
			      0))) {
				purple_connection_error_reason(sip->gc,
							       PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED,
							       _
							       ("Invalid Password or Mobileno"));

				return FALSE;
			}

			cur += 4;
			len = strlen(cur);
			isc = xmlnode_from_str(cur, len);
			g_return_val_if_fail(isc != NULL, FALSE);
			item = xmlnode_get_child(isc, "user");
			g_return_val_if_fail(item != NULL, FALSE);
			uri = xmlnode_get_attrib(item, "uri");
			g_return_val_if_fail(uri != NULL, FALSE);
			sip->uri = g_strdup(uri);
			cur = strstr(uri, "@");
			g_return_val_if_fail(cur != NULL, FALSE);
			*cur = '\0';
			sip->username = g_strdup_printf("%s", uri + 4);
			purple_debug_info("fetion:", "cookie[%s]\n",
					  sip->username);
			purple_timeout_remove(sip->registertimeout);
			srvresolved(sip);

			xmlnode_free(isc);
			purple_ssl_close(gsc);

			return TRUE;

		}

	}
	purple_ssl_close(gsc);
	return FALSE;
}
Example #9
0
void
msn_session_set_error(MsnSession *session, MsnErrorType error,
					  const char *info)
{
	PurpleConnection *gc;
	PurpleConnectionError reason;
	char *msg;

	if (session->destroying)
		return;

	gc = purple_account_get_connection(session->account);

	switch (error)
	{
		case MSN_ERROR_SERVCONN:
			reason = PURPLE_CONNECTION_ERROR_NETWORK_ERROR;
			msg = g_strdup(info);
			break;
		case MSN_ERROR_UNSUPPORTED_PROTOCOL:
			reason = PURPLE_CONNECTION_ERROR_NETWORK_ERROR;
			msg = g_strdup(_("Our protocol is not supported by the "
							 "server"));
			break;
		case MSN_ERROR_HTTP_MALFORMED:
			reason = PURPLE_CONNECTION_ERROR_NETWORK_ERROR;
			msg = g_strdup(_("Error parsing HTTP"));
			break;
		case MSN_ERROR_SIGN_OTHER:
			reason = PURPLE_CONNECTION_ERROR_NAME_IN_USE;
			msg = g_strdup(_("You have signed on from another location"));
			if (!purple_account_get_remember_password(session->account))
				purple_account_set_password(session->account, NULL);
			break;
		case MSN_ERROR_SERV_UNAVAILABLE:
			reason = PURPLE_CONNECTION_ERROR_NETWORK_ERROR;
			msg = g_strdup(_("The MSN servers are temporarily "
							 "unavailable. Please wait and try "
							 "again."));
			break;
		case MSN_ERROR_SERV_DOWN:
			reason = PURPLE_CONNECTION_ERROR_NETWORK_ERROR;
			msg = g_strdup(_("The MSN servers are going down "
							 "temporarily"));
			break;
		case MSN_ERROR_AUTH:
			reason = PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED;
			msg = g_strdup_printf(_("Unable to authenticate: %s"),
								  (info == NULL ) ?
								  _("Unknown error") : info);
			/* Clear the password if it isn't being saved */
			if (!purple_account_get_remember_password(session->account))
				purple_account_set_password(session->account, NULL);
			break;
		case MSN_ERROR_BAD_BLIST:
			reason = PURPLE_CONNECTION_ERROR_NETWORK_ERROR;
			msg = g_strdup(_("Your MSN buddy list is temporarily "
							 "unavailable. Please wait and try "
							 "again."));
			break;
		default:
			reason = PURPLE_CONNECTION_ERROR_NETWORK_ERROR;
			msg = g_strdup(_("Unknown error"));
			break;
	}

	msn_session_disconnect(session);

	purple_connection_error_reason(gc, reason, msg);

	g_free(msg);
}
Example #10
0
static void waprpl_process_incoming_events(PurpleConnection * gc)
{
	whatsapp_connection *wconn = purple_connection_get_protocol_data(gc);
	PurpleAccount *acc = purple_connection_get_account(gc);

	int err;
	do {
		char * reason;
		err = waAPI_geterror(wconn->waAPI, &reason);
		if (err != 0) {
			PurpleConnectionError errcode = PURPLE_CONNECTION_ERROR_OTHER_ERROR;
			if (err == 1)
				errcode = PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED;
			purple_connection_error_reason(gc, errcode, reason);
			g_free(reason);
		}
	} while (err != 0);

	switch (waAPI_loginstatus(wconn->waAPI)) {
	case 0:
		purple_connection_update_progress(gc, "Connecting", 0, 4);
		break;
	case 1:
		purple_connection_update_progress(gc, "Sending authorization", 1, 4);
		break;
	case 2:
		purple_connection_update_progress(gc, "Awaiting response", 2, 4);
		break;
	case 3:
		if (!wconn->connected) {
			purple_connection_update_progress(gc, "Connection established", 3, 4);
			purple_connection_set_state(gc, PURPLE_CONNECTED);

			PurpleAccount *account = purple_connection_get_account(gc);
			PurpleStatus *status = purple_account_get_active_status(account);

			waprpl_insert_contacts(gc);
			waprpl_set_status(account, status);

			wconn->connected = 1;
		}
		break;
	default:
		break;
	};
	
	/* Groups update */
	if (waAPI_getgroupsupdated(wconn->waAPI)) {
		purple_debug_info(WHATSAPP_ID, "Receiving update information from my groups\n");

		/* Delete/update the chats that are in our list */
		PurpleBlistNode *node;

		for (node = purple_blist_get_root(); node; node = purple_blist_node_next(node, FALSE)) {
			if (!PURPLE_BLIST_NODE_IS_CHAT(node))
				continue;

			PurpleChat *ch = PURPLE_CHAT(node);
			if (purple_chat_get_account(ch) != acc)
				continue;

			GHashTable *hasht = purple_chat_get_components(ch);
			char *grid = g_hash_table_lookup(hasht, "id");
			char *glist = waAPI_getgroups(wconn->waAPI);
			gchar **gplist = g_strsplit(glist, ",", 0);

			if (str_array_find(gplist, grid) >= 0) {
				/* The group is in the system, update the fields */
				char *sub, *own;
				waAPI_getgroupinfo(wconn->waAPI, grid, &sub, &own, 0);
				g_hash_table_replace(hasht, g_strdup("subject"), sub);
				g_hash_table_replace(hasht, g_strdup("owner"), own);
				purple_blist_alias_chat(ch, sub);
			} else {
				/* The group was deleted */
				PurpleChat *del = (PurpleChat *) node;
				node = purple_blist_node_next(node, FALSE);
				purple_blist_remove_chat(del);
			}

			g_strfreev(gplist);
			g_free(glist);
		}

		/* Add new groups */
		char *glist = waAPI_getgroups(wconn->waAPI);
		gchar **gplist = g_strsplit(glist, ",", 0);
		gchar **p;

		for (p = gplist; *p; p++) {
			gchar *gpid = *p;
			PurpleChat *ch = blist_find_chat_by_id(gc, gpid);
			if (!ch)
				ch = create_chat_group(gpid, wconn, acc);
			
			/* Now update the open conversation that may exist */
			char *id = g_hash_table_lookup(purple_chat_get_components(ch), "id");
			int prplid = chatid_to_convo(id);
			PurpleConversation *conv = purple_find_chat(gc, prplid);
			char *subject, *owner, *part;
			if (conv && waAPI_getgroupinfo(wconn->waAPI, id, &subject, &owner, &part)) {
				conv_add_participants(conv, part, owner);
			}
		}

		g_strfreev(gplist);
		g_free(glist);
	}

	t_message m;
	while (waAPI_querymsg(wconn->waAPI, &m)) {
		switch (m.type) {
		case 0:
			purple_debug_info(WHATSAPP_ID, "Got chat message from %s: %s\n", m.who, m.message);
			conv_add_message(gc, m.who, m.message, m.author, m.t);
			break;
		case 1: {
			purple_debug_info(WHATSAPP_ID, "Got image from %s: %s\n", m.who, m.message);
			int imgid = purple_imgstore_add_with_id(g_memdup(m.image, m.imagelen), m.imagelen, NULL);
			char *msg = g_strdup_printf("<a href=\"%s\"><img id=\"%u\"></a><br/><a href=\"%s\">%s</a>",
				m.url, imgid, m.url, m.url);
			conv_add_message(gc, m.who, msg, m.author, m.t);
			g_free(msg);
			} break;
		case 2: {
			purple_debug_info(WHATSAPP_ID, "Got geomessage from: %s Coordinates (%f %f)\n", 
				m.who, (float)m.lat, (float)m.lng);
			char * lat = dbl2str(m.lat);
			char * lng = dbl2str(m.lng);
			char *msg = g_strdup_printf("<a href=\"http://openstreetmap.org/?lat=%s&lon=%s&zoom=20\">"
				"http://openstreetmap.org/?lat=%s&lon=%s&zoom=20</a>", 
				lat, lng, lat, lng);
			conv_add_message(gc, m.who, msg, m.author, m.t);
			g_free(msg); g_free(lng); g_free(lat);
			} break;
		case 3: {
			purple_debug_info(WHATSAPP_ID, "Got chat sound from %s: %s\n", m.who, m.url);
			char *msg = g_strdup_printf("<a href=\"%s\">%s</a>", m.url, m.url);
			conv_add_message(gc, m.who, msg, m.author, m.t);
			g_free(msg);
			} break;
		case 4: {
			purple_debug_info(WHATSAPP_ID, "Got chat video from %s: %s\n", m.who, m.url);
			char *msg = g_strdup_printf("<a href=\"%s\">%s</a>", m.url, m.url);
			conv_add_message(gc, m.who, msg, m.author, m.t);
			g_free(msg);
			} break;
		case 5: {
			purple_debug_info(WHATSAPP_ID, "Got phone call from %s\n", m.who);
			conv_add_message(gc, m.who, "[Trying to voice-call you]", m.author, m.t);
			} break;
		default:
			purple_debug_info(WHATSAPP_ID, "Got an unrecognized message!\n");
			break;
		};
		g_free(m.who); g_free(m.author); g_free(m.message);
	}

	while (1) {
		int typer;
		char msgid[128];
		if (!waAPI_queryreceivedmsg(wconn->waAPI, msgid, &typer))
			break;

		purple_debug_info(WHATSAPP_ID, "Received message %s type: %d\n", msgid, typer);
		purple_signal_emit(purple_connection_get_prpl(gc), "whatsapp-message-received", gc, msgid, typer);
	}

	/* Status changes, typing notices and profile pictures. */
	query_status(gc);
	query_typing(gc);
	query_icon(gc);
}
Example #11
0
static void got_form_id_page(FacebookAccount *fba, const gchar *data, gsize data_len, gpointer userdata)
{
	const gchar *start_text = "id=\"post_form_id\" name=\"post_form_id\" value=\"";
	const gchar *dtsg_start = "fb_dtsg:\"";
	const gchar *channel_start = "js\", \"channel";
	const gchar *channel_start2 = "js\",\"channel";
	gchar *post_form_id;
	gchar *channel = NULL;
	gchar *tmp = NULL;
	FacebookFunc callback;
	
	/* NULL data crashes on Windows */
	if (data == NULL)
		data = "(null)";
	
	tmp = g_strstr_len(data, data_len, start_text);
	if (tmp == NULL)
	{
		purple_debug_error("facebook", "couldn't find post_form_id\n");
		purple_debug_info("facebook", "page content: %s\n", data);
		/* Maybe they changed their HTML slightly? */
		purple_connection_error_reason(fba->pc,
				PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED,
				_("Error getting info from Facebook."));
		return;
	}
	tmp += strlen(start_text);
	post_form_id = g_strndup(tmp, strchr(tmp, '"') - tmp);
	
	g_free(fba->post_form_id);
	fba->post_form_id = post_form_id;
	
	tmp = g_strstr_len(data, data_len, dtsg_start);
	if (tmp != NULL)
	{
		tmp += strlen(dtsg_start);
		g_free(fba->dtsg);
		fba->dtsg = g_strndup(tmp, strchr(tmp, '"') - tmp);
	}

	tmp = g_strstr_len(data, data_len, channel_start);
	if (tmp != NULL)
	{
		tmp += 6;
	} else {
		tmp = g_strstr_len(data, data_len, channel_start2);
		if (tmp != NULL)
			tmp += 5;
	}
	if (tmp != NULL)
	{
		channel = g_strndup(tmp, strchr(tmp, '"') - tmp);
		g_free(fba->channel_number);
		fba->channel_number = channel;
	}
	
	if (userdata)
	{
		callback = userdata;
		callback(fba);
	}
}
Example #12
0
void got_reconnect_json(FacebookAccount *fba, const gchar *data, gsize data_len, gpointer userdata)
{
	JsonParser *parser;
	JsonObject *objnode;
	gchar *error_message;

	parser = fb_get_parser(data, data_len);

	if (!parser) {
		purple_debug_error("facebook", "couldn't parse reconnect data\n");
		purple_debug_info("facebook", "page content: %s\n", data);
		purple_connection_error_reason(fba->pc,
				PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
				_("Chat service currently unavailable"));
		return;
	}

	objnode = fb_get_json_object(parser, &error_message);
	
	if (error_message != NULL)
	{
		if (json_node_get_int(json_object_get_member(objnode, "error")) == 1356007)
		{
			//There'll normally be an error message if chat is down for maintenance
			purple_connection_error_reason(fba->pc,
				PURPLE_CONNECTION_ERROR_AUTHENTICATION_IMPOSSIBLE,
				error_message);
			g_free(error_message);
			json_parser_free(parser);
			return;
		}
	}

	JsonObject *payload = json_node_get_object(json_object_get_member(objnode, "payload"));
	
	/* eg {"host":"channel01"} */
	const gchar *new_channel_host = json_node_get_string(json_object_get_member(payload, "host"));

	if (new_channel_host == NULL)
	{
		purple_debug_error("facebook", "couldn't find new channel number\n");
		purple_debug_info("facebook", "page content: %s\n", data);
		purple_connection_error_reason(fba->pc,
				PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
				_("Error fetching channel; did you log in elsewhere?"));
		json_parser_free(parser);
		return;
	}
	
	g_free(fba->channel_number);
	fba->channel_number = g_strdup(new_channel_host);
	
	gint new_seq = json_node_get_int(json_object_get_member(payload, "seq"));
	fba->message_fetch_sequence = new_seq;
	
	/*
	 * Now that we have a channel number we can start looping and
	 * waiting for messages
	 */
	fb_get_new_messages(fba);
	json_parser_free(parser);
}
Example #13
0
/**
 * This is where we do a bit more than merely prompt the user.
 * Now we have some real data to tell us the state of their requested username
 * \persistr\\cmd\257\dsn\5\uid\204084363\lid\7\rid\367\body\UserName=TheAlbinoRhino1\final\
 */
static void msim_username_is_available_cb(MsimSession *session, const MsimMessage *userinfo, gpointer data)
{
    MsimMessage *msg;
    gchar *username;
    MsimMessage *body;
    gint userid;

    purple_debug_info("msim_username_is_available_cb", "Look up username callback made\n");

    msg = (MsimMessage *)data;
    g_return_if_fail(MSIM_SESSION_VALID(session));
    g_return_if_fail(msg != NULL);

    username = msim_msg_get_string(msg, "user");
    body = msim_msg_get_dictionary(userinfo, "body");

    if (!body) {
        purple_debug_info("msim_username_is_available_cb", "No body for %s?!\n", username);
        purple_connection_error_reason(session->gc, PURPLE_CONNECTION_ERROR_OTHER_ERROR,
                                       "An error occurred while trying to set the username.\n"
                                       "Please try again, or visit http://editprofile.myspace.com/index.cfm?"
                                       "fuseaction=profile.username to set your username.");
        return;
    }

    userid = msim_msg_get_integer(body, "UserID");

    purple_debug_info("msim_username_is_available_cb", "Returned username is %s and userid is %d\n", username, userid);
    msim_msg_free(body);
    msim_msg_free(msg);

    /* The response for a free username will ONLY have the UserName in it..
     * thus making UserID return 0 when we msg_get_integer it */
    if (userid == 0) {
        /* This username is currently unused */
        purple_debug_info("msim_username_is_available_cb", "Username available. Prompting to Confirm.\n");
        msim_username_to_set = g_strdup(username);
        g_free(username);
        purple_request_yes_no(session->gc,
                              _("MySpaceIM - Username Available"),
                              _("This username is available. Would you like to set it?"),
                              _("ONCE SET, THIS CANNOT BE CHANGED!"),
                              0,
                              session->account,
                              NULL,
                              NULL,
                              session->gc,
                              G_CALLBACK(msim_set_username_confirmed_cb),
                              G_CALLBACK(msim_do_not_set_username_cb));
    } else {
        /* Looks like its in use or we have an invalid response */
        purple_debug_info("msim_username_is_available_cb", "Username unavaiable. Prompting for new entry.\n");
        purple_request_input(session->gc, _("MySpaceIM - Please Set a Username"),
                             _("This username is unavailable."),
                             _("Please try another username:"******"", FALSE, FALSE, NULL,
                             _("OK"), G_CALLBACK(msim_check_username_availability_cb),
                             _("Cancel"), G_CALLBACK(msim_do_not_set_username_cb),
                             session->account,
                             NULL,
                             NULL,
                             session->gc);
    }
}
static void
pb_got_everything(PushBulletAccount *pba, JsonNode *node, gpointer user_data)
{
	JsonObject *rootobj = json_node_get_object(node);
	JsonArray *devices = json_object_has_member(rootobj, "devices") ? json_object_get_array_member(rootobj, "devices") : NULL;
	JsonArray *pushes = json_object_has_member(rootobj, "pushes") ? json_object_get_array_member(rootobj, "pushes") : NULL;
	JsonArray *contacts = json_object_has_member(rootobj, "contacts") ? json_object_get_array_member(rootobj, "contacts") : NULL;
	JsonArray *chats = json_object_has_member(rootobj, "chats") ? json_object_get_array_member(rootobj, "chats") : NULL;
	JsonArray *texts = json_object_has_member(rootobj, "texts") ? json_object_get_array_member(rootobj, "texts") : NULL;
	gint i;
	guint len;
	PurpleGroup *pbgroup;
	
	pbgroup = purple_find_group("PushBullet");
	if (!pbgroup)
	{
		pbgroup = purple_group_new("PushBullet");
		purple_blist_add_group(pbgroup, NULL);
	}
	
	if (json_object_has_member(rootobj, "error")) {
		JsonObject *error = json_object_get_object_member(rootobj, "error");
		const gchar *type = json_object_get_string_member(error, "type");
		const gchar *message = json_object_get_string_member(error, "message");
		
		//TODO check type
		purple_connection_error_reason(pba->pc, PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED, message);
		return;
	}
	
	if (devices != NULL) {
		for(i = 0, len = json_array_get_length(devices); i < len; i++) {
			JsonObject *device = json_array_get_object_element(devices, i);
			
			if (pba->main_sms_device == NULL && json_object_get_boolean_member(device, "has_sms")) {
				pba->main_sms_device = g_strdup(json_object_get_string_member(device, "iden"));
				purple_account_set_string(pba->account, "main_sms_device", pba->main_sms_device);
				
				pb_get_phonebook(pba, pba->main_sms_device);
				
				if (!pba->websocket) {
					pb_start_polling(pba);
				}
				
				break; //TODO handle more than one
			}
		}
	}
	
	if (pushes != NULL) {
		gint last_message_timestamp = purple_account_get_int(pba->account, "last_message_timestamp", 0);
		for(i = json_array_get_length(pushes); i > 0; i--) {
			JsonObject *push = json_array_get_object_element(pushes, i - 1);
			const gchar *type = json_object_get_string_member(push, "type");
			gdouble modified;
			time_t timestamp;
			gboolean dismissed;
			
			if (!type)
				continue;
			
			modified = json_object_get_double_member(push, "modified");
			timestamp = (time_t) modified;
			dismissed = json_object_get_boolean_member(push, "dismissed");
			
			if (timestamp <= last_message_timestamp || dismissed) {
				continue;
			}
			
			// {"active":true,"iden":"uffvytgsjApuAUIFRk","created":1.438895081423904e+09,"modified":1.438895081432786e+09,"type":"file","dismissed":false,"guid":"153b70f0-f7a6-4db9-a6f4-28b99fa416f1","direction":"self","sender_iden":"uffvytg","sender_email":"*****@*****.**","sender_email_normalized":"*****@*****.**","sender_name":"Eion Robb","receiver_iden":"uffvytg","receiver_email":"*****@*****.**","receiver_email_normalized":"*****@*****.**","target_device_iden":"uffvytgsjz7O3P0Jl6","source_device_iden":"uffvytgsjAoIRwhIL6","file_name":"IMG_20150807_084618.jpg","file_type":"image/jpeg","file_url":"https://dl.pushbulletusercontent.com/FHOZdyzfvnoYZY0DP6oK1rGKiJpWCPc0/IMG_20150807_084618.jpg","image_width":4128,"image_height":2322,"image_url":"https://lh3.googleusercontent.com/WY5TK7h3mzD32qMcnxtqt-4PrYcWW1uWDHnRW2x1oJK8mnYk2v4HbZrRjIQkiYdxMKQSdNI8GGPqfO6s6tEyuRVLzeA"}
			
			if (purple_strequal(type, "note") || purple_strequal(type, "link") || purple_strequal(type, "file")) {
				const gchar *from = json_object_get_string_member(push, "sender_email_normalized");
				const gchar *body = json_object_get_string_member(push, "body");
				const gchar *direction = json_object_get_string_member(push, "direction");
				gchar *body_html;
				
				if (from == NULL) {
					if (!json_object_has_member(push, "sender_name")) {
						purple_debug_error("pushbullet", "no sender name/email\n");
						continue;
					}
					from = json_object_get_string_member(push, "sender_name");
				}
				
				if (body && *body) {
					body_html = purple_strdup_withhtml(body);
				} else {
					const gchar *title = json_object_get_string_member(push, "title");
					if (title && *title) {
						body_html = purple_strdup_withhtml(title);
					} else {
						body_html = "Message";
					}
				}
				
				if (json_object_has_member(push, "url")) {
					gchar *body_with_link = g_strconcat("<a href=\"", json_object_get_string_member(push, "url"), "\">", body_html, "</a>", NULL);
					g_free(body_html);
					body_html = body_with_link;
					
				} else if (json_object_has_member(push, "image_url")) {
					const gchar *image_url = json_object_get_string_member(push, "image_url");
					PurpleConversation *conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, from, pba->account);
					
					if (conv == NULL)
					{
						conv = purple_conversation_new(PURPLE_CONV_TYPE_IM, pba->account, from);
					}
					pb_download_image_to_conv(image_url, conv);
					
				} else if (json_object_has_member(push, "file_url")) {
					gchar *body_with_link;
					const gchar *file_name = json_object_get_string_member(push, "file_name");
					
					if (file_name && *file_name) {
						g_free(body_html);
						body_html = purple_strdup_withhtml(file_name);
					}
					
					body_with_link= g_strconcat("<a href=\"", json_object_get_string_member(push, "file_url"), "\">", json_object_get_string_member(push, "file_name"), "</a>", NULL);
					g_free(body_html);
					body_html = body_with_link;
				}
				
				if (direction[0] != 'o') {
					serv_got_im(pba->pc, from, body_html, PURPLE_MESSAGE_RECV, timestamp);
				} else {
					const gchar *guid = json_object_get_string_member(push, "guid");
					from = json_object_get_string_member(push, "receiver_email_normalized");
					
					if (!guid || !g_hash_table_remove(pba->sent_messages_hash, guid)) {
						PurpleConversation *conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, from, pba->account);
						if (conv == NULL)
						{
							conv = purple_conversation_new(PURPLE_CONV_TYPE_IM, pba->account, from);
						}
						purple_conversation_write(conv, from, body_html, PURPLE_MESSAGE_SEND, timestamp);
					}
				}
				
				g_free(body_html);
			}
				
			purple_account_set_int(pba->account, "last_message_timestamp", MAX(purple_account_get_int(pba->account, "last_message_timestamp", 0), timestamp));
		}
	}
	
	if (contacts != NULL) {
		for(i = 0, len = json_array_get_length(contacts); i < len; i++) {
			JsonObject *contact = json_array_get_object_element(contacts, i);
			const gchar *email = json_object_get_string_member(contact, "email_normalized");
			const gchar *name = json_object_get_string_member(contact, "name");
			const gchar *image_url = json_object_get_string_member(contact, "image_url");
			
			PurpleBuddy *buddy = purple_find_buddy(pba->account, email);
			if (buddy == NULL)
			{
				buddy = purple_buddy_new(pba->account, email, name);
				purple_blist_add_buddy(buddy, NULL, pbgroup, NULL);
			}
			purple_prpl_got_user_status(pba->account, email, purple_primitive_get_id_from_type(PURPLE_STATUS_AVAILABLE), NULL);
		}
	}
	
	if (chats != NULL) {
		for(i = 0, len = json_array_get_length(chats); i < len; i++) {
			JsonObject *chat = json_array_get_object_element(chats, i);
			JsonObject *contact = json_object_get_object_member(chat, "with");
			const gchar *email = json_object_get_string_member(contact, "email_normalized");
			const gchar *name = json_object_get_string_member(contact, "name");
			const gchar *image_url = json_object_get_string_member(contact, "image_url");
			
			PurpleBuddy *buddy = purple_find_buddy(pba->account, email);
			if (buddy == NULL)
			{
				buddy = purple_buddy_new(pba->account, email, name);
				purple_blist_add_buddy(buddy, NULL, pbgroup, NULL);
			}
			purple_prpl_got_user_status(pba->account, email, purple_primitive_get_id_from_type(PURPLE_STATUS_AVAILABLE), NULL);
		}
	}
	
	if (texts != NULL) {
		for(i = 0, len = json_array_get_length(texts); i < len; i++) {
			JsonObject *text = json_array_get_object_element(texts, i);
		}
	}
}
Example #15
0
static void boot_response_cb(PurpleBOSHConnection *conn, xmlnode *node) {
	JabberStream *js = conn->js;
	const char *sid, *version;
	const char *inactivity, *requests;
	xmlnode *packet;

	g_return_if_fail(node != NULL);
	if (jabber_bosh_connection_error_check(conn, node))
		return;

	sid = xmlnode_get_attrib(node, "sid");
	version = xmlnode_get_attrib(node, "ver");

	inactivity = xmlnode_get_attrib(node, "inactivity");
	requests = xmlnode_get_attrib(node, "requests");

	if (sid) {
		conn->sid = g_strdup(sid);
	} else {
		purple_connection_error_reason(js->gc,
		        PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
		        _("No session ID given"));
		return;
	}

	if (version) {
		const char *dot = strstr(version, ".");
		int major, minor = 0;

		purple_debug_info("jabber", "BOSH connection manager version %s\n", version);

		major = atoi(version);
		if (dot)
			minor = atoi(dot + 1);

		if (major != 1 || minor < 6) {
			purple_connection_error_reason(js->gc,
			        PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
			        _("Unsupported version of BOSH protocol"));
			return;
		}
	} else {
		purple_debug_info("jabber", "Missing version in BOSH initiation\n");
	}

	if (inactivity) {
		conn->max_inactivity = atoi(inactivity);
		if (conn->max_inactivity <= 5) {
			purple_debug_warning("jabber", "Ignoring bogusly small inactivity: %s\n",
			                     inactivity);
			conn->max_inactivity = 0;
		} else {
			/* TODO: Integrate this with jabber.c keepalive checks... */
			/* TODO: Can this check fail? It shouldn't */
			if (conn->inactivity_timer == 0) {
				purple_debug_misc("jabber", "Starting BOSH inactivity timer "
						"for %d secs (compensating for rounding)\n",
						conn->max_inactivity - 5);
				restart_inactivity_timer(conn);
			}
		}
	}

	if (requests)
		conn->max_requests = atoi(requests);

	jabber_stream_set_state(js, JABBER_STREAM_AUTHENTICATING);

	/* FIXME: Depending on receiving features might break with some hosts */
	packet = xmlnode_get_child(node, "features");
	conn->state = BOSH_CONN_ONLINE;
	conn->receive_cb = jabber_bosh_connection_received;
	jabber_stream_features_parse(js, packet);
}
Example #16
0
void
msn_session_set_error (MsnSession *session,
                       MsnErrorType error,
                       const char *info)
{
    PurpleAccount *account;
    PurpleConnection *connection;
    char *msg;

    account = msn_session_get_user_data (session);
    connection = purple_account_get_connection (account);

    switch (error)
    {
        case MSN_ERROR_SERVCONN:
            msg = g_strdup (info);
            break;
        case MSN_ERROR_UNSUPPORTED_PROTOCOL:
            msg = g_strdup (_("Our protocol is not supported by the "
                              "server."));
            break;
        case MSN_ERROR_HTTP_MALFORMED:
            msg = g_strdup (_("Error parsing HTTP."));
            break;
        case MSN_ERROR_SIGN_OTHER:
            msg = g_strdup (_("You have signed on from another location."));
            break;
        case MSN_ERROR_SERV_UNAVAILABLE:
            msg = g_strdup (_("The MSN servers are temporarily "
                              "unavailable. Please wait and try "
                              "again."));
            break;
        case MSN_ERROR_SERV_DOWN:
            msg = g_strdup (_("The MSN servers are going down "
                              "temporarily."));
            break;
        case MSN_ERROR_AUTH:
            msg = g_strdup_printf (_("Unable to authenticate: %s"),
                                   info ? info : _("Unknown error"));
            break;
        case MSN_ERROR_BAD_BLIST:
            msg = g_strdup (_("Your MSN buddy list is temporarily "
                              "unavailable. Please wait and try "
                              "again."));
            break;
        default:
            msg = g_strdup (_("Unknown error."));
            break;
    }

    msn_session_disconnect (session);

#if PURPLE_VERSION_CHECK(2,3,0)
    purple_connection_error_reason (connection,
            msn_error_to_purple_reason(error), msg);
#else
    purple_connection_error (connection, msg);
#endif

    g_free (msg);
}
Example #17
0
static gboolean parse_start_oscar_session_response(PurpleConnection *gc, const gchar *response, gsize response_len, char **host, unsigned short *port, char **cookie, char **tls_certname)
{
	xmlnode *response_node, *tmp_node, *data_node;
	xmlnode *host_node = NULL, *port_node = NULL, *cookie_node = NULL, *tls_node = NULL;
	gboolean use_tls;
	char *tmp;
	guint code;

	use_tls = purple_account_get_bool(purple_connection_get_account(gc), "use_ssl", OSCAR_DEFAULT_USE_SSL);

	/* Parse the response as XML */
	response_node = xmlnode_from_str(response, response_len);
	if (response_node == NULL)
	{
		char *msg;
		purple_debug_error("oscar", "startOSCARSession could not parse "
				"response as XML: %s\n", response);
		/* Note to translators: %s in this string is a URL */
		msg = g_strdup_printf(_("Received unexpected response from %s"),
				URL_START_OSCAR_SESSION);
		purple_connection_error_reason(gc,
				PURPLE_CONNECTION_ERROR_NETWORK_ERROR, msg);
		g_free(msg);
		return FALSE;
	}

	/* Grab the necessary XML nodes */
	tmp_node = xmlnode_get_child(response_node, "statusCode");
	data_node = xmlnode_get_child(response_node, "data");
	if (data_node != NULL) {
		host_node = xmlnode_get_child(data_node, "host");
		port_node = xmlnode_get_child(data_node, "port");
		cookie_node = xmlnode_get_child(data_node, "cookie");
		tls_node = xmlnode_get_child(data_node, "tlsCertName");
	}

	/* Make sure we have a status code */
	if (tmp_node == NULL || (tmp = xmlnode_get_data_unescaped(tmp_node)) == NULL) {
		char *msg;
		purple_debug_error("oscar", "startOSCARSession response was "
				"missing statusCode: %s\n", response);
		msg = g_strdup_printf(_("Received unexpected response from %s"),
				URL_START_OSCAR_SESSION);
		purple_connection_error_reason(gc,
				PURPLE_CONNECTION_ERROR_NETWORK_ERROR, msg);
		g_free(msg);
		xmlnode_free(response_node);
		return FALSE;
	}

	/* Make sure the status code was 200 */
	code = atoi(tmp);
	if (code != 200)
	{
		purple_debug_error("oscar", "startOSCARSession response statusCode "
				"was %s: %s\n", tmp, response);

		if (code == 401 || code == 607)
			purple_connection_error_reason(gc,
					PURPLE_CONNECTION_ERROR_OTHER_ERROR,
					_("You have been connecting and disconnecting too "
					  "frequently. Wait ten minutes and try again. If "
					  "you continue to try, you will need to wait even "
					  "longer."));
		else {
			char *msg;
			msg = g_strdup_printf(_("Received unexpected response from %s"),
					URL_START_OSCAR_SESSION);
			purple_connection_error_reason(gc,
					PURPLE_CONNECTION_ERROR_OTHER_ERROR, msg);
			g_free(msg);
		}

		g_free(tmp);
		xmlnode_free(response_node);
		return FALSE;
	}
	g_free(tmp);

	/* Make sure we have everything else */
	if (data_node == NULL || host_node == NULL ||
		port_node == NULL || cookie_node == NULL ||
		(use_tls && tls_node == NULL))
	{
		char *msg;
		purple_debug_error("oscar", "startOSCARSession response was missing "
				"something: %s\n", response);
		msg = g_strdup_printf(_("Received unexpected response from %s"),
				URL_START_OSCAR_SESSION);
		purple_connection_error_reason(gc,
				PURPLE_CONNECTION_ERROR_NETWORK_ERROR, msg);
		g_free(msg);
		xmlnode_free(response_node);
		return FALSE;
	}

	/* Extract data from the XML */
	*host = xmlnode_get_data_unescaped(host_node);
	tmp = xmlnode_get_data_unescaped(port_node);
	*cookie = xmlnode_get_data_unescaped(cookie_node);

	if (use_tls)
		*tls_certname = xmlnode_get_data_unescaped(tls_node);

	if (*host == NULL || **host == '\0' || tmp == NULL || *tmp == '\0' || *cookie == NULL || **cookie == '\0' ||
			(use_tls && (*tls_certname == NULL || **tls_certname == '\0')))
	{
		char *msg;
		purple_debug_error("oscar", "startOSCARSession response was missing "
				"something: %s\n", response);
		msg = g_strdup_printf(_("Received unexpected response from %s"),
				URL_START_OSCAR_SESSION);
		purple_connection_error_reason(gc,
				PURPLE_CONNECTION_ERROR_NETWORK_ERROR, msg);
		g_free(msg);
		g_free(*host);
		g_free(tmp);
		g_free(*cookie);
		xmlnode_free(response_node);
		return FALSE;
	}

	*port = atoi(tmp);
	g_free(tmp);

	return TRUE;
}
Example #18
0
void RetriveSysCfg_cb(gpointer sodata, gint source, const gchar * error_message)
{
	gchar buf[10240];
	gchar *cur, *tail;
	gchar *msg_server, *ssic_server, *por_server, *upload_server;
	gchar *cfg_size = NULL;
	gchar *cfg_filename = NULL;
	struct fetion_account_data *sip = sodata;
	gint len, rcv_len;
	xmlnode *root, *son_node, *item;
	memset(buf, 0, 10240);
	rcv_len = read(source, buf, 10240);
	if (rcv_len > 0) {
		if ((cur = strstr(buf, "\r\n\r\n"))) {
			if (strncmp(buf, "HTTP/1.1 200 OK\r\n", 17) != 0)
				purple_connection_error_reason(sip->gc,
							       PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED,
							       _
							       ("Invalid Password or Mobileno"));
			cfg_size = get_token(buf, "Content-Length: ", "\r\n");
			if (cfg_size == NULL)
				return;
			cur += 4;
			sip->SysCfg.size = atoi(cfg_size);
			sip->SysCfg.buf = g_malloc(sip->SysCfg.size);
			len = rcv_len - (cur - buf);
			sip->SysCfg.rcv_len = len;
			memcpy((sip->SysCfg.buf), cur, len);

		} else {
			cur = sip->SysCfg.buf + sip->SysCfg.rcv_len;
			if ((sip->SysCfg.rcv_len) + rcv_len >
			    (sip->SysCfg.size))
				memcpy(cur, buf,
				       (sip->SysCfg.size) -
				       (sip->SysCfg.rcv_len));
			else
				memcpy(cur, buf, rcv_len);
			sip->SysCfg.rcv_len += rcv_len;
		}
	} else {
		purple_input_remove(sip->SysCfg.inpa);
		if (sip->mobileno != NULL)
			cfg_filename =
			    g_strdup_printf("%s-SysCfg.xml", sip->mobileno);
		else if (sip->username != NULL)
			cfg_filename =
			    g_strdup_printf("%s-SysCfg.xml", sip->username);
		else
			cfg_filename = g_strdup_printf("SysCfg.xml");

		root = xmlnode_from_str(sip->SysCfg.buf, sip->SysCfg.size);
		g_return_if_fail(root != NULL);
		son_node = xmlnode_get_child(root, "servers");
		if (son_node == NULL) {
			LoginToSsiPortal(sip);	//fixme
			return;
		}
		purple_debug_info("fetion", "systemconfig:after servers[%s]",
				  sip->SysCfg.buf);
		item = xmlnode_get_child(son_node, "sipc-proxy");
		g_return_if_fail(item != NULL);
		msg_server = g_strdup(xmlnode_get_data(item));
		item = xmlnode_get_child(son_node, "ssi-app-sign-in");
		g_return_if_fail(item != NULL);
		ssic_server = g_strdup(xmlnode_get_data(item));

		item =
		    xmlnode_get_child(root, "http-applications/get-portrait");
		g_return_if_fail(item != NULL);
		por_server = g_strdup(xmlnode_get_data(item));

		item =
		    xmlnode_get_child(root, "http-applications/set-portrait");
		g_return_if_fail(item != NULL);
		upload_server = g_strdup(xmlnode_get_data(item));

		cur = strstr(msg_server, ":");
		*cur = '\0';
		cur++;
		sip->MsgServer = g_strdup(msg_server);
		sip->MsgPort = atoi(cur);

		cur = strstr(ssic_server, "/ssiportal");
		*cur = '\0';
		cur = ssic_server + 8;
		sip->SsicServer = g_strdup(cur);

		cur = strstr(por_server, "/HDS");
		*cur = '\0';
		tail = cur + 1;
		cur = por_server + 7;
		sip->PortraitServer = g_strdup(cur);
		cur = strstr(por_server, "/");
		*cur = '\0';
		sip->PortraitPrefix = g_strdup(tail);

		cur = strstr(upload_server, "/HDS");
		*cur = '\0';
		tail = cur + 1;
		cur = upload_server + 7;
		sip->UploadServer = g_strdup(cur);
		cur = strstr(upload_server, "/");
		*cur = '\0';
		sip->UploadPrefix = g_strdup(tail);

		LoginToSsiPortal(sip);

		purple_util_write_data_to_file(cfg_filename, sip->SysCfg.buf,
					       sip->SysCfg.size);

		g_free(msg_server);
		g_free(ssic_server);
		g_free(por_server);
		g_free(upload_server);

	}

}
Example #19
0
/**
 * This function parses the given response from a clientLogin request
 * and extracts the useful information.
 *
 * @param gc           The PurpleConnection.  If the response data does
 *                     not indicate then purple_connection_error_reason()
 *                     will be called to close this connection.
 * @param response     The response data from the clientLogin request.
 * @param response_len The length of the above response, or -1 if
 *                     @response is NUL terminated.
 * @param token        If parsing was successful then this will be set to
 *                     a newly allocated string containing the token.  The
 *                     caller should g_free this string when it is finished
 *                     with it.  On failure this value will be untouched.
 * @param secret       If parsing was successful then this will be set to
 *                     a newly allocated string containing the secret.  The
 *                     caller should g_free this string when it is finished
 *                     with it.  On failure this value will be untouched.
 * @param hosttime     If parsing was successful then this will be set to
 *                     the time on the OpenAuth Server in seconds since the
 *                     Unix epoch.  On failure this value will be untouched.
 *
 * @return TRUE if the request was successful and we were able to
 *         extract all info we need.  Otherwise FALSE.
 */
static gboolean parse_client_login_response(PurpleConnection *gc, const gchar *response, gsize response_len, char **token, char **secret, time_t *hosttime)
{
	xmlnode *response_node, *tmp_node, *data_node;
	xmlnode *secret_node = NULL, *hosttime_node = NULL, *token_node = NULL, *tokena_node = NULL;
	char *tmp;

	/* Parse the response as XML */
	response_node = xmlnode_from_str(response, response_len);
	if (response_node == NULL)
	{
		char *msg;
		purple_debug_error("oscar", "clientLogin could not parse "
				"response as XML: %s\n", response);
		msg = g_strdup_printf(_("Received unexpected response from %s"),
				URL_CLIENT_LOGIN);
		purple_connection_error_reason(gc,
				PURPLE_CONNECTION_ERROR_NETWORK_ERROR, msg);
		g_free(msg);
		return FALSE;
	}

	/* Grab the necessary XML nodes */
	tmp_node = xmlnode_get_child(response_node, "statusCode");
	data_node = xmlnode_get_child(response_node, "data");
	if (data_node != NULL) {
		secret_node = xmlnode_get_child(data_node, "sessionSecret");
		hosttime_node = xmlnode_get_child(data_node, "hostTime");
		token_node = xmlnode_get_child(data_node, "token");
		if (token_node != NULL)
			tokena_node = xmlnode_get_child(token_node, "a");
	}

	/* Make sure we have a status code */
	if (tmp_node == NULL || (tmp = xmlnode_get_data_unescaped(tmp_node)) == NULL) {
		char *msg;
		purple_debug_error("oscar", "clientLogin response was "
				"missing statusCode: %s\n", response);
		msg = g_strdup_printf(_("Received unexpected response from %s"),
				URL_CLIENT_LOGIN);
		purple_connection_error_reason(gc,
				PURPLE_CONNECTION_ERROR_NETWORK_ERROR, msg);
		g_free(msg);
		xmlnode_free(response_node);
		return FALSE;
	}

	/* Make sure the status code was 200 */
	if (strcmp(tmp, "200") != 0)
	{
		int status_code, status_detail_code = 0;

		status_code = atoi(tmp);
		g_free(tmp);
		tmp_node = xmlnode_get_child(response_node, "statusDetailCode");
		if (tmp_node != NULL && (tmp = xmlnode_get_data_unescaped(tmp_node)) != NULL) {
			status_detail_code = atoi(tmp);
			g_free(tmp);
		}

		purple_debug_error("oscar", "clientLogin response statusCode "
				"was %d (%d): %s\n", status_code, status_detail_code, response);

		if (status_code == 330 && status_detail_code == 3011) {
			purple_connection_error_reason(gc,
					PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED,
					_("Incorrect password"));
		} else if (status_code == 401 && status_detail_code == 3019) {
			purple_connection_error_reason(gc,
					PURPLE_CONNECTION_ERROR_OTHER_ERROR,
					_("AOL does not allow your screen name to authenticate here"));
		} else {
			char *msg;
			msg = g_strdup_printf(_("Received unexpected response from %s"),
					URL_CLIENT_LOGIN);
			purple_connection_error_reason(gc,
					PURPLE_CONNECTION_ERROR_OTHER_ERROR, msg);
			g_free(msg);
		}

		xmlnode_free(response_node);
		return FALSE;
	}
	g_free(tmp);

	/* Make sure we have everything else */
	if (data_node == NULL || secret_node == NULL ||
		token_node == NULL || tokena_node == NULL)
	{
		char *msg;
		purple_debug_error("oscar", "clientLogin response was missing "
				"something: %s\n", response);
		msg = g_strdup_printf(_("Received unexpected response from %s"),
				URL_CLIENT_LOGIN);
		purple_connection_error_reason(gc,
				PURPLE_CONNECTION_ERROR_NETWORK_ERROR, msg);
		g_free(msg);
		xmlnode_free(response_node);
		return FALSE;
	}

	/* Extract data from the XML */
	*token = xmlnode_get_data_unescaped(tokena_node);
	*secret = xmlnode_get_data_unescaped(secret_node);
	tmp = xmlnode_get_data_unescaped(hosttime_node);
	if (*token == NULL || **token == '\0' || *secret == NULL || **secret == '\0' || tmp == NULL || *tmp == '\0')
	{
		char *msg;
		purple_debug_error("oscar", "clientLogin response was missing "
				"something: %s\n", response);
		msg = g_strdup_printf(_("Received unexpected response from %s"),
				URL_CLIENT_LOGIN);
		purple_connection_error_reason(gc,
				PURPLE_CONNECTION_ERROR_NETWORK_ERROR, msg);
		g_free(msg);
		g_free(*token);
		g_free(*secret);
		g_free(tmp);
		xmlnode_free(response_node);
		return FALSE;
	}

	*hosttime = strtol(tmp, NULL, 10);
	g_free(tmp);

	xmlnode_free(response_node);

	return TRUE;
}
Example #20
0
static void fb_login_cb(FacebookAccount *fba, gchar *response, gsize len,
		gpointer userdata)
{
	gchar *user_cookie;
	const gchar *persist_data_start;
	gchar *persist_data;
	const gchar *session_start;
	gchar *session;
	gchar *captcha_url;
	const gchar *extra_challenge_params;
	gchar *extra_challenge;
	if (len && g_strstr_len(response, len, "captcha"))
	{
		purple_debug_info("facebook", "captcha page: %s\n", response);

		purple_connection_update_progress(fba->pc, _("Handling Captcha"), 2, 4);
		
		persist_data_start = "<input type=\"hidden\" id=\"captcha_persist_data\" name=\"captcha_persist_data\" value=\"";
		persist_data = g_strstr_len(response, len, persist_data_start);
		if (persist_data)
		{
			persist_data += strlen(persist_data_start);
			fba->persist_data = g_strndup(persist_data, strchr(persist_data, '"') - persist_data);
		}
		
		session_start = "<input type=\"hidden\" id=\"captcha_session\" name=\"captcha_session\" value=\"";
		session = g_strstr_len(response, len, session_start);
		if (session)
		{
			session += strlen(session_start);
			fba->captcha_session = g_strndup(session, strchr(session, '"') - session);
		}
		
		
		extra_challenge_params = "<input type=\"hidden\" id=\"extra_challenge_params\" name=\"extra_challenge_params\" value=\"";
		extra_challenge = g_strstr_len(response, len, extra_challenge_params);
		if (extra_challenge)
		{
			extra_challenge += strlen(extra_challenge_params);
			fba->extra_challenge = g_strndup(extra_challenge, strchr(extra_challenge, '"') - extra_challenge);
			extra_challenge = purple_unescape_html(fba->extra_challenge);
			g_free(fba->extra_challenge);
			fba->extra_challenge = extra_challenge;
		}
		
		if (!fba->extra_challenge || !fba->persist_data || !fba->captcha_session)
		{
			purple_debug_info("facebook", "captcha response: %s\n", response);
			g_free(fba->extra_challenge);
			g_free(fba->persist_data);
			g_free(fba->captcha_session);
			fba->extra_challenge = NULL;
			fba->persist_data = NULL;
			fba->captcha_session = NULL;
			purple_connection_error_reason(fba->pc, PURPLE_CONNECTION_ERROR_OTHER_ERROR,
				"Could not authenticate captcha.  Logging into the Facebook website may fix this.");
			return;
		}
		
		captcha_url = g_strdup_printf("/challenge?k=" FACEBOOK_CAPTCHA_SITE "&%s",
				fba->extra_challenge?fba->extra_challenge:"");
		
		fb_post_or_get(fba, FB_METHOD_GET | FB_METHOD_SSL, "api-secure.recaptcha.net",
			captcha_url, NULL, fb_login_captcha_cb, NULL, FALSE);
		
		g_free(captcha_url);
		
		return;
	}

	purple_connection_update_progress(fba->pc, _("Authenticating"), 2, 3);

	/* Look for our uid */
	user_cookie = g_hash_table_lookup(fba->cookie_table, "c_user");
	if (user_cookie == NULL) {
		/*
		 * Server didn't set the c_user cookie, so we must have given
		 * them a bad username or password
		 */
		purple_connection_error_reason(fba->pc,
				PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED,
				_("Incorrect username or password."));
		return;
	}
	fba->uid = atoll(user_cookie);
	purple_debug_info("facebook", "uid %" G_GINT64_FORMAT "\n", fba->uid);

	/* ok, we're logged in now! */
	purple_connection_set_state(fba->pc, PURPLE_CONNECTED);

	/* This will kick off our long-poll message retrieval loop */
	fb_get_post_form_id(fba);
	fb_check_friend_requests(fba);

	/* periodically check for people adding you to their facebook friend list */
	fba->friend_request_timer = purple_timeout_add_seconds(60 * 5,
			fb_check_friend_requests, fba);

	/* periodically check for new notifications */
	fba->notifications_timer = purple_timeout_add_seconds(60,
			(GSourceFunc)fb_get_notifications_feed, fba);

	/* Periodically check for new messages.  NOTE: This MUST exist,
	 * regardless of other other mechanisms for checking messages.  This
	 * is because the code needs a failsafe checker in case other one of
	 * the other retrieval mechanisms dies due to a bad request, etc.
	 * Without such a failsafe, a user will receive no messages, which is
	 * one of hardest bugs to debug and get reports about.  Hence, the
	 * importance of this loop.
	 * That said, there is room for tweaking this loop and possibly even
	 * setting it such that it is the primary or only message checker.
	 * The key is that the method must NEVER die until logout.
	 */
	fba->perpetual_messages_timer = purple_timeout_add_seconds(15,
			(GSourceFunc)fb_get_messages_failsafe, fba);

	/* init blist subsystem */
	fb_blist_init(fba);

	/* init conversation subsystem */
	fb_conversation_init(fba);
}
Example #21
0
/**
 * purplemot_login - Login for an account. Establishes a connection
 *                   to the discovery server and initializes
 *
 * @param acct       The account to be logged in
 */
static void
purplemot_login(PurpleAccount *acct)
{
  char **userparts;
  struct pm_account *account;
  int port;

  const char *username = purple_account_get_username(acct);

  PurpleConnection *gc = purple_account_get_connection(acct);
  GList *offline_messages;

  purple_debug_info("purplemot", "logging in %s\n", acct->username);

  // TODO(carl): initialize motmot here?

  if (strpbrk(username, " \t\v\r\n") != NULL) {
    purple_connection_error_reason (gc,
      PURPLE_CONNECTION_ERROR_INVALID_SETTINGS,
      _("Motmot server may not contain whitespace"));
    return;
  }

  gc->proto_data = account = g_new0(struct pm_account, 1);
  account->pa = acct;

  userparts = g_strsplit(username, "@", 2);
  purple_connection_set_display_name(gc, userparts[0]);
  account->server_host = g_strdup(userparts[1]);
  g_strfreev(userparts);

  port = purple_account_get_int(acct, "disc_port", DEFAULT_PORT);

  purple_connection_update_progress(gc, _("Connecting"),
                                    0,   /* which connection step this is */
                                    2);  /* total number of steps */

  purple_debug_info("motmot", "connecting to discovery server");

  rpc_connect(account);


  purple_connection_update_progress(gc, _("Connected"),
                                    1,   /* which connection step this is */
                                    2);  /* total number of steps */
  purple_connection_set_state(gc, PURPLE_CONNECTED);


  /* fetch stored offline messages */
  purple_debug_info("purplemot", "checking for offline messages for %s\n",
                    acct->username);
  offline_messages = g_hash_table_lookup(goffline_messages, acct->username);
  while (offline_messages) {
    GOfflineMessage *message = (GOfflineMessage *)offline_messages->data;
    purple_debug_info("purplemot", "delivering offline message to %s: %s\n",
                      acct->username, message->message);
    serv_got_im(gc, message->from, message->message, message->flags,
                message->mtime);
    offline_messages = g_list_next(offline_messages);

    g_free(message->from);
    g_free(message->message);
    g_free(message);
  }

  g_list_free(offline_messages);
  g_hash_table_remove(goffline_messages, &acct->username);
}
Example #22
0
gboolean silcpurple_check_silc_dir(PurpleConnection *gc)
{
	char filename[256], file_public_key[256], file_private_key[256];
	char servfilename[256], clientfilename[256], friendsfilename[256];
	char pkd[256], prd[256];
	struct stat st;
	struct passwd *pw;
	int fd;

	pw = getpwuid(getuid());
	if (!pw) {
		purple_debug_error("silc", "silc: %s\n", g_strerror(errno));
		return FALSE;
	}

	g_snprintf(filename, sizeof(filename) - 1, "%s", silcpurple_silcdir());
	g_snprintf(servfilename, sizeof(servfilename) - 1, "%s" G_DIR_SEPARATOR_S "serverkeys",
		   silcpurple_silcdir());
	g_snprintf(clientfilename, sizeof(clientfilename) - 1, "%s" G_DIR_SEPARATOR_S "clientkeys",
		   silcpurple_silcdir());
	g_snprintf(friendsfilename, sizeof(friendsfilename) - 1, "%s" G_DIR_SEPARATOR_S "friends",
		   silcpurple_silcdir());

	if (pw->pw_uid != geteuid()) {
		purple_debug_error("silc", "Couldn't create directories due to wrong uid!\n");
		return FALSE;
	}

	/*
	 * Check ~/.silc directory
	 */
	if (g_mkdir(filename, 0755) != 0 && errno != EEXIST) {
		purple_debug_error("silc", "Couldn't create '%s' directory\n", filename);
		return FALSE;
	}

#ifndef _WIN32
	if ((g_stat(filename, &st)) == -1) {
		purple_debug_error("silc", "Couldn't stat '%s' directory, error: %s\n", filename, g_strerror(errno));
		return FALSE;
	} else {
		/* Check the owner of the dir */
		if (st.st_uid != 0 && st.st_uid != pw->pw_uid) {
			purple_debug_error("silc", "You don't seem to own '%s' directory\n",
				filename);
			return FALSE;
		}
	}
#endif

	/*
	 * Check ~./silc/serverkeys directory
	 */
	if (g_mkdir(servfilename, 0755) != 0 && errno != EEXIST) {
		purple_debug_error("silc", "Couldn't create '%s' directory\n", servfilename);
		return FALSE;
	}

	/*
	 * Check ~./silc/clientkeys directory
	 */
	if (g_mkdir(clientfilename, 0755) != 0 && errno != EEXIST) {
		purple_debug_error("silc", "Couldn't create '%s' directory\n", clientfilename);
		return FALSE;
	}

	/*
	 * Check ~./silc/friends directory
	 */
	if (g_mkdir(friendsfilename, 0755) != 0 && errno != EEXIST) {
		purple_debug_error("silc", "Couldn't create '%s' directory\n", friendsfilename);
		return FALSE;
	}

	/*
	 * Check Public and Private keys
	 */
	g_snprintf(pkd, sizeof(pkd), "%s" G_DIR_SEPARATOR_S "public_key.pub", silcpurple_silcdir());
	g_snprintf(prd, sizeof(prd), "%s" G_DIR_SEPARATOR_S "private_key.prv", silcpurple_silcdir());
	g_snprintf(file_public_key, sizeof(file_public_key) - 1, "%s",
		   purple_account_get_string(gc->account, "public-key", pkd));
	g_snprintf(file_private_key, sizeof(file_public_key) - 1, "%s",
		   purple_account_get_string(gc->account, "private-key", prd));

	if ((g_stat(file_public_key, &st)) == -1) {
		/* If file doesn't exist */
		if (errno == ENOENT) {
			purple_connection_update_progress(gc, _("Creating SILC key pair..."), 1, 5);
			if (!silc_create_key_pair(SILCPURPLE_DEF_PKCS,
						  SILCPURPLE_DEF_PKCS_LEN,
						  file_public_key,
						  file_private_key, NULL,
						  (gc->password == NULL)
						  ? "" : gc->password,
						  NULL, NULL, FALSE)) {
				purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_OTHER_ERROR,
				                             _("Unable to create SILC key pair"));
				return FALSE;
			}

			if ((g_stat(file_public_key, &st)) == -1) {
				purple_debug_error("silc", "Couldn't stat '%s' public key, error: %s\n",
						   file_public_key, g_strerror(errno));
				return FALSE;
			}
		} else {
			purple_debug_error("silc", "Couldn't stat '%s' public key, error: %s\n",
					   file_public_key, g_strerror(errno));
			return FALSE;
		}
	}

#ifndef _WIN32
	/* Check the owner of the public key */
	if (st.st_uid != 0 && st.st_uid != pw->pw_uid) {
		purple_debug_error("silc", "You don't seem to own your public key!?\n");
		return FALSE;
	}
#endif

	if ((fd = g_open(file_private_key, O_RDONLY, 0)) != -1) {
		if ((fstat(fd, &st)) == -1) {
			purple_debug_error("silc", "Couldn't stat '%s' private key, error: %s\n",
					   file_private_key, g_strerror(errno));
			close(fd);
			return FALSE;
		}
	} else {
		/* If file doesn't exist */
		if (errno == ENOENT) {
			purple_connection_update_progress(gc, _("Creating SILC key pair..."), 1, 5);
			if (!silc_create_key_pair(SILCPURPLE_DEF_PKCS,
						  SILCPURPLE_DEF_PKCS_LEN,
						  file_public_key,
						  file_private_key, NULL,
						  (gc->password == NULL)
						  ? "" : gc->password,
						  NULL, NULL, FALSE)) {
				purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_OTHER_ERROR,
				                             _("Unable to create SILC key pair"));
				return FALSE;
			}

			if ((fd = g_open(file_private_key, O_RDONLY, 0)) != -1) {
				if ((fstat(fd, &st)) == -1) {
					purple_debug_error("silc", "Couldn't stat '%s' private key, error: %s\n",
							   file_private_key, g_strerror(errno));
					close(fd);
					return FALSE;
				}
			} else {
				purple_debug_error("silc", "Couldn't open '%s' "
					"private key, error: %s\n",
					file_private_key, g_strerror(errno));
				return FALSE;
			}
		} else {
			purple_debug_error("silc", "Couldn't open '%s' private key, error: %s\n",
					   file_private_key, g_strerror(errno));
			return FALSE;
		}
	}

#ifndef _WIN32
	/* Check the owner of the private key */
	if (st.st_uid != 0 && st.st_uid != pw->pw_uid) {
		purple_debug_error("silc", "You don't seem to own your private key!?\n");
		if (fd != -1)
			close(fd);
		return FALSE;
	}

	/* Check the permissions for the private key */
	if ((st.st_mode & 0777) != 0600) {
		purple_debug_warning("silc", "Wrong permissions in your private key file `%s'!\n"
			"Trying to change them ...\n", file_private_key);
		if ((fd == -1) || (fchmod(fd, S_IRUSR | S_IWUSR)) == -1) {
			purple_debug_error("silc",
				"Failed to change permissions for private key file!\n"
				"Permissions for your private key file must be 0600.\n");
			if (fd != -1)
				close(fd);
			return FALSE;
		}
		purple_debug_warning("silc", "Done.\n\n");
	}
#endif

	if (fd != -1)
		close(fd);

	return TRUE;
}
Example #23
0
static void disallow_plaintext_auth(PurpleAccount *account)
{
	purple_connection_error_reason(purple_account_get_connection(account),
		PURPLE_CONNECTION_ERROR_ENCRYPTION_ERROR,
		_("Server may require plaintext authentication over an unencrypted stream"));
}
Example #24
0
void irc_parse_msg(struct irc_conn *irc, char *input)
{
	struct _irc_msg *msgent;
	char *cur, *end, *tmp, *from, *msgname, *fmt, **args, *msg;
	guint i;
	PurpleConnection *gc = purple_account_get_connection(irc->account);

	irc->recv_time = time(NULL);

	/*
	 * The data passed to irc-receiving-text is the raw protocol data.
	 * TODO: It should be passed as an array of bytes and a length
	 * instead of a null terminated string.
	 */
	purple_signal_emit(_irc_plugin, "irc-receiving-text", gc, &input);
	
	if (!strncmp(input, "PING ", 5)) {
		msg = irc_format(irc, "vv", "PONG", input + 5);
		irc_send(irc, msg);
		g_free(msg);
		return;
	} else if (!strncmp(input, "ERROR ", 6)) {
		if (g_utf8_validate(input, -1, NULL)) {
			char *tmp = g_strdup_printf("%s\n%s", _("Disconnected."), input);
			purple_connection_error_reason (gc,
				PURPLE_CONNECTION_ERROR_NETWORK_ERROR, tmp);
			g_free(tmp);
		} else
			purple_connection_error_reason (gc,
				PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
				_("Disconnected."));
		return;
	}

	if (input[0] != ':' || (cur = strchr(input, ' ')) == NULL) {
		irc_parse_error_cb(irc, input);
		return;
	}

	from = g_strndup(&input[1], cur - &input[1]);
	cur++;
	end = strchr(cur, ' ');
	if (!end)
		end = cur + strlen(cur);

	tmp = g_strndup(cur, end - cur);
	msgname = g_ascii_strdown(tmp, -1);
	g_free(tmp);

	if ((msgent = g_hash_table_lookup(irc->msgs, msgname)) == NULL) {
		irc_msg_default(irc, "", from, &input);
		g_free(msgname);
		g_free(from);
		return;
	}
	g_free(msgname);

	args = g_new0(char *, strlen(msgent->format));
	for (cur = end, fmt = msgent->format, i = 0; fmt[i] && *cur++; i++) {
		switch (fmt[i]) {
		case 'v':
			if (!(end = strchr(cur, ' '))) end = cur + strlen(cur);
			args[i] = g_strndup(cur, end - cur);
			cur += end - cur;
			break;
		case 't':
		case 'n':
		case 'c':
			if (!(end = strchr(cur, ' '))) end = cur + strlen(cur);
			tmp = g_strndup(cur, end - cur);
			args[i] = irc_recv_convert(irc, tmp);
			g_free(tmp);
			cur += end - cur;
			break;
		case ':':
			if (*cur == ':') cur++;
			args[i] = irc_recv_convert(irc, cur);
			cur = cur + strlen(cur);
			break;
		case '*':
			args[i] = g_strdup(cur);
			cur = cur + strlen(cur);
			break;
		default:
			purple_debug(PURPLE_DEBUG_ERROR, "irc", "invalid message format character '%c'\n", fmt[i]);
			break;
		}
	}
	tmp = irc_recv_convert(irc, from);
	(msgent->cb)(irc, msgent->name, tmp, args);
	g_free(tmp);
	for (i = 0; i < strlen(msgent->format); i++) {
		g_free(args[i]);
	}
	g_free(args);
	g_free(from);
}
Example #25
0
static void spin_receive_friends_cb(PurpleUtilFetchUrlData* url_data,
				    gpointer userp,
				    JsonNode* node,
				    const gchar* error_message)
{
  PurpleConnection* gc = (PurpleConnection*) userp;
  
  if(!PURPLE_CONNECTION_IS_VALID(gc))
    return;

  if(!node)
    {
      purple_debug_error("spin","friend list error:%s\n",error_message);
      purple_connection_error_reason(gc,PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
				     _("could not receive friend list"));
      return;
    }
  
  SpinData* spin = (SpinData*) gc->proto_data;
  PurpleAccount* account = purple_connection_get_account(gc);
  GHashTable* found_buddies = g_hash_table_new(g_direct_hash,g_direct_equal);
  GSList* account_buddies = purple_find_buddies(account,NULL);
  
  if(!node || JSON_NODE_TYPE(node) != JSON_NODE_ARRAY)
    {
      purple_connection_error_reason
	(gc,PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
	 _("invalid friend list format"));
      goto exit;
    }
  JsonArray* friends = json_node_get_array(node);
  guint i;
  for(i = 0; i < json_array_get_length(friends); ++i)
    {
      node = json_array_get_element(friends,i);
      JsonArray* entry;
      if(JSON_NODE_TYPE(node) != JSON_NODE_ARRAY
	 || json_array_get_length(entry = json_node_get_array(node)) != 7)
	{
	  purple_debug_info("spin","invalid friend list entry\n");
	  continue;
	}

      const gchar* id = json_node_get_string(json_array_get_element(entry,0));
      const gchar* name = json_node_get_string(json_array_get_element(entry,1));
      guint online = json_node_get_int(json_array_get_element(entry,2));
      const gchar* away = json_node_get_string(json_array_get_element(entry,3));
      const gchar* photo =json_node_get_string(json_array_get_element(entry,5));
      purple_debug_info("spin","got friend info: %s %s %i %s %s\n",
			id,name,online,	away,photo);
      if(!name || !away || !photo || !id)
	continue;

      PurpleBuddy* buddy = spin_sync_buddy(spin,account_buddies,id,name,
					   online,away,photo);
      g_hash_table_insert(found_buddies,buddy,(gpointer)0x1);
    }

  GSList* b;
  for(b = account_buddies; b; b = b->next)
    {
      if(!g_hash_table_lookup(found_buddies,b->data))
	{
	  spin_notify_nick_removed
	    (spin,purple_buddy_get_name((PurpleBuddy*) b->data));
	  purple_blist_remove_buddy((PurpleBuddy*)b->data);
	}
    }

  spin_connect_add_state(spin,SPIN_STATE_GOT_INITIAL_FRIEND_LIST);

 exit:
  g_slist_free(account_buddies);
  g_hash_table_destroy(found_buddies);
}
Example #26
0
static void tcp_pending(gpointer data, gint source, PurpleInputCondition cond)
{
	PurpleConnection *gc = (PurpleConnection *) data;
	qq_data *qd;
	qq_connection *conn;
	guint8 buf[1024];		/* set to 16 when test  tcp_rxqueue */
	gint buf_len;
	gint bytes;

	guint8 *pkt;
	guint16 pkt_len;

	gchar *error_msg;
	guint8 *jump;
	gint jump_len;

	g_return_if_fail(gc != NULL && gc->proto_data != NULL);
	qd = (qq_data *) gc->proto_data;

	if(cond != PURPLE_INPUT_READ) {
		purple_connection_error_reason(gc,
				PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
				_("Socket error"));
		return;
	}

	conn = connection_find(qd, source);
	g_return_if_fail(conn != NULL);

	/* test code, not using tcp_rxqueue
	memset(pkt,0, sizeof(pkt));
	buf_len = read(qd->fd, pkt, sizeof(pkt));
	if (buf_len > 2) {
		packet_process(gc, pkt + 2, buf_len - 2);
	}
	return;
	*/

	buf_len = read(source, buf, sizeof(buf));
	if (buf_len < 0) {
		if (errno == EAGAIN)
			/* No worries */
			return;

		error_msg = g_strdup_printf(_("Lost connection with server: %s"), g_strerror(errno));
		purple_connection_error_reason(gc,
				PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
				error_msg);
		g_free(error_msg);
		return;
	} else if (buf_len == 0) {
		purple_connection_error_reason(gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
				_("Server closed the connection"));
		return;
	}

	/* keep alive will be sent in 30 seconds since last_receive
	 *  QQ need a keep alive packet in every 60 seconds
	 gc->last_received = time(NULL);
	*/
#if 1
	purple_debug_info("TCP_PENDING", "Read %d bytes, tcp_rxlen is %d\n", buf_len, conn->tcp_rxlen);
#endif
	conn->tcp_rxqueue = g_realloc(conn->tcp_rxqueue, buf_len + conn->tcp_rxlen);
	memcpy(conn->tcp_rxqueue + conn->tcp_rxlen, buf, buf_len);
	conn->tcp_rxlen += buf_len;

	pkt = g_newa(guint8, MAX_PACKET_SIZE);
	while (PURPLE_CONNECTION_IS_VALID(gc)) {
		if (qd->openconns == NULL) {
			break;
		}
		if (conn->tcp_rxqueue == NULL) {
			conn->tcp_rxlen = 0;
			break;
		}
		if (conn->tcp_rxlen < QQ_TCP_HEADER_LENGTH) {
			break;
		}

		bytes = 0;
		bytes += qq_get16(&pkt_len, conn->tcp_rxqueue + bytes);
		if (conn->tcp_rxlen < pkt_len) {
			break;
		}

#if 1
		qq_show_packet("tcp_pending", conn->tcp_rxqueue, pkt_len);
#endif
		/* purple_debug_info("TCP_PENDING", "Packet len=%d, rxlen=%d\n", pkt_len, conn->tcp_rxlen); */
		if ( pkt_len < QQ_TCP_HEADER_LENGTH
		    || *(conn->tcp_rxqueue + bytes) != QQ_PACKET_TAG
			|| *(conn->tcp_rxqueue + pkt_len - 1) != QQ_PACKET_TAIL) {
			/* HEY! This isn't even a QQ. What are you trying to pull? */
			purple_debug_warning("TCP_PENDING", "Packet error, no header or tail tag\n");

			jump = memchr(conn->tcp_rxqueue + 1, QQ_PACKET_TAIL, conn->tcp_rxlen - 1);
			if ( !jump ) {
				purple_debug_warning("TCP_PENDING", "Failed to find next tail, clear receive buffer\n");
				g_free(conn->tcp_rxqueue);
				conn->tcp_rxqueue = NULL;
				conn->tcp_rxlen = 0;
				return;
			}

			/* jump and over QQ_PACKET_TAIL */
			jump_len = (jump - conn->tcp_rxqueue) + 1;
			purple_debug_warning("TCP_PENDING", "Find next tail at %d, jump %d\n", jump_len, jump_len + 1);
			g_memmove(conn->tcp_rxqueue, jump, conn->tcp_rxlen - jump_len);
			conn->tcp_rxlen -= jump_len;
			continue;
		}

		/* get packet */
		memset(pkt, 0, MAX_PACKET_SIZE);
		g_memmove(pkt, conn->tcp_rxqueue + bytes, pkt_len - bytes);

		/* jump to next packet */
		conn->tcp_rxlen -= pkt_len;
		if (conn->tcp_rxlen) {
			/* purple_debug_info("TCP_PENDING", "shrink tcp_rxqueue to %d\n", conn->tcp_rxlen);	*/
			jump = g_memdup(conn->tcp_rxqueue + pkt_len, conn->tcp_rxlen);
			g_free(conn->tcp_rxqueue);
			conn->tcp_rxqueue = jump;
		} else {
			/* purple_debug_info("TCP_PENDING", "free tcp_rxqueue\n"); */
			g_free(conn->tcp_rxqueue);
			conn->tcp_rxqueue = NULL;
		}

		/* packet_process may call disconnect and destory data like conn
		 * do not call packet_process before jump,
		 * break if packet_process return FALSE */
		if (packet_process(gc, pkt, pkt_len - bytes) == FALSE) {
			purple_debug_info("TCP_PENDING", "Connection has been destory\n");
			break;
		}
	}
}
Example #27
0
static void got_buddy_list_cb(FacebookAccount *fba, gchar *data,
                              gsize data_len, gpointer userdata)
{
    GSList *buddies_list;
    GSList *online_buddies_list = NULL;
    PurpleBuddy *buddy;
    FacebookBuddy *fbuddy;
    gchar *uid;
    gchar *name;
    gchar *status_text;
    gchar *status_time_text;
    gchar *buddy_icon_url;
    gboolean idle;
    guint32 error_number;

    gchar *search_start;
    gchar *search_tmp;
    gchar *tmp;
    gchar *largest_buddy_search_point = NULL;

    PurpleGroup *fb_group = NULL;

    gboolean current_buddy_online = FALSE;

    purple_debug_info("facebook", "parsing buddy list\n");
    purple_debug_misc("facebook", "buddy list\n%s\n", data);

    if (fba == NULL)
        return;

    if (data == NULL) {
        purple_connection_error_reason(fba->pc,
                                       PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
                                       _("Could not retrieve buddy list"));
        return;
    }

    /* Check if the facebook group already exists (fixes #13) */
    fb_group = purple_find_group("Facebook");

    /* if logged out, this comes up */
    /* for (;;);{"error":1357001,"errorSummary":"Not Logged In",
    	"errorDescription":"You must be logged in to do that.",
    	"payload":null,"bootload":[{"name":"js\/common.js.pkg.php",
    	"type":"js","src":"http:\/\/static.ak.fbcdn.net\/rsrc.php\/pkg\/59\
    	/98561\/js\/common.js.pkg.php"}]} */
    tmp = g_strstr_len(data, data_len, "\"error\":");
    if (tmp != NULL)
    {
        tmp += 9;
        tmp = g_strndup(tmp, strchr(tmp, ',')-tmp);
        error_number = atoi(tmp);
        g_free(tmp);
        if (error_number)
        {
            /* error :( */
            tmp = g_strstr_len(data, data_len, "\"errorDescription\":");
            tmp += 20;
            tmp = g_strndup(tmp, strchr(tmp, '"')-tmp);
            /* TODO: Use purple_connection_error_reason() */
            purple_connection_error(fba->pc, tmp);
            g_free(tmp);
            return;
        }
    }

    /* look for "userInfos":{ ... }, */
    search_start = strstr(data, "\"userInfos\":{");
    if (search_start == NULL)
        return;
    search_start += 13;

    while (*search_start != '}' && (search_start - data < data_len))
    {
        tmp = strchr(search_start, ':');
        uid = g_strndup(search_start+1, tmp-search_start-2);
        /* purple_debug_misc("facebook", "uid: %s\n", uid); */

        search_start += strlen(uid) + 2;

        search_tmp = strstr(search_start, "\"name\":") + 8;
        if (search_tmp > largest_buddy_search_point)
            largest_buddy_search_point = search_tmp;
        search_tmp = g_strndup(search_tmp, strchr(search_tmp, '"')-search_tmp);
        name = fb_convert_unicode(search_tmp);
        g_free(search_tmp);
        /* purple_debug_misc("facebook", "name: %s\n", name); */

        /* try updating the alias, just in case it was removed locally */
        serv_got_alias(fba->pc, uid, name);

        /* look for "uid":{"i":_____} */
        tmp = g_strdup_printf("\"%s\":{\"i\":", uid);
        search_tmp = g_strstr_len(data, data_len, tmp);
        if (search_tmp != NULL)
        {
            search_tmp += strlen(tmp);
            if (search_tmp > largest_buddy_search_point)
                largest_buddy_search_point = search_tmp;
            search_tmp = g_strndup(search_tmp, strchr(search_tmp, '}')-search_tmp);
            /* purple_debug_misc("facebook", "buddy idle: %s\n", search_tmp); */
            buddy = purple_find_buddy(fba->account, uid);
            idle = g_str_equal(search_tmp, "true");
            g_free(search_tmp);
            current_buddy_online = TRUE;
        } else {
            /* if we're here, the buddy's info has been sent, but they're not actually online */
            current_buddy_online = FALSE;
            idle = FALSE;
        }
        g_free(tmp);

        /* Set the buddy status text and time */
        search_tmp = strstr(search_start, "\"status\":");
        if (search_tmp != NULL && *(search_tmp + 9) == '"')
        {
            search_tmp += 10;
            if (search_tmp > largest_buddy_search_point)
                largest_buddy_search_point = strstr(search_tmp, ",\"statusTime");
            search_tmp = g_strndup(search_tmp, strstr(search_tmp, ",\"statusTime")-1-search_tmp);
            status_text = fb_convert_unicode(search_tmp);
            g_free(search_tmp);
        } else {
            status_text = NULL;
        }

        /* is this us? */
        if (atoi(uid) == fba->uid)
        {
            purple_connection_set_display_name(fba->pc, name);

            /* set our last known status so that we don't re-set it */
            if (status_text && !fba->last_status_message)
                fba->last_status_message = g_strdup(status_text);

            /* check that we don't want to show ourselves */
            if (purple_account_get_bool(fba->account, "facebook_hide_self", TRUE))
            {
                g_free(status_text);
                g_free(name);
                g_free(uid);

                /* Move pointer to the end of the buddy entry */
                search_start = strchr(largest_buddy_search_point, '}') + 1;
                while (*search_start == ',' && (search_start - data < data_len))
                    search_start++;
                /* go on to the next buddy */
                continue;
            } else {
                current_buddy_online = TRUE;
            }
        }

        /* Is this a new buddy? */
        buddy = purple_find_buddy(fba->account, uid);
        if (buddy == NULL)
        {
            buddy = purple_buddy_new(fba->account, uid, NULL);
            if (fb_group == NULL)
            {
                fb_group = purple_group_new("Facebook");
                purple_blist_add_group(fb_group, NULL);
            }
            purple_blist_add_buddy(buddy, NULL, fb_group, NULL);
        }
        serv_got_alias(fba->pc, uid, name);
        purple_presence_set_idle(purple_buddy_get_presence(buddy), idle, 0);

        /* Set the FacebookBuddy structure */
        if (buddy->proto_data == NULL)
        {
            fbuddy = g_new0(FacebookBuddy, 1);
            fbuddy->buddy = buddy;
            fbuddy->fba = fba;
            fbuddy->uid = atoi(uid);
            fbuddy->name = g_strdup(name);

            /* load the old buddy icon from the account settings */
            tmp = g_strdup_printf("buddy_icon_%d_cache", fbuddy->uid);
            fbuddy->thumb_url = g_strdup(purple_account_get_string(fba->account, tmp, ""));
            g_free(tmp);

            buddy->proto_data = fbuddy;
        } else {
            fbuddy = buddy->proto_data;
        }

        g_free(uid);
        g_free(name);

        if (status_text != NULL)
        {
            tmp = fb_strdup_withhtml(status_text);
            g_free(status_text);
            status_text = tmp;
            /* purple_debug_misc("facebook", "status: %s\n", status_text); */

            search_tmp = strstr(search_start, "\"statusTimeRel\":") + 17;
            if (search_tmp > largest_buddy_search_point)
                largest_buddy_search_point = strchr(search_tmp, '"');
            search_tmp = g_strndup(search_tmp, strchr(search_tmp, '"')-search_tmp);
            status_time_text = fb_convert_unicode(search_tmp);
            g_free(search_tmp);

            if (g_str_equal(status_time_text, "ull,"))
            {
                g_free(status_time_text);
                status_time_text = NULL;
            }
            g_free(fbuddy->status_rel_time);
            if (status_time_text != NULL)
            {
                fbuddy->status_rel_time = fb_strdup_withhtml(status_time_text);
                g_free(status_time_text);
                /* purple_debug_misc("facebook", "status time: %s\n", fbuddy->status_rel_time); */
            } else {
                fbuddy->status_rel_time = NULL;
            }

            /* if the buddy status has changed, update the contact list */
            if (fbuddy->status == NULL || !g_str_equal(fbuddy->status, status_text))
            {
                tmp = fbuddy->status;
                fbuddy->status = status_text;
                g_free(tmp);
                if (current_buddy_online)
                    purple_prpl_got_user_status(fba->account, buddy->name, purple_primitive_get_id_from_type(PURPLE_STATUS_AVAILABLE), NULL);
            } else {
                g_free(status_text);
            }
        } else {
            if (fbuddy->status != NULL)
            {
                g_free(fbuddy->status);
                fbuddy->status = NULL;
                if (current_buddy_online)
                {
                    /* update the status in the contact list */
                    purple_prpl_got_user_status(fba->account, buddy->name, purple_primitive_get_id_from_type(PURPLE_STATUS_AVAILABLE), NULL);
                }
            }
        }

        /* Set the buddy icon (if it hasn't changed) */
        search_tmp = strstr(search_start, "\"thumbSrc\":") + 12;
        if (search_tmp > largest_buddy_search_point)
            largest_buddy_search_point = search_tmp;
        buddy_icon_url = g_strndup(search_tmp, strchr(search_tmp, '"')-search_tmp);
        if (fbuddy->thumb_url == NULL || !g_str_equal(fbuddy->thumb_url, buddy_icon_url))
        {
            g_free(fbuddy->thumb_url);
            fbuddy->thumb_url = g_strdup(buddy_icon_url);

            /* Save the buddy icon so that they don't all need to be reloaded at startup */
            tmp = g_strdup_printf("buddy_icon_%d_cache", fbuddy->uid);
            purple_account_set_string(fba->account, tmp, buddy_icon_url);
            g_free(tmp);

            /* Turn the \/ into / */
            tmp = g_strcompress(buddy_icon_url);

            /* small icon at http://profile.ak.facebook.com/profile6/1845/74/q800753867_2878.jpg */
            /* bigger icon at http://profile.ak.facebook.com/profile6/1845/74/n800753867_2878.jpg */
            search_tmp = strstr(tmp, "/q");
            if (search_tmp)
                *(search_tmp + 1) = 'n';

            if (g_str_equal(tmp, "http://static.ak.fbcdn.net/pics/q_silhouette.gif"))
                /* User has no icon */
                purple_buddy_icons_set_for_user(fba->account,
                                                purple_buddy_get_name(buddy), NULL, 0, NULL);
            else
                /* Fetch their icon */
                fb_post_or_get(fba, FB_METHOD_GET, "profile.ak.facebook.com",
                               tmp + strlen("http://profile.ak.facebook.com"), NULL,
                               buddy_icon_cb, g_strdup(purple_buddy_get_name(buddy)),
                               FALSE);
            g_free(tmp);
        }
        g_free(buddy_icon_url);

        if (current_buddy_online)
        {
            /* Add buddy to the list of online buddies */
            online_buddies_list = g_slist_append(online_buddies_list, buddy);

            /* Update the display of the buddy in the buddy list and make the user online */
            if (!PURPLE_BUDDY_IS_ONLINE(buddy))
                purple_prpl_got_user_status(fba->account, buddy->name, purple_primitive_get_id_from_type(PURPLE_STATUS_AVAILABLE), NULL);
        }

        /* Move pointer after any user configurable data */
        search_start = search_tmp;
        /* Move pointer to the end of the buddy entry */
        search_start = strchr(largest_buddy_search_point, '}') + 1;
        while (*search_start == ',' && (search_start - data < data_len))
            search_start++;
    }

    buddies_list = purple_find_buddies(fba->account, NULL);
    if (buddies_list != NULL)
    {
        g_slist_foreach(buddies_list, (GFunc)set_buddies_offline, online_buddies_list);
        g_slist_free(buddies_list);
    }
    g_slist_free(online_buddies_list);
}