Пример #1
0
tgl_peer_t *find_peer_by_name (struct tgl_state *TLS, const char *who) {
  tgl_peer_t *peer = tgl_peer_get (TLS, TGL_MK_USER(atoi (who)));
  if (peer) { return peer; }
  peer = tgl_peer_get (TLS, TGL_MK_CHAT(atoi(who)));
  if (peer) { return peer; }
  peer = tgl_peer_get (TLS, TGL_MK_ENCR_CHAT(atoi(who)));
  if (peer) { return peer; }
  return NULL;
}
Пример #2
0
static void tgprpl_chat_invite (PurpleConnection * gc, int id, const char *message, const char *name) {
  debug ("tgprpl_chat_invite()\n");

  telegram_conn *conn = purple_connection_get_protocol_data (gc);
  tgl_peer_t *chat = tgl_peer_get(conn->TLS, TGL_MK_CHAT (id));
  tgl_peer_t *user = tgl_peer_get(conn->TLS, TGL_MK_USER (atoi(name)));
  
  if (! chat || ! user) {
    purple_notify_error (_telegram_protocol, "Not found", "Cannot invite buddy to chat.", "Specified user is not existing.");
    return;
  }
  
  tgl_do_add_user_to_chat (conn->TLS, chat->id, user->id, 0, NULL, NULL);
}
Пример #3
0
static int tgprpl_send_im (PurpleConnection * gc, const char *who, const char *message, PurpleMessageFlags flags) {
  debug ("tgprpl_send_im()\n");
  
  telegram_conn *conn = purple_connection_get_protocol_data(gc);
  PurpleAccount *pa = conn->pa;
 
  // this is part of a workaround to support clients without
  // the request API (request.h), see telegram-base.c:request_code()
  if (conn->in_fallback_chat) {
    request_code_entered (conn->TLS, message);
    conn->in_fallback_chat = 0;
    return 1;
  }
  
  PurpleBuddy *b = purple_find_buddy (pa, who);
  if (!b) {
    warning ("Buddy %s not found, cannot send IM\n", who);
    return -1;
  }
  
  tgl_peer_t *peer = tgl_peer_get(conn->TLS, TGL_MK_USER(atoi (who)));
  if (!peer) {
    warning ("Protocol data tgl_peer_t for %s not found, cannot send IM\n", who);
    return -1;
  }
  gchar *raw = purple_unescape_html(message);
  tgl_do_send_message (conn->TLS, peer->id, raw, (int)strlen (raw), 0, 0);
  g_free(raw);
  return 1;
}
Пример #4
0
void bl_do_chat_del_user (struct tgl_state *TLS, tgl_peer_id_t id, int version, int user) /* {{{ */ {
  tgl_peer_t *P = tgl_peer_get (TLS, id);
  if (!P || !(P->flags & TGLPF_CREATED)) { return; }

  struct tgl_chat *C = &P->chat;
  if (C->user_list_version >= version || !C->user_list_version) { return; }
  
  int i;
  for (i = 0; i < C->user_list_size; i++) {
    if (C->user_list[i].user_id == user) {
      struct tgl_chat_user t;
      t = C->user_list[i];
      C->user_list[i] = C->user_list[C->user_list_size - 1];
      C->user_list[C->user_list_size - 1] = t;
    }
  }
  if (C->user_list[C->user_list_size - 1].user_id != user) { return; }

  assert (C->user_list[C->user_list_size - 1].user_id == user);
  C->user_list_size --;
  C->user_list = trealloc (C->user_list, 12 * C->user_list_size + 12, 12 * C->user_list_size);
  C->user_list_version = version;
  
  if (TLS->callback.chat_update) {
    TLS->callback.chat_update (TLS, C, TGL_UPDATE_MEMBERS);
  }
}
Пример #5
0
void bl_do_chat_add_user (struct tgl_state *TLS, tgl_peer_id_t id, int version, int user, int inviter, int date) /* {{{ */ {
  tgl_peer_t *P = tgl_peer_get (TLS, id);
  if (!P || !(P->flags & TGLPF_CREATED)) { return; }

  struct tgl_chat *C = &P->chat;
  if (C->user_list_version >= version || !C->user_list_version) { return; }

  int i;
  for (i = 0; i < C->user_list_size; i++) {
    if (C->user_list[i].user_id == user) { 
      return;
    }
  }

  C->user_list_size ++;
  C->user_list = trealloc (C->user_list, 12 * C->user_list_size - 12, 12 * C->user_list_size);
  C->user_list[C->user_list_size - 1].user_id = user;
  C->user_list[C->user_list_size - 1].inviter_id = inviter;
  C->user_list[C->user_list_size - 1].date = date;
  C->user_list_version = version;
  
  if (TLS->callback.chat_update) {
    TLS->callback.chat_update (TLS, C, TGL_UPDATE_MEMBERS);
  }
}
Пример #6
0
void bl_do_set_channel_pts (struct tgl_state *TLS, int id, int pts) /* {{{ */ {
  tgl_peer_t *E = tgl_peer_get (TLS, TGL_MK_CHANNEL (id));
  if (!E || !(E->flags & TGLPF_CREATED)) { return; }
  if (E->flags & TGLCHF_DIFF) { return ; }
  if (E->channel.pts <= pts) { return; }
  E->channel.pts = pts;
}
Пример #7
0
void bl_do_peer_delete (struct tgl_state *TLS, tgl_peer_id_t id) /* {{{ */ {
  tgl_peer_t *P = tgl_peer_get (TLS, id);
  if (!P || !(P->flags & TGLPF_CREATED)) { return; }

  if (P->flags & TGLPF_DELETED) { return; }
  P->flags |= TGLPF_DELETED;

  switch (id.peer_type) {
  case TGL_PEER_USER:
    if (TLS->callback.user_update) {
      TLS->callback.user_update (TLS, (void *)P, TGL_UPDATE_DELETED);
    }
    break;
  case TGL_PEER_CHAT:
    if (TLS->callback.chat_update) {
      TLS->callback.chat_update (TLS, (void *)P, TGL_UPDATE_DELETED);
    }
    break;
  case TGL_PEER_ENCR_CHAT:
    if (TLS->callback.secret_chat_update) {
      TLS->callback.secret_chat_update (TLS, (void *)P, TGL_UPDATE_DELETED);
    }
    break;
  case TGL_PEER_CHANNEL:
    if (TLS->callback.channel_update) {
      TLS->callback.channel_update (TLS, (void *)P, TGL_UPDATE_DELETED);
    }
    break;
  default:
    assert (0);
  }
}
Пример #8
0
json_t *json_pack_message (struct tgl_message *M) {  
  json_t *res = json_object ();
  assert (json_object_set (res, "event", json_string ("message")) >= 0);
  //will overwriten to service, if service.

  assert (json_object_set (res, "id", json_integer (M->id)) >= 0);
  if (!(M->flags & TGLMF_CREATED)) { return res; }

  assert (json_object_set (res, "flags", json_integer (M->flags)) >= 0);
 
  if (tgl_get_peer_type (M->fwd_from_id)) {
    assert (json_object_set (res, "fwd_from", json_pack_peer (M->fwd_from_id, tgl_peer_get (TLS, M->fwd_from_id))) >= 0);
    assert (json_object_set (res, "fwd_date", json_integer (M->fwd_date)) >= 0);
  }

  if (M->reply_id) {
    assert (json_object_set (res, "reply_id", json_integer (M->reply_id)) >= 0);
  }

  if (M->flags & TGLMF_MENTION) {
    assert (json_object_set (res, "mention", json_true ()) >= 0);
  }
 
  assert (json_object_set (res, "from", json_pack_peer (M->from_id, tgl_peer_get (TLS, M->from_id))) >= 0);
  assert (json_object_set (res, "to", json_pack_peer (M->to_id, tgl_peer_get (TLS, M->to_id))) >= 0);
  
  assert (json_object_set (res, "out", json_boolean (M->flags & TGLMF_OUT)) >= 0);
  assert (json_object_set (res, "unread", json_boolean (M->flags & TGLMF_UNREAD)) >= 0);
  assert (json_object_set (res, "service", json_boolean (M->flags & TGLMF_SERVICE)) >= 0);
  assert (json_object_set (res, "date", json_integer (M->date)) >= 0);
  
  if (!(M->flags & TGLMF_SERVICE)) {  
    if (M->message_len && M->message) {
      assert (json_object_set (res, "text", json_string (M->message)) >= 0);
    }
    if (M->media.type && M->media.type != tgl_message_media_none) {
      assert (json_object_set (res, "media", json_pack_media (&M->media)) >= 0);
    }
  } else {
    assert (json_object_set (res, "event", json_string ("service")) >= 0);
    assert (json_object_set (res, "action", json_pack_service (M)) >= 0);
  }
  return res;
}
Пример #9
0
void tgprpl_chat_join (PurpleConnection *gc, GHashTable *data) {
  debug ("tgprpl_chat_join()");
  g_return_if_fail(data);
  
  // auto joins will cause chat joins at a time when the dialogue list is not ready, remember
  // those chats and join them once the dialogue list is fetched
  if (! gc_get_data (gc)->dialogues_ready) {
    g_return_if_fail (data);
    const char *id = g_hash_table_lookup (data, "id");
    if (id) {
      debug ("attempting to join chat %s while not ready, queue up for later", id);
      gc_get_data (gc)->pending_joins = g_list_append (gc_get_data (gc)->pending_joins, g_strdup (id));
    }
    return;
  }

  // join existing chat by id when the user clicks on a chat in the buddy list
  void *value = g_hash_table_lookup (data, "id");
  if (value && atoi (value)) {
    tgl_peer_id_t cid = TGL_MK_CHAT(atoi (value));
    tgl_peer_t *P = tgl_peer_get (gc_get_tls (gc), cid);
    if (P) {
      debug ("joining chat by id %d ...", tgl_get_peer_id (cid));
      tgl_do_get_chat_info (gc_get_tls (gc), cid, FALSE, tgp_chat_on_loaded_chat_full_joining, NULL);
    } else {
      warning ("Cannot join chat %d, peer not found...", tgl_get_peer_id (cid));
      purple_serv_got_join_chat_failed (gc, data);
    }
    return;
  }
  
  // join chat by invite link provided in the chat join window
  const char *link = g_hash_table_lookup (data, "link");
  if (str_not_empty (link)) {
    tgl_do_import_chat_link (gc_get_tls (gc), link, (int)strlen (link), tgp_notify_on_error_gw, NULL);
    return;
  }
  
  // if a chat with this name doesn't exist yet, prompt to create one
  const char *subject = g_hash_table_lookup (data, "subject");
  if (str_not_empty (subject)) {
    tgl_peer_t *P = tgl_peer_get_by_name (gc_get_tls (gc), subject);
    
    // handle joining chats by print_names as used by the Adium plugin
    if (P && tgl_get_peer_type (P->id) == TGL_PEER_CHAT) {
      debug ("joining chat by subject %s ...", subject);
      
      tgl_do_get_chat_info (gc_get_tls (gc), P->id, FALSE, tgp_chat_on_loaded_chat_full_joining, NULL);
      return;
    }
    
    // user creates a new chat by providing its subject the chat join window
    request_create_chat (gc_get_tls (gc), subject);
  }
}
Пример #10
0
static unsigned int tgprpl_send_typing (PurpleConnection * gc, const char *who, PurpleTypingState typing) {
  debug ("tgprpl_send_typing()\n");
  int id = atoi (who);
  telegram_conn *conn = purple_connection_get_protocol_data(gc);
  tgl_peer_t *U = tgl_peer_get (conn->TLS, TGL_MK_USER (id));
  if (U) {
    if (typing == PURPLE_TYPING) {
      tgl_do_send_typing (conn->TLS, U->id, tgl_typing_typing, 0, 0);
    } else {
      tgl_do_send_typing (conn->TLS, U->id, tgl_typing_cancel, 0, 0);
    }
  }
  return 0;
}
Пример #11
0
Файл: loop.c Проект: AmesianX/tg
void read_secret_chat (int fd, int v) {
  int id, l, user_id, admin_id, date, ttl, layer, state;
  long long access_hash, key_fingerprint;
  static char s[1000];
  static unsigned char key[256];
  static unsigned char sha[20];
  assert (read (fd, &id, 4) == 4);
  //assert (read (fd, &flags, 4) == 4);
  assert (read (fd, &l, 4) == 4);
  assert (l > 0 && l < 1000);
  assert (read (fd, s, l) == l);
  assert (read (fd, &user_id, 4) == 4);
  assert (read (fd, &admin_id, 4) == 4);
  assert (read (fd, &date, 4) == 4);
  assert (read (fd, &ttl, 4) == 4);
  assert (read (fd, &layer, 4) == 4);
  assert (read (fd, &access_hash, 8) == 8);
  assert (read (fd, &state, 4) == 4);
  assert (read (fd, &key_fingerprint, 8) == 8);
  assert (read (fd, &key, 256) == 256);
  if (v >= 2) {
    assert (read (fd, sha, 20) == 20);
  }
  int in_seq_no = 0, out_seq_no = 0, last_in_seq_no = 0;
  if (v >= 1) {
    assert (read (fd, &in_seq_no, 4) == 4);
    assert (read (fd, &last_in_seq_no, 4) == 4);
    assert (read (fd, &out_seq_no, 4) == 4);
  }

  bl_do_encr_chat_create (TLS, id, user_id, admin_id, s, l);
  struct tgl_secret_chat  *P = (void *)tgl_peer_get (TLS, TGL_MK_ENCR_CHAT (id));
  assert (P && (P->flags & FLAG_CREATED));
  bl_do_encr_chat_set_date (TLS, P, date);
  bl_do_encr_chat_set_ttl (TLS, P, ttl);
  bl_do_encr_chat_set_layer (TLS ,P, layer);
  bl_do_encr_chat_set_access_hash (TLS, P, access_hash);
  bl_do_encr_chat_set_state (TLS, P, state);
  bl_do_encr_chat_set_key (TLS, P, key, key_fingerprint);
  if (v >= 2) {
    bl_do_encr_chat_set_sha (TLS, P, sha);
  } else {
    SHA1 ((void *)key, 256, sha);
    bl_do_encr_chat_set_sha (TLS, P, sha);
  }
  if (v >= 1) {
    bl_do_encr_chat_set_seq (TLS, P, in_seq_no, last_in_seq_no, out_seq_no);
  }
}
Пример #12
0
void bl_do_encr_chat_exchange (struct tgl_state *TLS, tgl_peer_id_t id, long long *exchange_id, const void *key, int *state) /* {{{ */ {
  tgl_peer_t *P = tgl_peer_get (TLS, id);
  if (!P) { return; }
  
  if (state) {
    P->encr_chat.exchange_state = *state;
  }
  if (exchange_id) {
    P->encr_chat.exchange_id = *exchange_id;
  }

  static unsigned char sha_buffer[20];
  switch (P->encr_chat.exchange_state) {
  case tgl_sce_requested:
    memcpy (P->encr_chat.exchange_key, key, 256);
    break;
  case tgl_sce_accepted:
    memcpy (P->encr_chat.exchange_key, key, 256);
  
    TGLC_sha1 ((unsigned char *)P->encr_chat.exchange_key, 256, sha_buffer);
    P->encr_chat.exchange_key_fingerprint = *(long long *)(sha_buffer + 12);
    break;
  case tgl_sce_committed:
    memcpy (P->encr_chat.exchange_key, P->encr_chat.key, 256);
    P->encr_chat.exchange_key_fingerprint = P->encr_chat.key_fingerprint;

    memcpy (P->encr_chat.key, key, 256);
  
    TGLC_sha1 ((unsigned char *)P->encr_chat.key, 256, sha_buffer);
    P->encr_chat.key_fingerprint = *(long long *)(sha_buffer + 12);
    break;
  case tgl_sce_confirmed:
    P->encr_chat.exchange_state = tgl_sce_none;
    if (P->encr_chat.exchange_state != tgl_sce_committed) {
      memcpy (P->encr_chat.key, P->encr_chat.exchange_key, 256);
      P->encr_chat.key_fingerprint = P->encr_chat.exchange_key_fingerprint;
    }
    break;
  case tgl_sce_aborted:
    P->encr_chat.exchange_state = tgl_sce_none;
    if (P->encr_chat.exchange_state == tgl_sce_committed) {
      memcpy (P->encr_chat.key, P->encr_chat.exchange_key, 256);
      P->encr_chat.key_fingerprint = P->encr_chat.exchange_key_fingerprint;
    }
    break;
  default:
    assert (0);
  }
}
Пример #13
0
tgl_peer_t *tgp_blist_peer_find (struct tgl_state *TLS, const char *purple_name) {
  // buddies will keep the name they had when they were first added to the user list. The print_name
  // of the peer may have changed since then, therefore the ID stored in the buddy is used to fetch
  // the user name.
  PurpleBuddy *buddy = purple_find_buddy (tg_get_acc (TLS), purple_name);
  if (! buddy) {
    // foreign users are not in the buddy list by default, therefore the name used by libpurple and the
    // print name is always identical
    return tgl_peer_get_by_name (TLS, purple_name);
  }
  if (! tgp_blist_buddy_has_id (buddy)) {
    return NULL;
  }
  return tgl_peer_get (TLS, tgp_blist_buddy_get_id (buddy));
}
Пример #14
0
void tgl_do_send_encr_msg (struct tgl_state *TLS, struct tgl_message *M, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, struct tgl_message *M), void *callback_extra) {
  if (M->flags & TGLMF_SERVICE) {
    tgl_do_send_encr_msg_action (TLS, M, callback, callback_extra);
    return;
  }
  tgl_peer_t *P = tgl_peer_get (TLS, M->to_id);
  if (!P || P->encr_chat.state != sc_ok) { 
    vlogprintf (E_WARNING, "Unknown encrypted chat\n");
    if (callback) {
      callback (TLS, callback_extra, 0, M);
    }
    return;
  }
  
  assert (M->flags & TGLMF_ENCRYPTED);

  clear_packet ();
  out_int (CODE_messages_send_encrypted);
  out_int (CODE_input_encrypted_chat);
  out_int (tgl_get_peer_id (M->to_id));
  out_long (P->encr_chat.access_hash);
  out_long (M->id);
  encr_start ();
  out_int (CODE_decrypted_message_layer);
  out_random (15 + 4 * (lrand48 () % 3));
  out_int (TGL_ENCRYPTED_LAYER);
  out_int (2 * P->encr_chat.in_seq_no + (P->encr_chat.admin_id != TLS->our_id));
  out_int (2 * P->encr_chat.out_seq_no + (P->encr_chat.admin_id == TLS->our_id) - 2);
  out_int (CODE_decrypted_message);
  out_long (M->id);
  out_int (P->encr_chat.ttl);
  out_cstring ((void *)M->message, M->message_len);
  switch (M->media.type) {
  case tgl_message_media_none:
    out_int (CODE_decrypted_message_media_empty);
    break;
  case tgl_message_media_geo:
    out_int (CODE_decrypted_message_media_geo_point);
    out_double (M->media.geo.latitude);
    out_double (M->media.geo.longitude);
    break;
  default:
    assert (0);
  }
  encr_finish (&P->encr_chat);
  
  tglq_send_query (TLS, TLS->DC_working, packet_ptr - packet_buffer, packet_buffer, &msg_send_encr_methods, M, callback, callback_extra);
}
Пример #15
0
static int msg_send_encr_on_error (struct tgl_state *TLS, struct query *q, int error_code, int error_len, const char *error) {
  struct tgl_message *M = q->extra;
  tgl_peer_t *P = tgl_peer_get (TLS, M->to_id);
  if (P && P->encr_chat.state != sc_deleted && error_code == 400) {
    if (strncmp (error, "ENCRYPTION_DECLINED", 19) == 0) {
      bl_do_encr_chat_delete (TLS, &P->encr_chat);
    }
  }
  if (q->callback) {
    ((void (*)(struct tgl_state *TLS, void *, int, struct tgl_message *))q->callback) (TLS, q->callback_extra, 0, M);
  }
  if (M) {
    bl_do_message_delete (TLS, M);
  }
  return 0;
}
Пример #16
0
static void tgprpl_tooltip_text (PurpleBuddy * buddy, PurpleNotifyUserInfo * info, gboolean full) {
  debug ("tgprpl_tooltip_text()\n", buddy->name);
  
  tgl_peer_id_t *peer = purple_buddy_get_protocol_data(buddy);
  if (!peer) {
    purple_notify_user_info_add_pair_plaintext(info, "Status", "Offline");
    return;
  }
  tgl_peer_t *P = tgl_peer_get (get_conn_from_buddy (buddy)->TLS, *peer);
  if (!P) {
    warning ("tgprpl_tooltip_text: warning peer with id %d not found in tree.\n", peer->id);
    return;
  }
  purple_notify_user_info_add_pair_plaintext (info, "Status", format_status(&P->user.status));
  purple_notify_user_info_add_pair_plaintext (info, "Last seen: ", format_time(P->user.status.when));
}
Пример #17
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;
}
Пример #18
0
void json_pack_chat (json_t *res, tgl_peer_t *P) {
  assert (P->chat.title);
  assert (json_object_set (res, "title", json_string (P->chat.title)) >= 0);
  assert (json_object_set (res, "members_num", json_integer (P->chat.users_num)) >= 0);

  if (P->chat.user_list) {
    json_t *m = json_array ();
    assert (m);

    int i;
    for (i = 0; i < P->chat.users_num; i++) {
      tgl_peer_id_t id = TGL_MK_USER (P->chat.user_list[i].user_id);
      assert (json_array_append (m, json_pack_peer (id, tgl_peer_get (TLS, id))) >= 0);
    }

    assert (json_object_set (res, "members", m) >= 0);
  }
}
Пример #19
0
void tgprpl_chat_join (PurpleConnection * gc, GHashTable *data) {
  debug ("tgprpl_chat_join()");
  connection_data *conn = purple_connection_get_protocol_data (gc);
  
  // join existing chat by id when the user clicks on a chat in the buddy list
  void *value = g_hash_table_lookup (data, "id");
  if (value && atoi (value)) {
    tgl_peer_id_t cid = TGL_MK_CHAT(atoi (value));
    tgl_peer_t *P = tgl_peer_get (conn->TLS, cid);
    if (P) {
      debug ("joining chat by id %d ...", tgl_get_peer_id (cid));
      tgl_do_get_chat_info (conn->TLS, cid, FALSE, tgp_chat_on_loaded_chat_full_joining, NULL);
    } else {
      warning ("Cannot join chat %d, peer not found...", tgl_get_peer_id (cid));
      purple_serv_got_join_chat_failed (gc, data);
    }
    return;
  }
  
  // join chat by invite link provided in the chat join window
  const char *link = g_hash_table_lookup (data, "link");
  if (str_not_empty (link)) {
    tgl_do_import_chat_link (conn->TLS, link, (int)strlen (link), tgp_notify_on_error_gw, NULL);
    return;
  }
  
  // if a chat with this name doesn't exist yet, prompt to create one
  const char *subject = g_hash_table_lookup (data, "subject");
  if (str_not_empty (subject)) {
    tgl_peer_t *P = tgl_peer_get_by_name (conn->TLS, subject);
    
    // handle joining chats by print_names as used by the Adium plugin
    if (P && tgl_get_peer_type (P->id) == TGL_PEER_CHAT) {
      debug ("joining chat by subject %s ...", subject);
      
      tgl_do_get_chat_info (conn->TLS, P->id, FALSE, tgp_chat_on_loaded_chat_full_joining, NULL);
      return;
    }
    
    // user creates a new chat by providing its subject the chat join window
    request_create_chat (conn->TLS, subject);
  }
}
Пример #20
0
static void tgp_chat_add_all_users (struct tgl_state *TLS, PurpleConversation *conv, struct tgl_chat *C) {
  GList *users = NULL,
        *flags = NULL;
  
  int i = 0;
  for (; i < C->user_list_size; i++) {
    struct tgl_chat_user *uid = (C->user_list + i);
    users = g_list_append (users, g_strdup_printf ("%d", uid->user_id));
    flags = g_list_append (flags, GINT_TO_POINTER(C->admin_id == uid->user_id ? PURPLE_CBFLAGS_FOUNDER : PURPLE_CBFLAGS_NONE));
  }
  
  purple_conv_chat_add_users (PURPLE_CONV_CHAT(conv), users, NULL, flags, FALSE);
  while (users) {
    p2tgl_conv_add_user_rename (tgl_peer_get (TLS, TGL_MK_USER(atoi (users->data))), conv);
    users = g_list_next (users);
  }
  
  g_list_free_full (users, g_free);
  g_list_free (flags);
}
Пример #21
0
void py_dialog_list_cb (struct tgl_state *TLSR, void *cb_extra, int success, int num, tgl_peer_id_t peers[], int msgs[], int unread[]) {
    assert (TLSR == TLS);
    PyObject *callable = cb_extra;
    PyObject *arglist = NULL;
    PyObject *dialog_list = NULL;
    PyObject *dialog = NULL;
    PyObject *result = NULL;

    if(PyCallable_Check(callable)) {
        dialog_list = PyList_New(0);
        if (success) {
            int i;
            for (i = 0; i < num; i++) {
                dialog = PyDict_New();
                PyDict_SetItemString(dialog, "peer", get_peer(peers[i], tgl_peer_get (TLS, peers[i])));

                struct tgl_message *M = tgl_message_get (TLS, msgs[i]);
                if (M && (M->flags & TGLMF_CREATED)) {
                    PyDict_SetItemString(dialog, "message", get_message(M));
                }
                PyDict_SetItemString(dialog, "unread", unread[i] ? Py_True : Py_False);

                PyList_Append(dialog_list, dialog);
            }
        }

        arglist = Py_BuildValue("(OO)", success ? Py_True : Py_False, dialog_list);
        result = PyEval_CallObject(callable, arglist);
        Py_DECREF(arglist);

        if(result == NULL)
            PyErr_Print();

        Py_XDECREF(result);
    }

    Py_XDECREF(callable);
}
Пример #22
0
static char *format_service_msg (struct tgl_state *TLS, struct tgl_message *M)
{
  assert (M && M->service);

  char *txt_user = NULL;
  char *txt_action = NULL;
  char *txt = NULL;
  
  tgl_peer_t *peer = tgl_peer_get (TLS, M->from_id);
  if (! peer) {
    return NULL;
  }
  txt_user = p2tgl_strdup_alias (peer);
  
  switch (M->action.type) {
    case tgl_message_action_chat_create:
      txt_action = g_strdup_printf ("created chat %s", M->action.title);
      break;
    case tgl_message_action_chat_edit_title:
      txt_action = g_strdup_printf ("changed title to %s", M->action.new_title);
      break;
    case tgl_message_action_chat_edit_photo:
      txt_action = g_strdup ("changed photo");
      break;
    case tgl_message_action_chat_delete_photo:
      txt_action = g_strdup ("deleted photo");
      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 = p2tgl_strdup_alias (peer);
          txt_action = g_strdup_printf ("added user %s", alias);
          g_free (alias);
        }
        break;
      }
    case tgl_message_action_chat_delete_user:
      {
        tgl_peer_t *peer = tgl_peer_get (TLS, TGL_MK_USER (M->action.user));
        if (peer) {
          char *alias = p2tgl_strdup_alias (peer);
          txt_action = g_strdup_printf ("deleted user %s", alias);
          g_free (alias);
        }
        break;
      }
    case tgl_message_action_set_message_ttl:
      txt_action = g_strdup_printf ("set ttl to %d seconds", M->action.ttl);
      break;
    case tgl_message_action_read_messages:
      txt_action = g_strdup_printf ("%d messages marked read", M->action.read_cnt);
      break;
    case tgl_message_action_delete_messages:
      txt_action = g_strdup_printf ("%d messages deleted", M->action.delete_cnt);
      break;
    case tgl_message_action_screenshot_messages:
      txt_action = g_strdup_printf ("%d messages screenshoted", M->action.screenshot_cnt);
      break;
    case tgl_message_action_notify_layer:
      txt_action = g_strdup_printf ("updated layer to %d", M->action.layer);
      break;
      /*
    case tgl_message_action_request_key:
      txt_action = g_strdup_printf ("Request rekey #%016llx\n", M->action.exchange_id);
      break;
    case tgl_message_action_accept_key:
      txt_action = g_strdup_printf ("Accept rekey #%016llx\n", M->action.exchange_id);
      break;
    case tgl_message_action_commit_key:
      txt_action = g_strdup_printf ("Commit rekey #%016llx\n", M->action.exchange_id);
      break;
    case tgl_message_action_abort_key:
      txt_action = g_strdup_printf ("Abort rekey #%016llx\n", M->action.exchange_id);
      break;
      */
    default:
      txt_action = NULL;
      break;
  }
  if (txt_action) {
    debug ("SERVICE MESSAGE: %s", txt_action);
    txt = g_strdup_printf ("%s %s.", txt_user, txt_action);
    g_free (txt_action);
  }
  g_free (txt_user);
  return txt;
}
Пример #23
0
tgl_peer_t *tgp_blist_buddy_get_peer (PurpleBuddy *buddy) {
  if (! tgp_blist_buddy_has_id (buddy)) {
    return NULL;
  }
  return tgl_peer_get (pbn_get_conn (&buddy->node)->TLS, tgp_blist_buddy_get_id (buddy));
}
Пример #24
0
void json_pack_encr_chat (json_t *res, tgl_peer_t *P) {
  assert (json_object_set (res, "user", json_pack_peer (TGL_MK_USER (P->encr_chat.user_id), tgl_peer_get (TLS, TGL_MK_USER (P->encr_chat.user_id)))) >= 0);
}
Пример #25
0
void tgl_do_send_create_encr_chat (struct tgl_state *TLS, void *x, unsigned char *random, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, struct tgl_secret_chat *E), void *callback_extra) {
  int user_id = (long)x;
  int i;
  unsigned char random_here[256];
  tglt_secure_random (random_here, 256);
  for (i = 0; i < 256; i++) {
    random[i] ^= random_here[i];
  }
  BIGNUM *a = BN_bin2bn (random, 256, 0);
  ensure_ptr (a);
  BIGNUM *p = BN_bin2bn (TLS->encr_prime, 256, 0); 
  ensure_ptr (p);
 
  BIGNUM *g = BN_new ();
  ensure_ptr (g);

  ensure (BN_set_word (g, TLS->encr_root));

  BIGNUM *r = BN_new ();
  ensure_ptr (r);

  ensure (BN_mod_exp (r, g, a, p, TLS->BN_ctx));

  BN_clear_free (a);

  static char g_a[256];
  memset (g_a, 0, 256);

  BN_bn2bin (r, (void *)(g_a + (256 - BN_num_bytes (r))));
  
  int t = lrand48 ();
  while (tgl_peer_get (TLS, TGL_MK_ENCR_CHAT (t))) {
    t = lrand48 ();
  }

  //bl_do_encr_chat_init (TLS, t, user_id, (void *)random, (void *)g_a);
  
  int state = sc_waiting;
  bl_do_encr_chat_new (TLS, t, NULL, NULL, &TLS->our_id, &user_id, random, NULL, NULL, &state, NULL, NULL, NULL, NULL, NULL, NULL, TGLPF_CREATE | TGLPF_CREATED);

  
  tgl_peer_t *_E = tgl_peer_get (TLS, TGL_MK_ENCR_CHAT (t));
  assert (_E);
  struct tgl_secret_chat *E = &_E->encr_chat;
  
  clear_packet ();
  out_int (CODE_messages_request_encryption);
  tgl_peer_t *U = tgl_peer_get (TLS, TGL_MK_USER (E->user_id));
  assert (U);
  if (U && U->user.access_hash) {
    out_int (CODE_input_user_foreign);
    out_int (E->user_id);
    out_long (U->user.access_hash);
  } else {
    out_int (CODE_input_user_contact);
    out_int (E->user_id);
  }
  out_int (tgl_get_peer_id (E->id));
  out_cstring (g_a, 256);
  //write_secret_chat_file ();
  
  BN_clear_free (g);
  BN_clear_free (p);
  BN_clear_free (r);

  tglq_send_query (TLS, TLS->DC_working, packet_ptr - packet_buffer, packet_buffer, &send_encr_request_methods, E, callback, callback_extra);
}
Пример #26
0
static void send_file_encrypted_end (struct tgl_state *TLS, struct send_file *f, void *callback, void *callback_extra) {
  out_int (CODE_messages_send_encrypted_file);
  out_int (CODE_input_encrypted_chat);
  out_int (tgl_get_peer_id (f->to_id));
  tgl_peer_t *P = tgl_peer_get (TLS, f->to_id);
  assert (P);
  out_long (P->encr_chat.access_hash);
  long long r;
  tglt_secure_random (&r, 8);
  out_long (r);
  encr_start ();
  out_int (CODE_decrypted_message_layer);
  out_random (15 + 4 * (lrand48 () % 3));
  out_int (TGL_ENCRYPTED_LAYER);
  out_int (2 * P->encr_chat.in_seq_no + (P->encr_chat.admin_id != TLS->our_id));
  out_int (2 * P->encr_chat.out_seq_no + (P->encr_chat.admin_id == TLS->our_id));
  out_int (CODE_decrypted_message);
  out_long (r);
  out_int (P->encr_chat.ttl);
  out_string ("");
  int *save_ptr = packet_ptr;
  if (f->flags == -1) {
    out_int (CODE_decrypted_message_media_photo);
  } else if ((f->flags & TGLDF_VIDEO)) {
    out_int (CODE_decrypted_message_media_video);
  } else if ((f->flags & TGLDF_AUDIO)) {
    out_int (CODE_decrypted_message_media_audio);
  } else {
    out_int (CODE_decrypted_message_media_document);
  }
  if (f->flags == -1 || !(f->flags & TGLDF_AUDIO)) {
    out_cstring ("", 0);
    out_int (90);
    out_int (90);
  }
  
  if (f->flags == -1) {
    out_int (f->w);
    out_int (f->h);
  } else if (f->flags & TGLDF_VIDEO) {
    out_int (f->duration);
    out_string (tg_mime_by_filename (f->file_name));
    out_int (f->w);
    out_int (f->h);
  } else if (f->flags & TGLDF_AUDIO) {
    out_int (f->duration);
    out_string (tg_mime_by_filename (f->file_name));
  } else {
    out_string ("");
    out_string (tg_mime_by_filename (f->file_name));
    // document
  }
  
  out_int (f->size);
  out_cstring ((void *)f->key, 32);
  out_cstring ((void *)f->init_iv, 32);
 
  int *save_in_ptr = in_ptr;
  int *save_in_end = in_end;

  in_ptr = save_ptr;
  in_end = packet_ptr;

  assert (skip_type_any (TYPE_TO_PARAM(decrypted_message_media)) >= 0);
  assert (in_ptr == in_end);
  
  in_ptr = save_ptr;
  in_end = packet_ptr;
  
  struct tl_ds_decrypted_message_media *DS_DMM = fetch_ds_type_decrypted_message_media (TYPE_TO_PARAM (decrypted_message_media));
  in_end = save_in_ptr;
  in_ptr = save_in_end;


  int peer_type = tgl_get_peer_type (f->to_id);
  int peer_id = tgl_get_peer_id (f->to_id);
  int date = time (NULL);


  encr_finish (&P->encr_chat);
  if (f->size < (16 << 20)) {
    out_int (CODE_input_encrypted_file_uploaded);
  } else {
    out_int (CODE_input_encrypted_file_big_uploaded);
  }
  out_long (f->id);
  out_int (f->part_num);
  if (f->size < (16 << 20)) {
    out_string ("");
  }

  unsigned char md5[16];
  unsigned char str[64];
  memcpy (str, f->key, 32);
  memcpy (str + 32, f->init_iv, 32);
  MD5 (str, 64, md5);
  out_int ((*(int *)md5) ^ (*(int *)(md5 + 4)));

  tfree_secure (f->iv, 32);
  
  bl_do_create_message_encr_new (TLS, r, &TLS->our_id, &peer_type, &peer_id, &date, NULL, 0, DS_DMM, NULL, NULL, TGLMF_OUT | TGLMF_UNREAD | TGLMF_ENCRYPTED | TGLMF_CREATE | TGLMF_CREATED);

  free_ds_type_decrypted_message_media (DS_DMM, TYPE_TO_PARAM (decrypted_message_media));
  struct tgl_message *M = tgl_message_get (TLS, r);
  assert (M);
      
  tglq_send_query (TLS, TLS->DC_working, packet_ptr - packet_buffer, packet_buffer, &send_encr_file_methods, M, callback, callback_extra);
  
  tfree_str (f->file_name);
  tfree (f, sizeof (*f));

}
Пример #27
0
void tgl_do_messages_mark_read_encr (struct tgl_state *TLS, tgl_peer_id_t id, long long access_hash, int last_time, void (*callback)(struct tgl_state *TLS, void *callback_extra, int), void *callback_extra) {
  clear_packet ();
  out_int (CODE_messages_read_encrypted_history);
  out_int (CODE_input_encrypted_chat);
  out_int (tgl_get_peer_id (id));
  out_long (access_hash);
  out_int (last_time);
  tglq_send_query (TLS, TLS->DC_working, packet_ptr - packet_buffer, packet_buffer, &mark_read_encr_methods, tgl_peer_get (TLS, id), callback, callback_extra);
}
Пример #28
0
int loop (void) {
  tgl_set_callback (TLS, &upd_cb);
  struct event_base *ev = event_base_new ();
  tgl_set_ev_base (TLS, ev);
  tgl_set_net_methods (TLS, &tgl_conn_methods);
  tgl_set_timer_methods (TLS, &tgl_libevent_timers);
  assert (TLS->timer_methods);
  tgl_set_download_directory (TLS, get_downloads_directory ());
  tgl_register_app_id (TLS, TELEGRAM_CLI_APP_ID, TELEGRAM_CLI_APP_HASH); 
  tgl_set_app_version (TLS, "Telegram-cli " TELEGRAM_CLI_VERSION);
  if (ipv6_enabled) {
    tgl_enable_ipv6 (TLS);
  }
  if (bot_mode) {
    tgl_enable_bot (TLS);
  }
  if (disable_link_preview) {
    tgl_disable_link_preview (TLS);
  }
  assert (tgl_init (TLS) >= 0);
 
  /*if (binlog_enabled) {
    double t = tglt_get_double_time ();
    if (verbosity >= E_DEBUG) {
      logprintf ("replay log start\n");
    }
    tgl_replay_log (TLS);
    if (verbosity >= E_DEBUG) {
      logprintf ("replay log end in %lf seconds\n", tglt_get_double_time () - t);
    }
    tgl_reopen_binlog_for_writing (TLS);
  } else {*/
    read_auth_file ();
    read_state_file ();
    read_secret_chat_file ();
  //}

  binlog_read = 1;
  #ifdef USE_LUA
    lua_binlog_end ();
  #endif
  
  #ifdef USE_PYTHON
    py_binlog_end ();
  #endif
  
  if (sfd >= 0) {
    struct event *ev = event_new (TLS->ev_base, sfd, EV_READ | EV_PERSIST, accept_incoming, 0);
    event_add (ev, 0);
  }
  if (usfd >= 0) {
    struct event *ev = event_new (TLS->ev_base, usfd, EV_READ | EV_PERSIST, accept_incoming, 0);
    event_add (ev, 0);
  }
  update_prompt ();
   
  if (reset_authorization) {
    tgl_peer_t *P = tgl_peer_get (TLS, TLS->our_id);
    if (P && P->user.phone && reset_authorization == 1) {
      set_default_username (P->user.phone);
    }
    bl_do_reset_authorization (TLS);
  }

  set_interface_callbacks ();
  tgl_login (TLS);
  net_loop ();
  return 0;
}
Пример #29
0
void tgl_do_send_encr_msg_action (struct tgl_state *TLS, struct tgl_message *M, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, struct tgl_message *M), void *callback_extra) {
  tgl_peer_t *P = tgl_peer_get (TLS, M->to_id);
  if (!P || P->encr_chat.state != sc_ok) { 
    vlogprintf (E_WARNING, "Unknown encrypted chat\n");
    if (callback) {
      callback (TLS, callback_extra, 0, 0);
    }
    return;
  }
 
  assert (M->flags & TGLMF_ENCRYPTED);
  clear_packet ();
  out_int (CODE_messages_send_encrypted_service);
  out_int (CODE_input_encrypted_chat);
  out_int (tgl_get_peer_id (M->to_id));
  out_long (P->encr_chat.access_hash);
  out_long (M->id);
  encr_start ();
  out_int (CODE_decrypted_message_layer);
  out_random (15 + 4 * (lrand48 () % 3));
  out_int (TGL_ENCRYPTED_LAYER);
  out_int (2 * P->encr_chat.in_seq_no + (P->encr_chat.admin_id != TLS->our_id));
  out_int (2 * P->encr_chat.out_seq_no + (P->encr_chat.admin_id == TLS->our_id) - 2);
  out_int (CODE_decrypted_message_service);
  out_long (M->id);

  switch (M->action.type) {
  case tgl_message_action_notify_layer:
    out_int (CODE_decrypted_message_action_notify_layer);
    out_int (M->action.layer);
    break;
  case tgl_message_action_set_message_ttl:
    out_int (CODE_decrypted_message_action_set_message_t_t_l);
    out_int (M->action.ttl);
    break;
  case tgl_message_action_request_key:
    out_int (CODE_decrypted_message_action_request_key);
    out_long (M->action.exchange_id);
    out_cstring ((void *)M->action.g_a, 256);
    break;
  case tgl_message_action_accept_key:
    out_int (CODE_decrypted_message_action_accept_key);
    out_long (M->action.exchange_id);
    out_cstring ((void *)M->action.g_a, 256);    
    out_long (M->action.key_fingerprint);
    break;
  case tgl_message_action_commit_key:
    out_int (CODE_decrypted_message_action_commit_key);
    out_long (M->action.exchange_id);
    out_long (M->action.key_fingerprint);
    break;
  case tgl_message_action_abort_key:
    out_int (CODE_decrypted_message_action_abort_key);
    out_long (M->action.exchange_id);
    break;
  case tgl_message_action_noop:
    out_int (CODE_decrypted_message_action_noop);
    break;
  default:
    assert (0);
  }
  encr_finish (&P->encr_chat);
  
  tglq_send_query (TLS, TLS->DC_working, packet_ptr - packet_buffer, packet_buffer, &msg_send_encr_methods, M, callback, callback_extra);
}
Пример #30
0
static void tgp_msg_display (struct tgl_state *TLS, struct tgp_msg_loading *C) {
  connection_data *conn = TLS->ev_base;
  struct tgl_message *M = C->msg;
  char *text = NULL;
  int flags = 0;

  // only display new messages, ignore updates or deletions
  if ((M->flags & (TGLMF_EMPTY | TGLMF_DELETED)) ||
      !(M->flags & TGLMF_CREATED) ||
      !M->message ||
      tgp_outgoing_msg (TLS, M) ||
      !tgl_get_peer_type (M->to_id)) {
    return;
  }

  if (M->flags & TGLMF_SERVICE) {
    text = format_service_msg (TLS, M);
    flags |= PURPLE_MESSAGE_SYSTEM;
  }
  else if (M->media.type == tgl_message_media_document && M->media.document->flags & TGLDF_STICKER) {
#ifdef HAVE_LIBWEBP
    char *filename = C->data;
    int img = p2tgl_imgstore_add_with_id_webp (filename);
    if (img <= 0) { failure ("Cannot display sticker, adding to imgstore failed"); return; }
    used_images_add (conn, img);
    text = format_img_full (img);
    flags |= PURPLE_MESSAGE_IMAGES;
    g_free (filename);
#else
    char *txt_user = p2tgl_strdup_alias (tgl_peer_get (TLS, M->from_id));
    text = g_strdup_printf ("%s sent a sticker", txt_user);
    flags |= PURPLE_MESSAGE_SYSTEM;
    g_free (txt_user);
#endif
  }
  else if (M->media.type == tgl_message_media_photo ||
          (M->media.type == tgl_message_media_document_encr && M->media.encr_document->flags & TGLDF_IMAGE)) {
    char *filename = C->data;
    int img = p2tgl_imgstore_add_with_id (filename);
    if (img <= 0) {
      failure ("Cannot display picture message, adding to imgstore failed.");
      return;
    }
    used_images_add (conn, img);
    text = format_img_full (img);
    flags |= PURPLE_MESSAGE_IMAGES;
    g_free (filename);
  }
  else if (M->media.type == tgl_message_media_document) {
    char *who = p2tgl_strdup_id (M->from_id);
    if (! tgp_our_msg(TLS, M)) {
      tgprpl_recv_file (conn->gc, who, M->media.document);
    }
    g_free (who);
    return;
  }
  else if (M->media.type == tgl_message_media_document_encr) {
    char *who = p2tgl_strdup_id (M->to_id);
    if (! tgp_our_msg(TLS, M)) {
      tgprpl_recv_encr_file (conn->gc, who, M->media.encr_document);
    }
    g_free (who);
    return;
  }
  else {
    text = format_message (M);
    flags |= PURPLE_MESSAGE_RECV;
  }
  
  if (! text || ! *text) {
    warning ("No text to display");
    return;
  }
  switch (tgl_get_peer_type (M->to_id)) {
    case TGL_PEER_CHAT: {
      if (chat_show (conn->gc, tgl_get_peer_id (M->to_id))) {
        p2tgl_got_chat_in (TLS, M->to_id, M->from_id, text, flags, M->date);
      }
      pending_reads_add (conn->pending_reads, M->to_id);
      break;
    }
    case TGL_PEER_ENCR_CHAT: {
      p2tgl_got_im (TLS, M->to_id, text, flags, M->date);
      pending_reads_add (conn->pending_reads, M->to_id);
      break;
    }
    case TGL_PEER_USER: {
      if (tgp_our_msg (TLS, M)) {
        flags |= PURPLE_MESSAGE_SEND;
        flags &= ~PURPLE_MESSAGE_RECV;
        p2tgl_got_im_combo (TLS, M->to_id, text, flags, M->date);
      } else {
        p2tgl_got_im (TLS, M->from_id, text, flags, M->date);
        pending_reads_add (conn->pending_reads, M->from_id);
      }
      break;
    }
  }
  
  if (p2tgl_status_is_present (purple_account_get_active_status (conn->pa)) && p2tgl_send_notifications(conn->pa)) {
    pending_reads_send_all (conn->pending_reads, conn->TLS);
  }
  
  g_free (text);
}