Ejemplo n.º 1
0
void tgp_chat_users_update (struct tgl_state *TLS, struct tgl_chat *C) {
  PurpleConversation *pc = purple_find_chat (tg_get_conn (TLS), tgl_get_peer_id (C->id));
  if (pc) {
    purple_conv_chat_clear_users (purple_conversation_get_chat_data (pc));
    tgp_chat_add_all_users (TLS, pc, C);
  }
}
Ejemplo n.º 2
0
void p2tgl_conv_add_user (PurpleConversation *conv, struct tgl_chat_user user, char *message, int flags, int new_arrival) {
  PurpleConvChat *cdata = purple_conversation_get_chat_data(conv);
  char *name = g_strdup_printf("%d", user.user_id);
  
  purple_conv_chat_add_user(cdata, name, message, flags, new_arrival);
  
  g_free(name);
}
Ejemplo n.º 3
0
PurpleConversation *tgp_chat_show (struct tgl_state *TLS, struct tgl_chat *C) {
  connection_data *conn = TLS->ev_base;
  PurpleConversation *convo = purple_find_chat (conn->gc, tgl_get_peer_id (C->id));
  PurpleConvChat *chat = purple_conversation_get_chat_data (convo);
  
  if (! convo || (chat && purple_conv_chat_has_left (chat))) {
    convo = serv_got_joined_chat (conn->gc, tgl_get_peer_id (C->id), C->print_title);
    tgp_chat_users_update (conn->TLS, C);
  }
  return convo;
}
Ejemplo n.º 4
0
PurpleConversation *tgp_chat_show (struct tgl_state *TLS, struct tgl_chat *C) {
  PurpleConvChat *chat = NULL;
  
  // check if chat is already shown
  PurpleConversation *conv = purple_find_chat (tls_get_conn (TLS), tgl_get_peer_id (C->id));
  if (conv) {
    chat = purple_conversation_get_chat_data (conv);
    if (chat && ! purple_conv_chat_has_left (chat)) {
      return conv;
    }
  }
  
  // join the chat now
  conv = serv_got_joined_chat (tls_get_conn (TLS), tgl_get_peer_id (C->id), C->print_title);
  g_return_val_if_fail(conv, NULL);
  
  purple_conv_chat_clear_users (purple_conversation_get_chat_data (conv));
  tgp_chat_add_all_users (TLS, conv, C);
  
  return conv;
}
Ejemplo n.º 5
0
SpectrumMUCConversation::SpectrumMUCConversation(PurpleConversation *conv, const std::string &jid, const std::string &resource) : AbstractConversation(SPECTRUM_CONV_GROUPCHAT) {
	m_jid = jid;
	m_res = "/" + resource;
	m_conv = conv;
	m_connected = false;
	m_lastPresence = NULL;
#ifndef TESTS
	m_conv->ui_data = this;
	PurpleConvChat *chat = purple_conversation_get_chat_data(m_conv);
	m_nickname = purple_conv_chat_get_nick(chat);
#endif
}
Ejemplo n.º 6
0
static PurpleCmdRet
send_whisper(PurpleConversation *conv, const char *cmd, char **args,
    char **error, void *userdata)
{
  const char *to_username;
  const char *message;
  const char *from_username;
  PurpleConvChat *chat;
  PurpleConvChatBuddy *chat_buddy;
  PurpleConnection *to;

  // parse args
  to_username = args[0];
  message = args[1];

  if (!to_username || strlen(to_username) == 0) {
    *error = g_strdup(_("Whisper is missing recipient."));
    return PURPLE_CMD_RET_FAILED;
  } else if (!message || strlen(message) == 0) {
    *error = g_strdup(_("Whisper is missing message."));
    return PURPLE_CMD_RET_FAILED;
  }

  from_username = conv->account->username;
  purple_debug_info("purplemot", "%s whispers to %s in chat room %s: %s\n",
                    from_username, to_username, conv->name, message);

  chat = purple_conversation_get_chat_data(conv);
  chat_buddy = purple_conv_chat_cb_find(chat, to_username);
  to = get_purplemot_gc(to_username);

  if (!chat_buddy) {
    // this will be freed by the caller
    *error = g_strdup_printf(_("%s is not logged in."), to_username);
    return PURPLE_CMD_RET_FAILED;
  } else if (!to) {
    *error = g_strdup_printf(_("%s is not in this chat room."), to_username);
    return PURPLE_CMD_RET_FAILED;
  } else {
    // write the whisper in the sender's chat window
    char *message_to = g_strdup_printf("%s (to %s)", message, to_username);
    purple_conv_chat_write(chat, from_username, message_to,
                           PURPLE_MESSAGE_SEND | PURPLE_MESSAGE_WHISPER,
                           time(NULL));
    g_free(message_to);

    // send the whisper
    serv_chat_whisper(to, chat->id, from_username, message);

    return PURPLE_CMD_RET_OK;
  }
}
Ejemplo n.º 7
0
void QuetzalChat::renameUser(const char *old_name, const char *new_name, const char *new_alias)
{
	QuetzalAccount *account = reinterpret_cast<QuetzalAccount*>(m_conv->account->ui_data);
	PurpleConvChat *data = purple_conversation_get_chat_data(m_conv);
	QuetzalChatUser *user = m_users.take(old_name);
	account->removeChatUnit(user);
	user->fixId(purple_conv_chat_cb_find(data, new_name));
	m_users.insert(new_name, user);
	user->rename(new_alias);
	account->addChatUnit(user);
//	if (!qstrcmp(old_name, data->nick))
//		emit meChanged(user);
}
Ejemplo n.º 8
0
static PurpleRoomlist *
purplemot_roomlist_get_list(PurpleConnection *gc)
{
  const char *username = gc->account->username;
  PurpleRoomlist *roomlist = purple_roomlist_new(gc->account);
  GList *fields = NULL;
  PurpleRoomlistField *field;
  GList *chats;
  GList *seen_ids = NULL;

  purple_debug_info("purplemot", "%s asks for room list; returning:\n", username);

  /* set up the room list */
  field = purple_roomlist_field_new(PURPLE_ROOMLIST_FIELD_STRING, "room",
                                    "room", TRUE /* hidden */);
  fields = g_list_append(fields, field);

  field = purple_roomlist_field_new(PURPLE_ROOMLIST_FIELD_INT, "Id", "Id", FALSE);
  fields = g_list_append(fields, field);

  purple_roomlist_set_fields(roomlist, fields);

  /* add each chat room. the chat ids are cached in seen_ids so that each room
   * is only returned once, even if multiple users are in it. */
  for (chats  = purple_get_chats(); chats; chats = g_list_next(chats)) {
    PurpleConversation *conv = (PurpleConversation *)chats->data;
    PurpleRoomlistRoom *room;
    const char *name = conv->name;
    int id = purple_conversation_get_chat_data(conv)->id;

    /* have we already added this room? */
    if (g_list_find_custom(seen_ids, name, (GCompareFunc)strcmp))
      continue;                                /* yes! try the next one. */

    /* This cast is OK because this list is only staying around for the life
     * of this function and none of the conversations are being deleted
     * in that timespan. */
    seen_ids = g_list_prepend(seen_ids, (char *)name); /* no, it's new. */
    purple_debug_info("purplemot", "%s (%d), ", name, id);

    room = purple_roomlist_room_new(PURPLE_ROOMLIST_ROOMTYPE_ROOM, name, NULL);
    purple_roomlist_room_add_field(roomlist, room, name);
    purple_roomlist_room_add_field(roomlist, room, &id);
    purple_roomlist_room_add(roomlist, room);
  }

  g_list_free(seen_ids);
  purple_timeout_add(1 /* ms */, purplemot_finish_get_roomlist, roomlist);
  return roomlist;
}
Ejemplo n.º 9
0
static void waprpl_chat_invite(PurpleConnection * gc, int id, const char *message, const char *name)
{
	whatsapp_connection *wconn = purple_connection_get_protocol_data(gc);
	PurpleConversation *convo = purple_find_chat(gc, id);
	PurpleChat *ch = blist_find_chat_by_convo(gc, id);
	GHashTable *hasht = purple_chat_get_components(ch);
	char *chat_id = g_hash_table_lookup(hasht, "id");

	if (strstr(name, "@s.whatsapp.net") == 0)
		name = g_strdup_printf("*****@*****.**", name);
	waAPI_manageparticipant(wconn->waAPI, chat_id, name, "add");

	purple_conv_chat_add_user(purple_conversation_get_chat_data(convo), name, "", PURPLE_CBFLAGS_NONE, FALSE);

	waprpl_check_output(gc);
}
Ejemplo n.º 10
0
PurpleConversation *chat_show (PurpleConnection *gc, int id) {
  connection_data *conn = purple_connection_get_protocol_data(gc);
  PurpleConversation *convo = purple_find_chat (gc, id);
  PurpleConvChat *chat = purple_conversation_get_chat_data (convo);
  tgl_peer_t *P = tgl_peer_get (conn->TLS, TGL_MK_CHAT(id));
  
  if (! P) {
    warning ("Chat %d not existing, not showing...", id);
    return NULL;
  }
  if (! convo || (chat && purple_conv_chat_has_left (chat))) {
    convo = p2tgl_got_joined_chat (conn->TLS, &P->chat);
  }
  chat_users_update (conn->TLS, &P->chat);

  return convo;
}
Ejemplo n.º 11
0
static void
purplemot_set_chat_topic(PurpleConnection *gc, int id, const char *topic)
{
  PurpleConversation *conv = purple_find_chat(gc, id);
  PurpleConvChat *chat = purple_conversation_get_chat_data(conv);
  const char *last_topic;

  if (!chat)
    return;

  purple_debug_info("purplemot", "%s sets topic of chat room '%s' to '%s'\n",
                    gc->account->username, conv->name, topic);

  last_topic = purple_conv_chat_get_topic(chat);
  if ((!topic && !last_topic) ||
      (topic && last_topic && !strcmp(topic, last_topic)))
    return;  /* topic is unchanged, this is a noop */
}
Ejemplo n.º 12
0
QuetzalChat::QuetzalChat(PurpleConversation *conv) : 
		Conference(reinterpret_cast<Account *>(conv->account->ui_data))
{
	m_conv = conv;
	m_conv->ui_data = this;
	m_id = m_conv->name;
	m_title = m_conv->title;
	if (m_id.isEmpty()) {
		// Hack for msn-like protocols
		m_id = QLatin1String("QuetzalChat#")
			   + QString::number(quint64(qrand()) << 20 | quint64(qrand()), 16);
	}
	PurpleConvChat *chat = purple_conversation_get_chat_data(conv);
	if (!chat->left)
		setJoined(true);
//	if (account()->protocol()->id() == "msn")
//		m_id = "QuetzalChat#" + QString::number(chat->id);
}
Ejemplo n.º 13
0
static void
chat_msg_received_cb(PurpleAccount *account, char *sender,
					 char *message, PurpleConversation *conv,
					 PurpleMessageFlags flags, PurpleSoundEventID event)
{
	PurpleConvChat *chat;

	if (flags & PURPLE_MESSAGE_DELAYED)
		return;

	chat = purple_conversation_get_chat_data(conv);
	g_return_if_fail(chat != NULL);

	if (purple_conv_chat_is_user_ignored(chat, sender))
		return;

	if (chat_nick_matches_name(conv, sender))
		return;

	if (flags & PURPLE_MESSAGE_NICK || purple_utf8_has_word(message, chat->nick))
		play_conv_event(conv, PURPLE_SOUND_CHAT_NICK);
	else
		play_conv_event(conv, event);
}
Ejemplo n.º 14
0
static void purple_chat_msg( struct groupchat *gc, char *message, int flags )
{
	PurpleConversation *pc = gc->data;
	
	purple_conv_chat_send( purple_conversation_get_chat_data( pc ), message );
}
Ejemplo n.º 15
0
xmlnode * _h_elim_message ( const char *name ,
                            const char *id   ,
                            SEXP_VALUE *args ,
                            gpointer data    )
{
    fprintf(stderr, "(elim-debug entered _h_elim_message)");
    ASSERT_ALISTP( args, id, name );
    
    elim_ping();

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

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

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

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

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

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

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

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

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

    g_free       ( esc  );
    sexp_val_free( args );
    fprintf(stderr, "(elim-debug leaving _h_elim_message)");
    return response_value( 0, id, name, rval );
}
Ejemplo n.º 16
0
static char *format_service_msg (struct tgl_state *TLS, struct tgl_message *M) {
  g_return_val_if_fail(M && M->flags & TGLMF_SERVICE, NULL);

  connection_data *conn = TLS->ev_base;
  char *txt = NULL;
  
  tgl_peer_t *fromPeer = tgl_peer_get (TLS, M->from_id);
  g_return_val_if_fail(fromPeer != NULL, NULL);
  
  const char *txt_user = fromPeer->print_name;

  switch (M->action.type) {
    case tgl_message_action_chat_create:
      txt = g_strdup_printf (_("%2$s created chat %1$s."), M->action.title, txt_user);
      break;
    case tgl_message_action_chat_edit_title:
      txt = g_strdup_printf (_("%2$s changed title to %1$s."), M->action.new_title, txt_user);
      break;
    case tgl_message_action_chat_edit_photo:
      txt = g_strdup_printf (_("%s changed photo."), txt_user);
      break;
    case tgl_message_action_chat_delete_photo:
      txt = g_strdup_printf (_("%s deleted photo."), txt_user);
      break;
    case tgl_message_action_chat_add_user_by_link: {
      tgl_peer_t *actionPeer = tgl_peer_get (TLS, TGL_MK_USER (M->action.user));
      if (actionPeer) {
        char *alias = actionPeer->print_name;
        
        PurpleConversation *conv = purple_find_chat (conn->gc, tgl_get_peer_id (M->to_id));
        txt = g_strdup_printf (_("%1$s added user %2$s by link."), alias, txt_user);
        if (conv) {
          p2tgl_conv_add_user (TLS, conv, tgl_get_peer_id (fromPeer->id), NULL, 0, FALSE);
        }

        return txt;
      }
      break;
    }
    case tgl_message_action_chat_add_user: {
      tgl_peer_t *peer = tgl_peer_get (TLS, TGL_MK_USER (M->action.user));
      if (peer) {
        char *alias = peer->print_name;
        txt = g_strdup_printf (_("%2$s added user %1$s."), alias, txt_user);
        PurpleConversation *conv = purple_find_chat (conn->gc, tgl_get_peer_id (M->to_id));
        if (conv) {
          p2tgl_conv_add_user (TLS, conv, M->action.user, NULL, 0, FALSE);
        }
      }
      break;
    }
    case tgl_message_action_chat_delete_user: {
      tgl_peer_t *peer = tgl_peer_get (TLS, TGL_MK_USER (M->action.user));
      if (peer) {

        tgl_peer_t *chatPeer = tgl_peer_get (TLS, M->to_id);
        g_return_val_if_fail(tgl_get_peer_type (chatPeer->id) == TGL_PEER_CHAT, NULL);
        
        // make sure that the chat is showing before deleting the user, otherwise the chat will be
        // initialised after removing the chat and the chat will still contain the deleted user
        PurpleConversation *conv = tgp_chat_show (TLS, &chatPeer->chat);
        if (conv) {
          char *alias = peer->print_name;
          const char *aliasLeft = tgp_blist_lookup_purple_name (TLS, TGL_MK_USER (M->action.user));

          if (tgl_get_peer_id (M->from_id) != tgl_get_peer_id (peer->id)) {
            txt = g_strdup_printf (_("%2$s deleted user %1$s."), alias, txt_user);
          }
          g_return_val_if_fail (aliasLeft, NULL);

          purple_conv_chat_remove_user (purple_conversation_get_chat_data (conv), aliasLeft, txt);
          if (M->action.user == tgl_get_peer_id (TLS->our_id)) {
            purple_conv_chat_left (purple_conversation_get_chat_data (conv));
          }
          
          // conv_del_user already printed a message, prevent a redundant message
          // from being printed by returning NULL
          g_free (txt);
          return NULL;
        }
        
        char *alias = peer->print_name;
        if (tgl_get_peer_id (M->from_id) != tgl_get_peer_id (peer->id)) {
          txt = g_strdup_printf (_("%2$s deleted user %1$s."), alias, txt_user);
        }
      }
      break;
    }
    case tgl_message_action_set_message_ttl:

      txt = g_strdup_printf (P_("%2$s set self destruction timer to %1$d second.",
                                "%2$s set self destruction timer to %1$d seconds.",
                                M->action.ttl),
                             M->action.ttl, txt_user);
      break;
    case tgl_message_action_read_messages:
      txt = g_strdup_printf (P_("%2$s marked %1$d message read.",
                                "%2$s marked %1$d messages read.",
                                M->action.read_cnt),
                             M->action.read_cnt, txt_user);
      break;
    case tgl_message_action_delete_messages:
      txt = g_strdup_printf (P_("%2$s deleted %1$d message.",
                                "%2$s deleted %1$d messages.",
                                M->action.delete_cnt),
                             M->action.delete_cnt, txt_user);
      break;
    case tgl_message_action_screenshot_messages:
      txt = g_strdup_printf (P_("%2$s made a screenshot of %1$d message.",
                                "%2$s made a screenshot of %1$d messages.",
                                M->action.screenshot_cnt),
                             M->action.screenshot_cnt, txt_user);
      break;
    default:
      g_warn_if_reached();
      break;
  }
  return txt;
}
Ejemplo n.º 17
0
Buddy *QuetzalChat::me() const
{
	PurpleConvChat *data = purple_conversation_get_chat_data(m_conv);
	return m_users.value(m_nick.isEmpty() ? QString::fromUtf8(data->nick) : m_nick);
}
Ejemplo n.º 18
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);

  switch (waAPI_loginstatus(wconn->waAPI)) {
  case 0:
    purple_connection_update_progress(gc, "Connecting", 0, 4);
    break;
  case 1:
    purple_connection_update_progress(gc, "Sending auth", 1, 4);
    break;
  case 2:
    purple_connection_update_progress(gc, "Waiting response", 2, 4);
    break;
  case 3:
    purple_connection_update_progress(gc, "Connected", 3, 4);
    purple_connection_set_state(gc, PURPLE_CONNECTED);
    
    if (!wconn->connected)
      waprpl_insert_contacts(gc);
      
    wconn->connected = 1;
    break;
  default:
    break;
  };
  
  char * msg, * who, * prev, * url, *author;
  int status; int size;
  double lat,lng;
  // Incoming messages
  while (waAPI_querychat(wconn->waAPI, &who, &msg, &author)) {
    purple_debug_info(WHATSAPP_ID, "Got chat message from %s: %s\n", who,msg);
    
    if (isgroup(who)) {
      // Search fot the combo
      PurpleBlistNode* node = purple_blist_get_root();
      GHashTable* hasht = NULL;
      while (node != 0) {
        if (PURPLE_BLIST_NODE_IS_CHAT(node)) {
          PurpleChat * ch = PURPLE_CHAT(node);
          if (purple_chat_get_account(ch) == acc) {
            hasht = purple_chat_get_components(ch);
            if (strcmp(g_hash_table_lookup(hasht, "id"),who) == 0) {
              break;
            }
          }
        }
        node = purple_blist_node_next(node,FALSE);
      }
      int convo_id = chatid_to_convo(who);
      PurpleConversation *convo = purple_find_chat(gc, convo_id);
      
      // Create a window if it's not open yet
      if (!convo)
        waprpl_chat_join(gc,hasht);
      
      if (convo != NULL) {
        serv_got_chat_in(gc, purple_conv_chat_get_id(PURPLE_CONV_CHAT(convo)), author, PURPLE_MESSAGE_RECV, msg, time(NULL));
      }else{
        printf("Received group message but could not find the group! %s\n",msg);
      }
    }else{
      // Search fot the combo
      PurpleConversation *convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, who, acc);
      if (!convo)
        convo = purple_conversation_new(PURPLE_CONV_TYPE_IM, acc, who);
      
      serv_got_chat_in(gc, purple_conv_chat_get_id(PURPLE_CONV_IM(convo)), who, PURPLE_MESSAGE_RECV, msg, time(NULL));
      purple_conv_im_write(PURPLE_CONV_IM(convo), who, msg, PURPLE_MESSAGE_RECV, time(NULL));
    }
  }
  while (waAPI_querychatimage(wconn->waAPI, &who, &prev, &size, &url)) {
    printf("Got chat image %s %s\n",who,url);
    purple_debug_info(WHATSAPP_ID, "Got image from %s: %s\n", who,url);
    
    // Search fot the combo
    PurpleConversation *convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, who, acc);
    if (!convo)
      convo = purple_conversation_new(PURPLE_CONV_TYPE_IM, acc, who);
      
    int imgid = purple_imgstore_add_with_id(g_memdup(prev, size), size, NULL);

    serv_got_chat_in(gc, purple_conv_chat_get_id(PURPLE_CONV_IM(convo)), who, PURPLE_MESSAGE_RECV, msg, time(NULL));
    purple_conv_im_write(PURPLE_CONV_IM(convo), who, g_strdup_printf("<a href=\"%s\"><img id=\"%u\"></a>",url,imgid),
      PURPLE_MESSAGE_RECV | PURPLE_MESSAGE_IMAGES, time(NULL));
  }
  while (waAPI_querychatlocation(wconn->waAPI, &who, &prev, &size, &lat, &lng)) {
    purple_debug_info(WHATSAPP_ID, "Got geomessage from: %s Coordinates (%f %f)\n", who,(float)lat,(float)lng);
    
    // Search fot the combo
    PurpleConversation *convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, who, acc);
    if (!convo)
      convo = purple_conversation_new(PURPLE_CONV_TYPE_IM, acc, who);
      
    int imgid = purple_imgstore_add_with_id(g_memdup(prev, size), size, NULL);

    serv_got_chat_in(gc, purple_conv_chat_get_id(PURPLE_CONV_IM(convo)), who, PURPLE_MESSAGE_RECV, msg, time(NULL));
    purple_conv_im_write(PURPLE_CONV_IM(convo), who, 
      g_strdup_printf("<a href=\"http://openstreetmap.org/?lat=%f&lon=%f&zoom=16\"><img src=\"%u\"></a>",lat,lng,imgid),
      PURPLE_MESSAGE_RECV | PURPLE_MESSAGE_IMAGES, time(NULL));
  }
  while (waAPI_querychatsound(wconn->waAPI, &who, &url)) {
    purple_debug_info(WHATSAPP_ID, "Got chat sound from %s: %s\n", who,url);
    
    // Search fot the combo
    PurpleConversation *convo = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, who, acc);
    if (!convo)
      convo = purple_conversation_new(PURPLE_CONV_TYPE_IM, acc, who);

    serv_got_chat_in(gc, purple_conv_chat_get_id(PURPLE_CONV_IM(convo)), who, PURPLE_MESSAGE_RECV, msg, time(NULL));
    purple_conv_im_write(PURPLE_CONV_IM(convo), who, g_strdup_printf("<a href=\"%s\">%s</a>",url,url),
      PURPLE_MESSAGE_RECV , time(NULL));
  }
  
  // User status change
  while (waAPI_querystatus(wconn->waAPI, &who, &status)) {
    if (status == 1) {
      purple_prpl_got_user_status(acc, who, "available", "message","", NULL);
    }
    else {
      purple_prpl_got_user_status(acc, who, "unavailable", "message","", NULL);
    }
  }
  // User typing info notify
  while (waAPI_querytyping(wconn->waAPI, &who, &status)) {
    if (status == 1) {
      serv_got_typing(gc,who,0,PURPLE_TYPING);
    }
    else {
      serv_got_typing_stopped(gc,who);
    }
  }
  
  // User profile picture
  char * icon, * hash;
  int len;
  while (waAPI_queryicon(wconn->waAPI, &who, &icon, &len, &hash)) {
    purple_buddy_icons_set_for_user(acc,who, g_memdup(icon,len),len, hash);
  }
  
  // Groups update
  if (waAPI_getgroupsupdated(wconn->waAPI)) {
  
    // Delete/update the chats that are in our list
    PurpleBlistNode* node = purple_blist_get_root();
    while (node != 0) {
      if (PURPLE_BLIST_NODE_IS_CHAT(node)) {
        PurpleChat * ch = PURPLE_CHAT(node);
        if (purple_chat_get_account(ch) == acc) {
        
          int found = 0;
          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);
          while (*gplist) {
            if (strcmp(*gplist,grid) == 0) {
              // The group is in the system, update the fields
              char *id,*sub,*own;
              waAPI_getgroupinfo(wconn->waAPI, *gplist, &sub, &own, 0);
              g_hash_table_insert(hasht, g_strdup("subject"), g_strdup(sub));
              g_hash_table_insert(hasht, g_strdup("owner"), g_strdup(own));
              
              found = 1;
              break;
            }
            gplist++;
          }

          // The group was deleted
          if (!found) {
              PurpleBlistNode* del = node;
              node = purple_blist_node_next(node,FALSE);
              purple_blist_remove_chat(del);
          }
          
        }
      }
      node = purple_blist_node_next(node,FALSE);
    }

    // Add new groups
    char * glist = waAPI_getgroups(wconn->waAPI);
    gchar **gplist = g_strsplit(glist,",",0);
    while (*gplist) {
      int found = 0;
      PurpleBlistNode* node = purple_blist_get_root();
      PurpleChat * ch;
      while (node != 0) {
        if (PURPLE_BLIST_NODE_IS_CHAT(node)) {
          ch = PURPLE_CHAT(node);
          if (purple_chat_get_account(ch) == acc) {
            char * grid = g_hash_table_lookup(purple_chat_get_components(ch), "id");
            if (strcmp(*gplist,grid) == 0) {
              found = 1;
              break;
            }
          }
        }
        node = purple_blist_node_next(node,FALSE);
      }

      if (!found) {
        char *sub,*own;
        waAPI_getgroupinfo(wconn->waAPI, *gplist, &sub, &own, 0);
        purple_debug_info("waprpl", "New group found %s %s\n", *gplist,sub);
        
        GHashTable * htable = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
        g_hash_table_insert(htable, g_strdup("subject"), g_strdup(sub));
        g_hash_table_insert(htable, g_strdup("id"), g_strdup(*gplist));
        g_hash_table_insert(htable, g_strdup("owner"), g_strdup(own));

        ch = purple_chat_new(acc,sub,htable);
        purple_blist_add_chat(ch,NULL,NULL);
      }
      
      // 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);
      if (conv) {
        char *subject, *owner, *part;
        if (!waAPI_getgroupinfo(wconn->waAPI, id, &subject, &owner, &part)) return;
        
        purple_conv_chat_clear_users(purple_conversation_get_chat_data(conv));
        gchar **plist = g_strsplit(part,",",0);
        while (*plist) {
          purple_conv_chat_add_user (purple_conversation_get_chat_data(conv),
            *plist,"",PURPLE_CBFLAGS_NONE | (!strcmp(owner,*plist) ? PURPLE_CBFLAGS_FOUNDER : 0),FALSE);
          plist++;
        }
      }
      
      gplist++;
    }
  }
}