Пример #1
0
static void tgp_info_load_photo_done (struct tgl_state *TLS, void *extra, int success, const char *filename) {
  tgl_peer_t *P = extra;
  
  g_return_if_fail(success);
  
  gchar *img = NULL;
  size_t len;
  GError *err = NULL;
  g_file_get_contents (filename, &img, &len, &err);
  if (err) {
    failure ("getting file contents for %s failed: %s", filename, err->message);
    return;
  }
  
  if (tgl_get_peer_type (P->id) == TGL_PEER_USER || tgl_get_peer_type (P->id) == TGL_PEER_ENCR_CHAT) {
    PurpleBuddy *B = tgp_blist_buddy_find (TLS, P->id);
    g_return_if_fail(B);
    
    purple_buddy_icons_set_for_user (tls_get_pa (TLS), purple_buddy_get_name (B),
       (guchar*) img, len, NULL);
    tgp_info_update_photo_id (&B->node, P->user.photo_big.local_id);
  } else {
    PurpleChat *C = tgp_blist_chat_find (TLS, P->id);
    g_return_if_fail(C);
    
    purple_buddy_icons_node_set_custom_icon (&C->node, (guchar*) img, len);
    tgp_info_update_photo_id (&C->node, P->user.photo_big.local_id);
  }
}
Пример #2
0
void write_secret_chat (tgl_peer_t *Peer, void *extra) {
  struct tgl_secret_chat *P = (void *)Peer;
  if (tgl_get_peer_type (P->id) != TGL_PEER_ENCR_CHAT) { return; }
  if (P->state != sc_ok) { return; }
  int *a = extra;
  int fd = a[0];
  a[1] ++;

  int id = tgl_get_peer_id (P->id);
  assert (write (fd, &id, 4) == 4);
  //assert (write (fd, &P->flags, 4) == 4);
  int l = strlen (P->print_name);
  assert (write (fd, &l, 4) == 4);
  assert (write (fd, P->print_name, l) == l);
  assert (write (fd, &P->user_id, 4) == 4);
  assert (write (fd, &P->admin_id, 4) == 4);
  assert (write (fd, &P->date, 4) == 4);
  assert (write (fd, &P->ttl, 4) == 4);
  assert (write (fd, &P->layer, 4) == 4);
  assert (write (fd, &P->access_hash, 8) == 8);
  assert (write (fd, &P->state, 4) == 4);
  assert (write (fd, &P->key_fingerprint, 8) == 8);
  assert (write (fd, &P->key, 256) == 256);
  assert (write (fd, &P->first_key_sha, 20) == 20);
  assert (write (fd, &P->in_seq_no, 4) == 4);
  assert (write (fd, &P->last_in_seq_no, 4) == 4);
  assert (write (fd, &P->out_seq_no, 4) == 4);
}
Пример #3
0
static void tgprpl_xfer_send_init (PurpleXfer *X) {
  struct tgp_xfer_send_data *data = X->data;
  
  purple_xfer_start (X, -1, NULL, 0);
  
  const char *file = purple_xfer_get_filename (X);
  const char *localfile = purple_xfer_get_local_filename (X);
  const char *who = purple_xfer_get_remote_user (X);
  debug ("xfer_on_init (file=%s, local=%s, who=%s)", file, localfile, who);
  
  tgl_peer_t *P = find_peer_by_name (data->conn->TLS, who);
  if (P) {
    if (tgl_get_peer_type (P->id) != TGL_PEER_ENCR_CHAT) {
      tgl_do_send_document (data->conn->TLS, P->id, (char*) localfile, NULL,
                            0, TGL_SEND_MSG_FLAG_DOCUMENT_AUTO, tgprpl_xfer_on_finished, data);
    }
    else {
      purple_notify_message (_telegram_protocol, PURPLE_NOTIFY_MSG_ERROR, "Not supported",
                             "Sorry, sending documents to encrypted chats not yet supported.",
                             NULL, NULL, NULL);
    }
  }
  
  data->timer = purple_timeout_add (100, tgprpl_xfer_upload_progress, X);
}
Пример #4
0
void tgp_msg_sys_out (struct tgl_state *TLS, const char *msg, tgl_peer_id_t to_id, int no_log) {
  int flags = PURPLE_MESSAGE_SYSTEM;
  if (no_log) {
    flags |= PURPLE_MESSAGE_NO_LOG;
  }
  time_t now;
  time (&now);
  
  switch (tgl_get_peer_type (to_id)) {
    case TGL_PEER_CHAT:
      p2tgl_got_chat_in (TLS, to_id, to_id, msg, flags, now);
      break;
    case TGL_PEER_USER:
    case TGL_PEER_ENCR_CHAT: {
      const char *name = tgp_blist_lookup_purple_name (TLS, to_id);
      PurpleConversation *conv = p2tgl_find_conversation_with_account (TLS, to_id);
      
      g_return_if_fail (name);

      if (! conv) {
        conv = purple_conversation_new (PURPLE_CONV_TYPE_IM, tls_get_pa (TLS), name);
      }
      purple_conversation_write (conv, name, msg, flags, now);
      break;
    }
  }
}
Пример #5
0
static void tgprpl_xfer_send_init (PurpleXfer *X) {
  debug ("tgprpl_xfer_send_init(): sending xfer accepted.");

  struct tgp_xfer_send_data *data;
  const char *file, *localfile, *who;
  tgl_peer_t *P;

  data = X->data;
  purple_xfer_start (X, -1, NULL, 0);

  file = purple_xfer_get_filename (X);
  localfile = purple_xfer_get_local_filename (X);
  who = purple_xfer_get_remote_user (X);
  debug ("xfer_on_init (file=%s, local=%s, who=%s)", file, localfile, who);

  P = tgp_blist_lookup_peer_get (data->conn->TLS, who);
  g_return_if_fail (P);

  if (tgl_get_peer_type (P->id) == TGL_PEER_ENCR_CHAT) {
    purple_xfer_error (PURPLE_XFER_SEND, data->conn->pa, who,
        _("Sorry, sending documents to encrypted chats not yet supported."));
    purple_xfer_cancel_local (X);
    return;
  }

  tgl_do_send_document (data->conn->TLS, P->id, (char*) localfile, NULL, 0,
      TGL_SEND_MSG_FLAG_DOCUMENT_AUTO, tgprpl_xfer_send_on_finished, data);

  // see comment in tgprpl_xfer_recv_init()
  purple_xfer_ref (X);

  data->timer = purple_timeout_add (100, tgprpl_xfer_upload_progress, X);
  data->loading = TRUE;
}
Пример #6
0
void tgp_blist_buddy_set_id (PurpleBuddy *buddy, tgl_peer_id_t id) {
  int uid = tgl_get_peer_id (id),
     type = tgl_get_peer_type (id);
  assert (type == TGL_PEER_ENCR_CHAT || type == TGL_PEER_USER);
  
  purple_blist_node_set_int (&buddy->node, TGP_BUDDY_KEY_PEER_ID, uid);
  purple_blist_node_set_int (&buddy->node, TGP_BUDDY_KEY_PEER_TYPE, type);
}
Пример #7
0
json_t *json_pack_peer (tgl_peer_id_t id, tgl_peer_t *P) {
  json_t *res = json_object ();
  assert (json_object_set (res, "id", json_integer (tgl_get_peer_id (id))) >= 0);

  json_pack_peer_type (res, id);

  assert (res);
    
  if (!P || !(P->flags & TGLPF_CREATED)) {
    static char s[100];
    switch (tgl_get_peer_type (id)) {
    case TGL_PEER_USER:
      sprintf (s, "user#%d", tgl_get_peer_id (id));
      break;
    case TGL_PEER_CHAT:
      sprintf (s, "chat#%d", tgl_get_peer_id (id));
      break;
    case TGL_PEER_ENCR_CHAT:
      sprintf (s, "encr_chat#%d", tgl_get_peer_id (id));
      break;
    default:
      assert (0);
    }

    assert (json_object_set (res, "print_name", json_string (s)) >= 0);
    return res;
  }
  
  assert (json_object_set (res, "print_name", json_string (P->print_name)) >= 0);
  assert (json_object_set (res, "flags", json_integer (P->flags)) >= 0);
  
  switch (tgl_get_peer_type (id)) {
  case TGL_PEER_USER:
    json_pack_user (res, P);
    break;
  case TGL_PEER_CHAT:
    json_pack_chat (res, P);
    break;
  case TGL_PEER_ENCR_CHAT:
    json_pack_encr_chat (res, P);
    break;
  default:
    assert (0);
  }
  return res;
}
Пример #8
0
void pending_reads_add (struct tgl_state *TLS, struct tgl_message *M) {
  tgl_peer_id_t *copy = g_new (tgl_peer_id_t, 1);
  if (tgl_get_peer_type (M->to_id) == TGL_PEER_USER) {
    *copy = M->from_id;
  } else {
    *copy = M->to_id;
  }
  g_hash_table_replace (tls_get_data (TLS)->pending_reads, GINT_TO_POINTER (tgl_get_peer_id (*copy)), copy);
}
Пример #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 void tgp_msg_err_out (struct tgl_state *TLS, const char *error, tgl_peer_id_t to) {
  int flags = PURPLE_MESSAGE_ERROR | PURPLE_MESSAGE_SYSTEM;
  time_t now;
  time (&now);
  switch (tgl_get_peer_type (to)) {
      case TGL_PEER_CHAT:
        p2tgl_got_chat_in (TLS, to, to, error, flags, now);
        break;
      case TGL_PEER_USER:
      case TGL_PEER_ENCR_CHAT:
        p2tgl_got_im (TLS, to, error, flags, now);
        break;
  }
}
Пример #11
0
static void tgp_chat_roomlist_it (tgl_peer_t *P, void *extra) {
  connection_data *conn = extra;
  
  if (tgl_get_peer_type (P->id) == TGL_PEER_CHAT && P->chat.users_num) {
    char *id = g_strdup_printf ("%d", tgl_get_peer_id (P->id));
    
    PurpleRoomlistRoom *room = purple_roomlist_room_new (PURPLE_ROOMLIST_ROOMTYPE_ROOM, P->chat.print_title, NULL);
    purple_roomlist_room_add_field (conn->roomlist, room, id);
    purple_roomlist_room_add_field (conn->roomlist, room, GINT_TO_POINTER(P->chat.users_num));
    purple_roomlist_room_add (conn->roomlist, room);
    
    g_free (id);
  }
}
Пример #12
0
PurpleBuddy *tgp_blist_buddy_find (struct tgl_state *TLS, tgl_peer_id_t user) {
  PurpleBlistNode *node = purple_blist_get_root ();
  while (node) {
    if (PURPLE_BLIST_NODE_IS_BUDDY(node)) {
      PurpleBuddy *buddy = PURPLE_BUDDY(node);
      if (purple_buddy_get_account (buddy) == tg_get_acc (TLS)) {
        if (purple_blist_node_get_int (node, TGP_BUDDY_KEY_PEER_ID) == tgl_get_peer_id (user)) {
          assert (tgl_get_peer_type (user) == purple_blist_node_get_int (node, TGP_BUDDY_KEY_PEER_TYPE));
          return buddy;
        }
      }
    }
    node = purple_blist_node_next (node, FALSE);
  }
  return NULL;
}
Пример #13
0
void json_pack_peer_type (json_t *res, tgl_peer_id_t id) {
  int x = tgl_get_peer_type (id);
  switch (x) {
  case TGL_PEER_USER:
    assert (json_object_set (res, "type", json_string ("user")) >= 0);
    break;
  case TGL_PEER_CHAT:
    assert (json_object_set (res, "type", json_string ("chat")) >= 0);
    break;
  case TGL_PEER_ENCR_CHAT:
    assert (json_object_set (res, "type", json_string ("encr_chat")) >= 0);
    break;
  default:
    assert (0);
  }
}
Пример #14
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;
}
Пример #15
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);
  }
}
Пример #16
0
void tgprpl_info_show (PurpleConnection *gc, const char *who) {
  tgl_peer_t *P = tgp_blist_lookup_peer_get (gc_get_data (gc)->TLS, who);
  if (P) {
    switch (tgl_get_peer_type (P->id)) {
      case TGL_PEER_ENCR_CHAT: {
        tgl_peer_t *parent = tgp_encr_chat_get_partner (gc_get_tls (gc), &P->encr_chat);
        if (parent) {
          tgl_do_get_user_info (gc_get_tls (gc), parent->id, 0, tgp_info_load_user_done, P);
        }
        break;
      }
        
      case TGL_PEER_CHANNEL:
        tgl_do_get_channel_info (gc_get_tls (gc), P->id, FALSE, tgp_info_load_channel_done, P);
        break;
        
      case TGL_PEER_USER:
        tgl_do_get_user_info (gc_get_tls (gc), P->id, 0, tgp_info_load_user_done, P);
        break;
    }
  }
}
Пример #17
0
void on_message_load_photo (struct tgl_state *TLS, void *extra, int success, char *filename) {
  gchar *data = NULL;
  size_t len;
  GError *err = NULL;
  g_file_get_contents (filename, &data, &len, &err);
  int imgStoreId = purple_imgstore_add_with_id (g_memdup(data, (guint)len), len, NULL);
    
  char *image = format_img_full(imgStoreId);
  struct tgl_message *M = extra;
  switch (tgl_get_peer_type (M->to_id)) {
    case TGL_PEER_CHAT:
      debug ("PEER_CHAT\n");
      if (!our_msg(TLS, M)) {
        chat_add_message (TLS, M, image);
      }
      break;
      
    case TGL_PEER_USER:
      debug ("PEER_USER\n");
      if (out_msg(TLS, M)) {
        p2tgl_got_im (TLS, M->to_id, image, PURPLE_MESSAGE_SEND | PURPLE_MESSAGE_IMAGES, M->date);
      } else {
        p2tgl_got_im (TLS, M->from_id, image, PURPLE_MESSAGE_RECV | PURPLE_MESSAGE_IMAGES, M->date);
      }
      break;
      
    case TGL_PEER_ENCR_CHAT:
      break;
      
    case TGL_PEER_GEO_CHAT:
      break;
  }
 
  g_free (image);
  telegram_conn *conn = TLS->ev_base;
  conn->updated = 1;
}
Пример #18
0
void tgl_do_send_location_encr (struct tgl_state *TLS, tgl_peer_id_t id, double latitude, double longitude, unsigned long long flags, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, struct tgl_message *M), void *callback_extra) {
  struct tl_ds_decrypted_message_media TDSM;
  TDSM.magic = CODE_decrypted_message_media_geo_point;
  TDSM.latitude = talloc (sizeof (double));
  *TDSM.latitude = latitude;
  TDSM.longitude = talloc (sizeof (double));
  *TDSM.longitude = longitude;
  
  int peer_type = tgl_get_peer_type (id);
  int peer_id = tgl_get_peer_id (id);
  int date = time (0);

  long long t;
  tglt_secure_random (&t, 8);

  bl_do_create_message_encr_new (TLS, t, &TLS->our_id, &peer_type, &peer_id, &date, NULL, 0, &TDSM, NULL, NULL, TGLMF_UNREAD | TGLMF_OUT | TGLMF_PENDING | TGLMF_CREATE | TGLMF_CREATED | TGLMF_ENCRYPTED);

  tfree (TDSM.latitude, sizeof (double));
  tfree (TDSM.longitude, sizeof (double));

  struct tgl_message *M = tgl_message_get (TLS, t);

  tgl_do_send_encr_msg (TLS, M, callback, callback_extra);
}
Пример #19
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;
  
  if (M->flags & (TGLMF_EMPTY | TGLMF_DELETED)) {
    return;
  }
  if (!(M->flags & TGLMF_CREATED)) {
    return;
  }
  if (!tgl_get_peer_type (M->to_id)) {
    warning ("Bad msg\n");
    return;
  }

  // only display new messages, ignore updates or deletions
  if (!M->message || tgp_outgoing_msg (TLS, M) || !tgl_get_peer_type (M->to_id)) {
    return;
  }
  
  // Mark messages that contain a mention as if they contained our current nick name
  // FIXME: doesn't work in Adium
  if (M->flags & TGLMF_MENTION) {
    flags |= PURPLE_MESSAGE_NICK;
  }
  
  // handle messages that failed to load
  if (C->error) {
    const char *err = C->error_msg;
    if (! err) {
      err = _("failed loading message");
    }
    tgp_msg_err_out (TLS, err, tgp_our_msg (TLS, M) ? M->from_id : M->to_id);
    return;
  }

  // format the message text
  if (M->flags & TGLMF_SERVICE) {
    text = format_service_msg (TLS, M);
    flags |= PURPLE_MESSAGE_SYSTEM;
    
  } else if (M->media.type != tgl_message_media_none) {
    switch (M->media.type) {
  
      case tgl_message_media_photo: {
        if (M->media.photo) {
          g_return_if_fail(C->data != NULL);
          
          text = tgp_msg_photo_display (TLS, C->data, &flags);
          if (str_not_empty (text)) {
            if (str_not_empty (M->media.caption)) {
              char *old = text;
              text = g_strdup_printf ("%s<br>%s", old, M->media.caption);
              g_free (old);
            }
          }
        }
        break;
      }
        
      case tgl_message_media_document:
        if (M->media.document->flags & TGLDF_STICKER) {
          g_return_if_fail(C->data != NULL);
          text = tgp_msg_sticker_display (TLS, M->from_id, C->data, &flags);
        } else if (M->media.document->flags & TGLDF_IMAGE) {
          g_return_if_fail(C->data != NULL);
          text = tgp_msg_photo_display (TLS, C->data, &flags);
        } else {
          if (! tgp_our_msg(TLS, M)) {
            tgprpl_recv_file (conn->gc, tgp_blist_lookup_purple_name (TLS, M->from_id), M);
          }
          return;
        }
        break;
        
      case tgl_message_media_video:
      case tgl_message_media_audio: {
        if (! tgp_our_msg(TLS, M)) {
          tgprpl_recv_file (conn->gc, tgp_blist_lookup_purple_name (TLS, M->from_id), M);
        }
      }
      break;
        
      case tgl_message_media_document_encr:
        if (M->media.encr_document->flags & TGLDF_STICKER) {
          g_return_if_fail(C->data != NULL);
          text = tgp_msg_sticker_display (TLS, M->from_id, C->data, &flags);
        } if (M->media.encr_document->flags & TGLDF_IMAGE) {
          g_return_if_fail(C->data != NULL);
          text = tgp_msg_photo_display (TLS, C->data, &flags);
        } else {
          if (! tgp_our_msg(TLS, M)) {
            tgprpl_recv_file (conn->gc, tgp_blist_lookup_purple_name (TLS, M->to_id), M);
          }
          return;
        }
        break;
      
      case tgl_message_media_contact:
        text = g_strdup_printf ("<b>%s %s</b> %s", M->media.first_name, M->media.last_name, M->media.phone);
        break;
        
      case tgl_message_media_venue: {
        char *address = NULL;
        if (M->media.venue.address && strcmp (M->media.venue.title, M->media.venue.address)) {
          address = g_strdup_printf (" %s", M->media.venue.address);
        }
        char *pos = format_geo_link_osm (M->media.venue.geo.latitude, M->media.geo.longitude);
        text = g_strdup_printf ("<a href=\"%s\">%s</a>%s",
                                pos,
                                M->media.venue.title ? M->media.venue.title : "", address ? address : "");
        if (address) {
          g_free (address);
        }
        g_free (pos);
        break;
      }
        
      case tgl_message_media_geo: {
        char *pos = format_geo_link_osm (M->media.venue.geo.latitude, M->media.geo.longitude);
        text = g_strdup_printf ("<a href=\"%s\">%s</a>", pos, pos);
        g_free (pos);
        break;
      }
        
      case tgl_message_media_webpage: {
        char *msg = g_strdup (M->message);
        text = purple_markup_escape_text (msg, strlen (msg));
        g_free (msg);
        break;
      }
        
      default:
        warning ("received unknown media type: %d", M->media.type);
        break;
    }
    
  } else {
    if (str_not_empty (M->message)) {
      text = purple_markup_escape_text (M->message, strlen (M->message));
    }
    flags |= PURPLE_MESSAGE_RECV;
  }
  
  if (tgl_get_peer_type (M->to_id) != TGL_PEER_ENCR_CHAT && ! (M->flags & TGLMF_UNREAD)) {
    flags |= PURPLE_MESSAGE_DELAYED;
  }
  
  // some service messages (like removing/adding users from chats) might print the message 
  // text through other means and leave the text empty
  if (! str_not_empty (text)) {
    return;
  }
  
  // display the message to the user
  switch (tgl_get_peer_type (M->to_id)) {
    case TGL_PEER_CHAT: {
      tgl_peer_t *P = tgl_peer_get (TLS, M->to_id);
      g_return_if_fail(P != NULL);
      
      if (tgp_chat_show (TLS, &P->chat)) {
        p2tgl_got_chat_in (TLS, M->to_id, M->from_id, text, flags, M->date);
      }
      break;
    }
    case TGL_PEER_ENCR_CHAT: {
      p2tgl_got_im_combo (TLS, M->to_id, text, flags, M->date);
      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_combo (TLS, M->from_id, text, flags, M->date);
      }
      break;
    }
  }
  
  g_free (text);
}
Пример #20
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;
}
Пример #21
0
static void tgp_info_load_user_done (struct tgl_state *TLS, void *extra, int success, struct tgl_user *U) {
  g_return_if_fail(success);
  
  // user info
  
  PurpleNotifyUserInfo *info = purple_notify_user_info_new ();
  
  if (str_not_empty (U->first_name) && str_not_empty (U->last_name)) {
    purple_notify_user_info_add_pair (info, _("First name"), U->first_name);
    purple_notify_user_info_add_pair (info, _("Last name"), U->last_name);
  } else {
    purple_notify_user_info_add_pair (info, _("Name"), U->print_name);
  }
  
  if (str_not_empty (U->username)) {
    char *username = g_strdup_printf ("@%s", U->username);
    purple_notify_user_info_add_pair (info, _("Username"), username);
    g_free (username);
  }
  
  char *status = tgp_format_user_status (&U->status);
  purple_notify_user_info_add_pair (info, _("Last seen"), status);
  g_free (status);
  
  if (str_not_empty (U->phone)) {
    char *phone = g_strdup_printf ("+%s", U->phone);
    purple_notify_user_info_add_pair (info, _("Phone"), phone);
    g_free (phone);
  }
  
  // secret chat info
  
  tgl_peer_t *O = extra;
  if (O && tgl_get_peer_type (O->id) == TGL_PEER_ENCR_CHAT) {
    
    struct tgl_secret_chat *secret = &O->encr_chat;
    
    if (secret->state == sc_waiting) {
      purple_notify_user_info_add_pair (info, "", _("Waiting for the user to get online..."));
    } else {
      const char *ttl_key = _("Self destruction timer");
      if (secret->ttl) {
        char *ttl = g_strdup_printf ("%d", secret->ttl);
        purple_notify_user_info_add_pair (info, ttl_key, ttl);
        g_free (ttl);
      } else {
        purple_notify_user_info_add_pair (info, ttl_key, _("Timer is not enabled."));
      }
      
      if (secret->first_key_sha[0]) {
        int sha1key = tgp_visualize_key (TLS, secret->first_key_sha);
        if (sha1key != -1) {
          char *ident_icon = tgp_format_img (sha1key);
          purple_notify_user_info_add_pair (info, _("Secret key"), ident_icon);
          g_free(ident_icon);
        }
      }
    }
  }
  
  const char *who = NULL;
  if (tgl_get_peer_type (O->id) == TGL_PEER_ENCR_CHAT) {
    who = tgp_blist_lookup_purple_name (TLS, O->id);
  } else {
    who = tgp_blist_lookup_purple_name (TLS, U->id);
  }
  
  purple_notify_userinfo (tls_get_conn (TLS), who, info, NULL, NULL);
}
Пример #22
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;
  
  // Filter message updates and deletes, are not created and
  // all messages in general that were already displayed, or shouldn't be displayed
  if ((M->flags & (FLAG_MESSAGE_EMPTY | FLAG_DELETED)) ||
      !(M->flags & FLAG_CREATED) ||
      !M->message ||
      our_msg (TLS, M) ||
      !tgl_get_peer_type (M->to_id)) {
    return;
  }
  
  
  if (M->service) {
    text = format_service_msg (TLS, M);
    flags |= PURPLE_MESSAGE_SYSTEM;
  }
  else if (M->media.type == tgl_message_media_document) {
    char *who = p2tgl_strdup_id (M->from_id);
    if (! out_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->from_id);
    if (! out_msg(TLS, M)) {
      tgprpl_recv_encr_file (conn->gc, who, &M->media.encr_document);
    }
    g_free (who);
  }
  else if (M->media.type == tgl_message_media_photo) {
    char *filename = C->data;
    int imgStoreId = p2tgl_imgstore_add_with_id (filename);
    if (imgStoreId <= 0) {
      failure ("Cannot display picture message, adding to imgstore failed.");
      return;
    }
    used_images_add (conn, imgStoreId);
    text = format_img_full (imgStoreId);
    flags |= PURPLE_MESSAGE_IMAGES;
  }
  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 (out_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))) {
    pending_reads_send_all (conn->pending_reads, conn->TLS);
  }

  
  g_free (text);
}
Пример #23
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));

}
Пример #24
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);
}
Пример #25
0
int tgp_msg_send (struct tgl_state *TLS, const char *message, tgl_peer_id_t to) {
  // search for outgoing embedded image tags and send them
  gchar *img = NULL;
  gchar *stripped = NULL;
  if ((img = g_strrstr (message, "<IMG")) || (img = g_strrstr (message, "<img"))) {
    if (tgl_get_peer_type(to) == TGL_PEER_ENCR_CHAT) {
      tgp_msg_err_out (TLS, "Sorry, sending documents to encrypted chats not yet supported.", to);
      return 0;
    }
    
    debug ("img found: %s", img);
    gchar *id;
    if ((id = g_strrstr (img, "ID=\"")) || (id = g_strrstr (img, "id=\""))) {
      id += 4;
      debug ("id found: %s", id);
      int imgid = atoi (id);
      if (imgid > 0) {
        PurpleStoredImage *psi = purple_imgstore_find_by_id (imgid);
        gchar *tmp = g_build_filename(g_get_tmp_dir(), purple_imgstore_get_filename (psi), NULL) ;
        GError *err = NULL;
        gconstpointer data = purple_imgstore_get_data (psi);
        g_file_set_contents (tmp, data, purple_imgstore_get_size (psi), &err);
        if (! err) {
          stripped = purple_markup_strip_html (message);
          tgl_do_send_document (TLS, to, tmp, stripped, (int)strlen (stripped), TGL_SEND_MSG_FLAG_DOCUMENT_AUTO, tgp_msg_send_done, NULL);
          g_free (stripped);
          return 1;
        } else {
          failure ("Cannot store image, temp directory not available: %s\n", err->message);
          g_error_free (err);
          return 0;
        }
      }
    }
    // no image id found in image
    return 0;
  }
  
#ifndef __ADIUM_
  /*
    Adium won't escape any HTML markup and just pass any user-input through,
    while Pidgin will replace special chars with the escape chars and also add 
    additional markup for RTL languages and such.

    First, we remove any HTML markup added by Pidgin, since Telegram won't handle it properly.
    User-entered HTML is still escaped and therefore won't be harmed.
   */
  stripped = purple_markup_strip_html (message);
  
  /* 
    now unescape the markup, so that html special chars will still show
    up properly in Telegram
   */
  gchar *unescaped = purple_unescape_text (stripped);
  int ret = tgp_msg_send_split (TLS, stripped, to);
  
  g_free (unescaped);
  g_free (stripped);
  return ret;
#endif
  
  return tgp_msg_send_split (TLS, message, to);
}
Пример #26
0
static void update_message_received (struct tgl_state *TLS, struct tgl_message *M) {
  debug ("received message\n");
  telegram_conn *conn = TLS->ev_base;
  conn->updated = 1;

  if (M->service) {
    debug ("service message, skipping...\n");
    char *text = format_service_msg (TLS, M);
    if (text) {
      switch (tgl_get_peer_type (M->to_id)) {
        case TGL_PEER_CHAT:
          chat_add_message (TLS, M, text);
          break;
          
        case TGL_PEER_USER:
          p2tgl_got_im (TLS, M->from_id, text, PURPLE_MESSAGE_SYSTEM, M->date);
          break;
      }
      g_free (text);
    }
    conn->updated = 1;
    return;
  }
  
  if ((M->flags & (FLAG_MESSAGE_EMPTY | FLAG_DELETED)) || !(M->flags & FLAG_CREATED)) {
    return;
  }
  if (!tgl_get_peer_type (M->to_id)) {
    warning ("Bad msg\n");
    return;
  }

  if (M->media.type == tgl_message_media_photo) {
    tgl_do_load_photo (TLS, &M->media.photo, on_message_load_photo, M);
    return;
  }

  if (!M->message) {
    return;
  }

  char *text = purple_markup_escape_text (M->message, strlen (M->message));
  switch (tgl_get_peer_type (M->to_id)) {
    case TGL_PEER_CHAT:
      debug ("PEER_CHAT\n");
      if (!our_msg(TLS, M)) {
        chat_add_message (TLS, M, text);
      }
      break;
      
    case TGL_PEER_USER:
      debug ("PEER_USER\n");
      
      // p2tgl_got_im (TLS, M->to_id, text, PURPLE_MESSAGE_SEND, M->date);
      // :TODO: figure out how to add messages from different devices to history
      if (!our_msg(TLS, M)) {
        if (out_msg(TLS, M)) {
          p2tgl_got_im (TLS, M->to_id, text, PURPLE_MESSAGE_SEND, M->date);
        } else {
          p2tgl_got_im (TLS, M->from_id, text, PURPLE_MESSAGE_RECV, M->date);
        }
      }
      break;
      
    case TGL_PEER_ENCR_CHAT:
      break;
      
    case TGL_PEER_GEO_CHAT:
      break;
  }
  
  g_free (text);
}
Пример #27
0
void tgp_msg_recv (struct tgl_state *TLS, struct tgl_message *M) {
  connection_data *conn = TLS->ev_base;
  if (M->flags & (TGLMF_EMPTY | TGLMF_DELETED)) {
    return;
  }
  if (!(M->flags & TGLMF_CREATED)) {
    return;
  }
  if (!(M->flags | TGLMF_UNREAD) && M->date != 0 && M->date < tgp_msg_oldest_relevant_ts (TLS)) {
    debug ("Message from %d on %d too old, ignored.", tgl_get_peer_id (M->from_id), M->date);
    return;
  }
  
  struct tgp_msg_loading *C = tgp_msg_loading_init (M);
  
  if (! (M->flags & TGLMF_SERVICE)) {
    
    // handle all messages that need to load content before they can be displayed
    if (M->media.type != tgl_message_media_none) {
      switch (M->media.type) {
        case tgl_message_media_photo: {
          
          // include the "bad photo" check from telegram-cli interface.c:3287 to avoid crashes when fetching history
          // TODO: find out the reason for this behavior
          if (M->media.photo) {
            ++ C->pending;
            tgl_do_load_photo (TLS, M->media.photo, tgp_msg_on_loaded_document, C);
          }
          break;
        }
          
        // documents that are stickers or images will be displayed just like regular photo messages
        // and need to be lodaed beforehand
        case tgl_message_media_document:
        case tgl_message_media_video:
        case tgl_message_media_audio:
          if (M->media.document->flags & TGLDF_STICKER || M->media.document->flags & TGLDF_IMAGE) {
            ++ C->pending;
            tgl_do_load_document (TLS, M->media.document, tgp_msg_on_loaded_document, C);
          }
          break;
        case tgl_message_media_document_encr:
          if (M->media.encr_document->flags & TGLDF_STICKER || M->media.encr_document->flags & TGLDF_IMAGE) {
            ++ C->pending;
            tgl_do_load_encr_document (TLS, M->media.encr_document, tgp_msg_on_loaded_document, C);
          }
          break;
          
        case tgl_message_media_geo:
          // TODO: load geo thumbnail
          break;
          
        default: // prevent Clang warnings ...
          break;
      }
    }
  }
  
  if (tgl_get_peer_type (M->to_id) == TGL_PEER_CHAT) {
    
    tgl_peer_t *P = tgl_peer_get (TLS, M->to_id);
    g_warn_if_fail(P);
    if (P && ! P->chat.user_list_size) {
      // To display a chat the full name of every single user is needed, but the updates received from the server only
      // contain the names of users mentioned in the events. In order to display a messages we always need to fetch the
      // full chat info first. If the user list is empty, this means that we still haven't fetched the full chat information.
      
      // assure that there is only one chat info request for every
      // chat to avoid causing FLOOD_WAIT_X errors that will lead to delays or dropped messages
      gpointer to_ptr = GINT_TO_POINTER(tgl_get_peer_id (M->to_id));
      
      if (! g_hash_table_lookup (conn->pending_chat_info, to_ptr)) {
        ++ C->pending;
        
        tgl_do_get_chat_info (TLS, M->to_id, FALSE, tgp_msg_on_loaded_chat_full, C);
        g_hash_table_replace (conn->pending_chat_info, to_ptr, to_ptr);
      }
    }
  }
  
  g_queue_push_tail (conn->new_messages, C);
  tgp_msg_process_in_ready (TLS);
}