1 /*
2  This file is part of telegram-purple
3 
4  This program is free software; you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation; either version 2 of the License, or
7  (at your option) any later version.
8 
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  GNU General Public License for more details.
13 
14  You should have received a copy of the GNU General Public License
15  along with this program; if not, write to the Free Software
16  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
17 
18  Copyright Matthias Jentsch 2014-2015
19  */
20 
21 #include "telegram-purple.h"
22 
request_values_data_init(struct tgl_state * TLS,void * callback,void * arg,int num_values)23 static struct request_values_data *request_values_data_init (struct tgl_state *TLS, void *callback, void *arg, int num_values) {
24   struct request_values_data *data = talloc0 (sizeof (struct request_values_data));
25   data->TLS = TLS;
26   data->callback = callback;
27   data->arg = arg;
28   data->num_values = num_values;
29   return data;
30 }
31 
request_code_entered(struct request_values_data * data,const gchar * code)32 static void request_code_entered (struct request_values_data *data, const gchar *code) {
33   char *stripped = g_strstrip (purple_markup_strip_html (code));
34   debug ("sending code: '%s'\n", stripped);
35   data->callback (data->TLS, (const char **)&stripped, data->arg);
36   g_free (stripped);
37 }
38 
request_canceled_disconnect(struct request_values_data * data)39 static void request_canceled_disconnect (struct request_values_data *data) {
40   purple_connection_error_reason (tls_get_conn (data->TLS), PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED, "registration canceled");
41   free (data);
42 }
43 
request_canceled(struct request_values_data * data)44 static void request_canceled (struct request_values_data *data) {
45   free (data);
46 }
47 
request_code(struct tgl_state * TLS,void (* callback)(struct tgl_state * TLS,const char * string[],void * arg),void * arg)48 static void request_code (struct tgl_state *TLS, void (*callback) (struct tgl_state *TLS, const char *string[], void *arg),
49     void *arg) {
50   debug ("client is not registered, registering...");
51   char *explanation = _("Telegram wants to verify your "
52       "identity. Please enter the login code that you have received via SMS.");
53   if (purple_account_get_bool (tls_get_pa (TLS), "compat-verification", 0) ||
54       !purple_request_input (tls_get_conn (TLS), _("Login code"), _("Enter login code"), explanation, NULL, 0, 0, _("the code"), _("OK"),
55           G_CALLBACK(request_code_entered), _("Cancel"), G_CALLBACK(request_canceled_disconnect), tls_get_pa (TLS),
56           NULL, NULL, request_values_data_init (TLS, callback, arg, 0))) {
57     // the purple request API is not supported, create a new conversation (the Telegram system account "Telegram") to
58     // prompt the user for the code.
59     tls_get_data (TLS)->request_code_data = request_values_data_init (TLS, callback, arg, 0);
60     purple_connection_set_state (tls_get_conn (TLS), PURPLE_CONNECTED);
61     PurpleConversation *conv = purple_conversation_new (PURPLE_CONV_TYPE_IM, tls_get_pa (TLS), "Telegram");
62     purple_conversation_write (conv, "Telegram", explanation,
63         PURPLE_MESSAGE_RECV | PURPLE_MESSAGE_SYSTEM, 0);
64   }
65 }
66 
67 static void request_name (struct tgl_state *TLS, void (*callback) (struct tgl_state *TLS, const char *string[],
68     void *arg), void *arg);
request_name_code_entered(struct request_values_data * data,PurpleRequestFields * fields)69 static void request_name_code_entered (struct request_values_data *data, PurpleRequestFields* fields) {
70   char *names[] = {
71     g_strdup ("y"), // input line is a y/n choice
72     g_strstrip (g_strdup (purple_request_fields_get_string (fields, "first_name"))),
73     g_strstrip (g_strdup (purple_request_fields_get_string (fields, "last_name")))
74   };
75   if (str_not_empty (names[1]) && str_not_empty (names[2])) {
76     data->callback (data->TLS, (const char **) names, data->arg);
77   } else {
78     request_name (data->TLS, data->callback, data->arg);
79   }
80   int j;
81   for (j = 0; j < 3; ++j) {
82     g_free (names[j]);
83   }
84   free (data);
85 }
86 
request_name(struct tgl_state * TLS,void (* callback)(struct tgl_state * TLS,const char * string[],void * arg),void * arg)87 static void request_name (struct tgl_state *TLS,
88     void (*callback) (struct tgl_state *TLS, const char *string[], void *arg), void *arg) {
89   debug("Phone is not registered, registering...");
90 
91   PurpleRequestFields *fields = purple_request_fields_new ();
92   PurpleRequestField *field = 0;
93 
94   PurpleRequestFieldGroup *group = purple_request_field_group_new (_("Registration"));
95   field = purple_request_field_string_new ("first_name", _("First name"), "", 0);
96   purple_request_field_group_add_field (group, field);
97 
98   field = purple_request_field_string_new ("last_name", _("Last name"), "", 0);
99   purple_request_field_group_add_field (group, field);
100   purple_request_fields_add_group (fields, group);
101 
102   if (!purple_request_fields (tls_get_conn (TLS), _("Register"), _("Please register your phone number."), NULL, fields,
103       _("OK"), G_CALLBACK(request_name_code_entered), _("Cancel"), G_CALLBACK(request_canceled_disconnect),
104       tls_get_pa (TLS), NULL, NULL, request_values_data_init(TLS, callback, arg, 0))) {
105 
106     // purple_request API not available
107     const char *error = _("Phone number is not registered. Please register your phone on a different client.");
108     purple_connection_error_reason (tls_get_conn (TLS), PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED, error);
109     purple_notify_error (_telegram_protocol, _("Not registered"), _("Not registered"), error);
110   }
111 }
112 
request_password_entered(struct request_values_data * data,char * password)113 static void request_password_entered (struct request_values_data *data, char *password) {
114   data->callback (data->TLS, (const char **) &password, data->arg);
115   free (data);
116 }
117 
request_password(struct tgl_state * TLS,void (* callback)(struct tgl_state * TLS,const char * string[],void * arg),void * arg)118 void request_password (struct tgl_state *TLS,
119     void (*callback) (struct tgl_state *TLS, const char *string[], void *arg), void *arg) {
120 
121   if (! purple_request_input (tls_get_conn (TLS), _("Password needed"), _("Password needed"), _("Enter password for two factor authentication"),
122       NULL, FALSE, TRUE, NULL, _("Ok"), G_CALLBACK(request_password_entered), _("Cancel"), G_CALLBACK(request_canceled_disconnect),
123       tls_get_pa (TLS), NULL, NULL, request_values_data_init (TLS, callback, arg, 0))) {
124     const char *error = _("No password set for two factor authentication. Please enter it in the extended settings.");
125     purple_connection_error_reason (tls_get_conn (TLS), PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED, error);
126     purple_notify_error (_telegram_protocol, _("Password invalid"), _("Password invalid"), error);
127   }
128 }
129 
accept_secret_chat_cb(struct accept_secret_chat_data * data)130 static void accept_secret_chat_cb (struct accept_secret_chat_data *data) {
131   tgl_do_accept_encr_chat_request (data->TLS, data->U, write_secret_chat_gw, 0);
132   free (data);
133 }
134 
decline_secret_chat_cb(struct accept_secret_chat_data * data)135 static void decline_secret_chat_cb (struct accept_secret_chat_data *data) {
136   bl_do_peer_delete (data->TLS, data->U->id);
137   purple_blist_remove_buddy (tgp_blist_buddy_find (data->TLS, data->U->id));
138   free (data);
139 }
140 
request_accept_secret_chat(struct tgl_state * TLS,struct tgl_secret_chat * U)141 void request_accept_secret_chat (struct tgl_state *TLS, struct tgl_secret_chat *U) {
142   tgl_peer_t *P = tgl_peer_get (TLS, TGL_MK_USER(U->user_id));
143   g_return_if_fail (P);
144 
145   struct accept_secret_chat_data *data = talloc0 (sizeof (struct accept_secret_chat_data));
146   data->TLS = TLS;
147   data->U = U;
148 
149   gchar *message = g_strdup_printf (_("Accept secret chat '%s' on this device?"), U->print_name);
150   purple_request_accept_cancel (tls_get_conn (TLS), _("Secret chat"), message, _("Secret chats can only have one "
151       "end point. If you accept a secret chat on this device, its messages will not be available anywhere "
152       "else. If you decline, you can still accept the chat on other devices."), 0, tls_get_pa (TLS), P->print_name,
153       NULL, data, G_CALLBACK(accept_secret_chat_cb), G_CALLBACK(decline_secret_chat_cb));
154   g_free (message);
155 }
156 
create_group_chat_cb(struct request_values_data * data,PurpleRequestFields * fields)157 static void create_group_chat_cb (struct request_values_data *data, PurpleRequestFields* fields) {
158   // FIXME: Oh god.
159   const char *users[3] = {
160     purple_request_fields_get_string (fields, "user1"),
161     purple_request_fields_get_string (fields, "user2"),
162     purple_request_fields_get_string (fields, "user3")
163   };
164 
165   tgp_create_group_chat_by_usernames (data->TLS, data->arg, users, 3, FALSE);
166   g_free (data->arg);
167   free (data);
168 }
169 
cancel_group_chat_cb(struct request_values_data * data)170 static void cancel_group_chat_cb (struct request_values_data *data) {
171   g_free (data->arg);
172   free (data);
173 }
174 
request_create_chat(struct tgl_state * TLS,const char * subject)175 void request_create_chat (struct tgl_state *TLS, const char *subject) {
176 
177   // Telegram doesn't allow to create chats with only one user, so we need to force
178   // the user to specify at least one other one.
179   PurpleRequestFields* fields = purple_request_fields_new ();
180   PurpleRequestFieldGroup* group = purple_request_field_group_new (
181       _("Invite at least one additional user by specifying\n their full name (autocompletion available).\nYou can add more users once"
182       " the chat was created."));
183 
184   PurpleRequestField *field = purple_request_field_string_new ("user1", _("Username"), NULL, FALSE);
185   purple_request_field_set_type_hint (field, "screenname");
186   purple_request_field_group_add_field (group, field);
187 
188   field = purple_request_field_string_new ("user2", _("Username"), NULL, FALSE);
189   purple_request_field_set_type_hint (field, "screenname");
190   purple_request_field_group_add_field (group, field);
191 
192   field = purple_request_field_string_new ("user3", _("Username"), NULL, FALSE);
193   purple_request_field_set_type_hint (field, "screenname");
194   purple_request_field_group_add_field (group, field);
195 
196   purple_request_fields_add_group (fields, group);
197   purple_request_fields (tls_get_conn (TLS), _("Create group chat"), _("Invite users"), NULL, fields, _("OK"),
198       G_CALLBACK(create_group_chat_cb), _("Cancel"), G_CALLBACK(cancel_group_chat_cb), tls_get_pa (TLS), NULL, NULL,
199       request_values_data_init (TLS, NULL, (void *) g_strdup (subject), 0));
200 }
201 
request_cur_and_new_password_ok(struct request_values_data * data,PurpleRequestFields * fields)202 static void request_cur_and_new_password_ok (struct request_values_data *data, PurpleRequestFields* fields) {
203   const char *names[3] = {
204       purple_request_fields_get_string (fields, "current"),
205       purple_request_fields_get_string (fields, "new1"),
206       purple_request_fields_get_string (fields, "new2")
207   };
208   data->callback(data->TLS, names, data->arg);
209   free (data);
210 }
211 
request_cur_and_new_password(struct tgl_state * TLS,void (* callback)(struct tgl_state * TLS,const char * string[],void * arg),void * arg)212 void request_cur_and_new_password (struct tgl_state *TLS,
213     void (*callback) (struct tgl_state *TLS, const char *string[], void *arg), void *arg) {
214 
215   PurpleRequestFields* fields = purple_request_fields_new ();
216   PurpleRequestFieldGroup* group = purple_request_field_group_new (_("Change password"));
217 
218   PurpleRequestField *field = purple_request_field_string_new ("current", _("Current"), NULL, FALSE);
219   purple_request_field_string_set_masked (field, TRUE);
220   purple_request_field_group_add_field (group, field);
221 
222   field = purple_request_field_string_new ("new1", _("Password"), NULL, FALSE);
223   purple_request_field_string_set_masked (field, TRUE);
224   purple_request_field_group_add_field (group, field);
225 
226   field = purple_request_field_string_new ("new2", _("Confirm"), NULL, FALSE);
227   purple_request_field_string_set_masked (field, TRUE);
228   purple_request_field_group_add_field (group, field);
229 
230   purple_request_fields_add_group (fields, group);
231   purple_request_fields (tls_get_conn (TLS), _("Change password"), _("Change password"), NULL, fields,
232       _("OK"), G_CALLBACK(request_cur_and_new_password_ok),
233       _("Cancel"), G_CALLBACK(request_canceled), tls_get_pa (TLS), NULL, NULL,
234       request_values_data_init (TLS, callback, arg, 0));
235 }
236 
request_new_password_ok(struct request_values_data * data,PurpleRequestFields * fields)237 static void request_new_password_ok (struct request_values_data *data, PurpleRequestFields* fields) {
238   const char *names[2] = {
239       purple_request_fields_get_string (fields, "new1"),
240       purple_request_fields_get_string (fields, "new2")
241   };
242   data->callback(data->TLS, names, data->arg);
243   free (data);
244 }
245 
request_new_password(struct tgl_state * TLS,void (* callback)(struct tgl_state * TLS,const char * string[],void * arg),void * arg)246 void request_new_password (struct tgl_state *TLS,
247     void (*callback) (struct tgl_state *TLS, const char *string[], void *arg), void *arg) {
248 
249   PurpleRequestFields* fields = purple_request_fields_new ();
250   PurpleRequestFieldGroup* group = purple_request_field_group_new (_("New password"));
251 
252   PurpleRequestField * field = purple_request_field_string_new ("new1", _("Password"), NULL, FALSE);
253   purple_request_field_string_set_masked (field, TRUE);
254   purple_request_field_group_add_field (group, field);
255 
256   field = purple_request_field_string_new ("new2", _("Confirm"), NULL, FALSE);
257   purple_request_field_string_set_masked (field, TRUE);
258   purple_request_field_group_add_field (group, field);
259 
260   purple_request_fields_add_group (fields, group);
261   purple_request_fields (tls_get_conn (TLS), _("New password"), _("New password"), NULL, fields,
262       _("OK"), G_CALLBACK(request_new_password_ok),
263       _("Cancel"), G_CALLBACK(request_canceled), tls_get_pa (TLS), NULL, NULL,
264       request_values_data_init (TLS, callback, arg, 0));
265 }
266 
request_value(struct tgl_state * TLS,enum tgl_value_type type,const char * prompt,int num_values,void (* callback)(struct tgl_state * TLS,const char * string[],void * arg),void * arg)267 void request_value (struct tgl_state *TLS, enum tgl_value_type type, const char *prompt, int num_values,
268     void (*callback) (struct tgl_state *TLS, const char *string[], void *arg), void *arg) {
269 
270   debug ("tgl requests user input, tgl_value_type: %d, prompt: %s, count: %d", type, prompt, num_values);
271   switch (type) {
272     case tgl_cur_password: {
273       const char *P = purple_account_get_string (tls_get_pa(TLS), TGP_KEY_PASSWORD_TWO_FACTOR, NULL);
274       if (str_not_empty (P)) {
275         if (tls_get_data (TLS)->password_retries ++ < 1) {
276           callback (TLS, &P, arg);
277           return;
278         }
279       }
280       request_password (TLS, callback, arg);
281       break;
282     }
283     case tgl_cur_and_new_password:
284       request_cur_and_new_password (TLS, callback, arg);
285       break;
286     case tgl_new_password:
287       request_new_password (TLS, callback, arg);
288       break;
289     case tgl_register_info:
290       request_name (TLS, callback, arg);
291       break;
292     case tgl_code:
293       request_code (TLS, callback, arg);
294       break;
295     case tgl_phone_number: {
296       // if we arrive here for the second time the specified phone number is not valid. We do not
297       // ask for the phone number directly, cause in that case the account would still be created
298       // named with the invalid phone number, even though the login will work
299       tgp_error_if_false (TLS, tls_get_data (TLS)->login_retries++ < 1, _("Invalid phone number"),
300           _("Please enter only numbers in the international phone number format, "
301               "a leading + following by the country prefix and the phone number.\n"
302               "Do not use any other special chars."));
303       const char *username = purple_account_get_username (tls_get_pa (TLS));
304       callback (TLS, &username, arg);
305       break;
306     }
307     case tgl_bot_hash:
308       assert (FALSE && "we are not a bot");
309       break;
310   }
311 }
312 
313 
314 // delete contact
315 
request_delete_contact_ok(struct request_values_data * data,PurpleRequestFields * fields)316 static void request_delete_contact_ok (struct request_values_data *data, PurpleRequestFields* fields) {
317   tgl_peer_t *P = data->arg;
318   g_return_if_fail(P);
319 
320   switch (tgl_get_peer_type (P->id)) {
321     case TGL_PEER_CHAT:
322       g_warn_if_fail (P->chat.flags & TGLCF_LEFT);
323       leave_and_delete_chat (data->TLS, P);
324       break;
325 
326     case TGL_PEER_ENCR_CHAT:
327       tgl_do_discard_secret_chat (data->TLS, &P->encr_chat, NULL, NULL);
328       break;
329 
330     case TGL_PEER_USER:
331       g_warn_if_fail(P->user.flags & TGLUF_CONTACT);
332       tgl_do_del_contact (data->TLS, P->id, tgp_notify_on_error_gw, NULL);
333       break;
334 
335     case TGL_PEER_CHANNEL:
336       g_warn_if_fail(P->channel.flags & TGLCHF_CREATOR);
337       if (! (P->channel.flags & TGLCHF_LEFT)) {
338         tgl_do_leave_channel (data->TLS, P->id, tgp_notify_on_error_gw, NULL);
339       }
340       break;
341 
342     default:
343       g_warn_if_reached();
344       break;
345   }
346 
347   free (data);
348 }
349 
request_delete_contact_cancel(struct request_values_data * data,PurpleRequestFields * fields)350 static void request_delete_contact_cancel (struct request_values_data *data, PurpleRequestFields* fields) {
351   free (data);
352 }
353 
tgprpl_request_delete_contact(PurpleConnection * gc,PurpleBuddy * buddy,PurpleGroup * group)354 void tgprpl_request_delete_contact (PurpleConnection *gc, PurpleBuddy *buddy, PurpleGroup *group) {
355   const char *title1 = NULL,
356              *title2 = NULL,
357                 *msg = NULL;
358 
359   g_return_if_fail(buddy);
360 
361   struct tgl_state *TLS = gc_get_tls (gc);
362 
363   tgl_peer_t *P = tgp_blist_buddy_get_peer (buddy);
364   g_return_if_fail(P);
365 
366   switch (tgl_get_peer_type (P->id)) {
367     case TGL_PEER_CHAT:
368       if (! (P->chat.flags & TGLCF_LEFT)) {
369         title1 = _("Leave Chat");
370         title2 = title1;
371         msg = _("Do you want to leave this chat permanently?");
372       }
373       break;
374 
375     case TGL_PEER_ENCR_CHAT:
376       title1 = _("Abort Secret Chat");
377       title2 = title1;
378       msg = _("Do you want to terminate this secret chat permanently?");
379       break;
380 
381     case TGL_PEER_USER:
382       if (P->user.flags & TGLUF_CONTACT) {
383         title1 = _("Delete Contact");
384         title2 = title1;
385         msg = _("Do you want to remove this user from your global contact list?");
386       }
387       break;
388 
389     case TGL_PEER_CHANNEL:
390       if (P->channel.flags & TGLCHF_CREATOR) {
391         /*
392          FIXME: Support destorying channels
393 
394          title1 = _("Destroy Channel");
395          title2 = title1;
396          msg = _("You are admin of this channel, do you want to delete it permanently?");
397         */
398       } else {
399         if (! (P->channel.flags & TGLCHF_LEFT)) {
400           title1 = _("Leave Channel");
401           title2 = title1;
402           msg = _("Do you want to leave this channel?");
403         }
404       }
405       break;
406 
407     default:
408       g_warn_if_reached();
409       break;
410   }
411 
412   if (msg) {
413     purple_request_ok_cancel(tls_get_conn (TLS), title1, title2, msg, 0, tls_get_pa (TLS),
414         tgp_blist_lookup_purple_name (TLS, P->id), NULL, (void *) request_values_data_init (TLS, 0, P, 0),
415         request_delete_contact_ok, request_delete_contact_cancel);
416   }
417 }
418 
419 
420 // add new contact
421 
request_add_contact(struct tgl_state * TLS)422 void request_add_contact (struct tgl_state *TLS) {
423 
424 }
425