1 /**
2  * @file request.c Request API
3  * @ingroup core
4  */
5 
6 /* purple
7  *
8  * Purple is the legal property of its developers, whose names are too numerous
9  * to list here.  Please refer to the COPYRIGHT file distributed with this
10  * source distribution.
11  *
12  * This program is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation; either version 2 of the License, or
15  * (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
25  */
26 #define _PURPLE_REQUEST_C_
27 
28 #include "internal.h"
29 
30 #include "glibcompat.h"
31 #include "notify.h"
32 #include "request.h"
33 #include "debug.h"
34 
35 static PurpleRequestUiOps *request_ui_ops = NULL;
36 static GList *handles = NULL;
37 
38 typedef struct
39 {
40 	PurpleRequestType type;
41 	void *handle;
42 	void *ui_handle;
43 
44 } PurpleRequestInfo;
45 
46 
47 PurpleRequestFields *
purple_request_fields_new(void)48 purple_request_fields_new(void)
49 {
50 	PurpleRequestFields *fields;
51 
52 	fields = g_new0(PurpleRequestFields, 1);
53 
54 	fields->fields = g_hash_table_new_full(g_str_hash, g_str_equal,
55 										   g_free, NULL);
56 
57 	return fields;
58 }
59 
60 void
purple_request_fields_destroy(PurpleRequestFields * fields)61 purple_request_fields_destroy(PurpleRequestFields *fields)
62 {
63 	g_return_if_fail(fields != NULL);
64 
65 	g_list_free_full(fields->groups,
66 	                 (GDestroyNotify)purple_request_field_group_destroy);
67 	g_list_free(fields->required_fields);
68 	g_hash_table_destroy(fields->fields);
69 	g_free(fields);
70 }
71 
72 void
purple_request_fields_add_group(PurpleRequestFields * fields,PurpleRequestFieldGroup * group)73 purple_request_fields_add_group(PurpleRequestFields *fields,
74 							  PurpleRequestFieldGroup *group)
75 {
76 	GList *l;
77 	PurpleRequestField *field;
78 
79 	g_return_if_fail(fields != NULL);
80 	g_return_if_fail(group  != NULL);
81 
82 	fields->groups = g_list_append(fields->groups, group);
83 
84 	group->fields_list = fields;
85 
86 	for (l = purple_request_field_group_get_fields(group);
87 		 l != NULL;
88 		 l = l->next) {
89 
90 		field = l->data;
91 
92 		g_hash_table_insert(fields->fields,
93 			g_strdup(purple_request_field_get_id(field)), field);
94 
95 		if (purple_request_field_is_required(field)) {
96 			fields->required_fields =
97 				g_list_append(fields->required_fields, field);
98 		}
99 
100 	}
101 }
102 
103 GList *
purple_request_fields_get_groups(const PurpleRequestFields * fields)104 purple_request_fields_get_groups(const PurpleRequestFields *fields)
105 {
106 	g_return_val_if_fail(fields != NULL, NULL);
107 
108 	return fields->groups;
109 }
110 
111 gboolean
purple_request_fields_exists(const PurpleRequestFields * fields,const char * id)112 purple_request_fields_exists(const PurpleRequestFields *fields, const char *id)
113 {
114 	g_return_val_if_fail(fields != NULL, FALSE);
115 	g_return_val_if_fail(id     != NULL, FALSE);
116 
117 	return (g_hash_table_lookup(fields->fields, id) != NULL);
118 }
119 
120 GList *
purple_request_fields_get_required(const PurpleRequestFields * fields)121 purple_request_fields_get_required(const PurpleRequestFields *fields)
122 {
123 	g_return_val_if_fail(fields != NULL, NULL);
124 
125 	return fields->required_fields;
126 }
127 
128 gboolean
purple_request_fields_is_field_required(const PurpleRequestFields * fields,const char * id)129 purple_request_fields_is_field_required(const PurpleRequestFields *fields,
130 									  const char *id)
131 {
132 	PurpleRequestField *field;
133 
134 	g_return_val_if_fail(fields != NULL, FALSE);
135 	g_return_val_if_fail(id     != NULL, FALSE);
136 
137 	if ((field = purple_request_fields_get_field(fields, id)) == NULL)
138 		return FALSE;
139 
140 	return purple_request_field_is_required(field);
141 }
142 
143 gpointer
purple_request_field_get_ui_data(const PurpleRequestField * field)144 purple_request_field_get_ui_data(const PurpleRequestField *field)
145 {
146 	g_return_val_if_fail(field != NULL, NULL);
147 
148 	return field->ui_data;
149 }
150 
151 void
purple_request_field_set_ui_data(PurpleRequestField * field,gpointer ui_data)152 purple_request_field_set_ui_data(PurpleRequestField *field,
153                                  gpointer ui_data)
154 {
155 	g_return_if_fail(field != NULL);
156 
157 	field->ui_data = ui_data;
158 }
159 
160 gboolean
purple_request_fields_all_required_filled(const PurpleRequestFields * fields)161 purple_request_fields_all_required_filled(const PurpleRequestFields *fields)
162 {
163 	GList *l;
164 
165 	g_return_val_if_fail(fields != NULL, FALSE);
166 
167 	for (l = fields->required_fields; l != NULL; l = l->next)
168 	{
169 		PurpleRequestField *field = (PurpleRequestField *)l->data;
170 
171 		switch (purple_request_field_get_type(field))
172 		{
173 			case PURPLE_REQUEST_FIELD_STRING:
174 				if (purple_request_field_string_get_value(field) == NULL ||
175 				    *(purple_request_field_string_get_value(field)) == '\0')
176 					return FALSE;
177 
178 				break;
179 
180 			default:
181 				break;
182 		}
183 	}
184 
185 	return TRUE;
186 }
187 
188 PurpleRequestField *
purple_request_fields_get_field(const PurpleRequestFields * fields,const char * id)189 purple_request_fields_get_field(const PurpleRequestFields *fields, const char *id)
190 {
191 	PurpleRequestField *field;
192 
193 	g_return_val_if_fail(fields != NULL, NULL);
194 	g_return_val_if_fail(id     != NULL, NULL);
195 
196 	field = g_hash_table_lookup(fields->fields, id);
197 
198 	g_return_val_if_fail(field != NULL, NULL);
199 
200 	return field;
201 }
202 
203 const char *
purple_request_fields_get_string(const PurpleRequestFields * fields,const char * id)204 purple_request_fields_get_string(const PurpleRequestFields *fields, const char *id)
205 {
206 	PurpleRequestField *field;
207 
208 	g_return_val_if_fail(fields != NULL, NULL);
209 	g_return_val_if_fail(id     != NULL, NULL);
210 
211 	if ((field = purple_request_fields_get_field(fields, id)) == NULL)
212 		return NULL;
213 
214 	return purple_request_field_string_get_value(field);
215 }
216 
217 int
purple_request_fields_get_integer(const PurpleRequestFields * fields,const char * id)218 purple_request_fields_get_integer(const PurpleRequestFields *fields,
219 								const char *id)
220 {
221 	PurpleRequestField *field;
222 
223 	g_return_val_if_fail(fields != NULL, 0);
224 	g_return_val_if_fail(id     != NULL, 0);
225 
226 	if ((field = purple_request_fields_get_field(fields, id)) == NULL)
227 		return 0;
228 
229 	return purple_request_field_int_get_value(field);
230 }
231 
232 gboolean
purple_request_fields_get_bool(const PurpleRequestFields * fields,const char * id)233 purple_request_fields_get_bool(const PurpleRequestFields *fields, const char *id)
234 {
235 	PurpleRequestField *field;
236 
237 	g_return_val_if_fail(fields != NULL, FALSE);
238 	g_return_val_if_fail(id     != NULL, FALSE);
239 
240 	if ((field = purple_request_fields_get_field(fields, id)) == NULL)
241 		return FALSE;
242 
243 	return purple_request_field_bool_get_value(field);
244 }
245 
246 int
purple_request_fields_get_choice(const PurpleRequestFields * fields,const char * id)247 purple_request_fields_get_choice(const PurpleRequestFields *fields, const char *id)
248 {
249 	PurpleRequestField *field;
250 
251 	g_return_val_if_fail(fields != NULL, -1);
252 	g_return_val_if_fail(id     != NULL, -1);
253 
254 	if ((field = purple_request_fields_get_field(fields, id)) == NULL)
255 		return -1;
256 
257 	return purple_request_field_choice_get_value(field);
258 }
259 
260 PurpleAccount *
purple_request_fields_get_account(const PurpleRequestFields * fields,const char * id)261 purple_request_fields_get_account(const PurpleRequestFields *fields,
262 								const char *id)
263 {
264 	PurpleRequestField *field;
265 
266 	g_return_val_if_fail(fields != NULL, NULL);
267 	g_return_val_if_fail(id     != NULL, NULL);
268 
269 	if ((field = purple_request_fields_get_field(fields, id)) == NULL)
270 		return NULL;
271 
272 	return purple_request_field_account_get_value(field);
273 }
274 
275 PurpleRequestFieldGroup *
purple_request_field_group_new(const char * title)276 purple_request_field_group_new(const char *title)
277 {
278 	PurpleRequestFieldGroup *group;
279 
280 	group = g_new0(PurpleRequestFieldGroup, 1);
281 
282 	group->title = g_strdup(title);
283 
284 	return group;
285 }
286 
287 void
purple_request_field_group_destroy(PurpleRequestFieldGroup * group)288 purple_request_field_group_destroy(PurpleRequestFieldGroup *group)
289 {
290 	g_return_if_fail(group != NULL);
291 
292 	g_free(group->title);
293 
294 	g_list_free_full(group->fields,
295 	                 (GDestroyNotify)purple_request_field_destroy);
296 
297 	g_free(group);
298 }
299 
300 void
purple_request_field_group_add_field(PurpleRequestFieldGroup * group,PurpleRequestField * field)301 purple_request_field_group_add_field(PurpleRequestFieldGroup *group,
302 								   PurpleRequestField *field)
303 {
304 	g_return_if_fail(group != NULL);
305 	g_return_if_fail(field != NULL);
306 
307 	group->fields = g_list_append(group->fields, field);
308 
309 	if (group->fields_list != NULL)
310 	{
311 		g_hash_table_insert(group->fields_list->fields,
312 							g_strdup(purple_request_field_get_id(field)), field);
313 
314 		if (purple_request_field_is_required(field))
315 		{
316 			group->fields_list->required_fields =
317 				g_list_append(group->fields_list->required_fields, field);
318 		}
319 	}
320 
321 	field->group = group;
322 
323 }
324 
325 const char *
purple_request_field_group_get_title(const PurpleRequestFieldGroup * group)326 purple_request_field_group_get_title(const PurpleRequestFieldGroup *group)
327 {
328 	g_return_val_if_fail(group != NULL, NULL);
329 
330 	return group->title;
331 }
332 
333 GList *
purple_request_field_group_get_fields(const PurpleRequestFieldGroup * group)334 purple_request_field_group_get_fields(const PurpleRequestFieldGroup *group)
335 {
336 	g_return_val_if_fail(group != NULL, NULL);
337 
338 	return group->fields;
339 }
340 
341 PurpleRequestField *
purple_request_field_new(const char * id,const char * text,PurpleRequestFieldType type)342 purple_request_field_new(const char *id, const char *text,
343 					   PurpleRequestFieldType type)
344 {
345 	PurpleRequestField *field;
346 
347 	g_return_val_if_fail(id   != NULL, NULL);
348 	g_return_val_if_fail(type != PURPLE_REQUEST_FIELD_NONE, NULL);
349 
350 	field = g_new0(PurpleRequestField, 1);
351 
352 	field->id   = g_strdup(id);
353 	field->type = type;
354 
355 	purple_request_field_set_label(field, text);
356 	purple_request_field_set_visible(field, TRUE);
357 
358 	return field;
359 }
360 
361 void
purple_request_field_destroy(PurpleRequestField * field)362 purple_request_field_destroy(PurpleRequestField *field)
363 {
364 	g_return_if_fail(field != NULL);
365 
366 	g_free(field->id);
367 	g_free(field->label);
368 	g_free(field->type_hint);
369 
370 	if (field->type == PURPLE_REQUEST_FIELD_STRING)
371 	{
372 		g_free(field->u.string.default_value);
373 		g_free(field->u.string.value);
374 	}
375 	else if (field->type == PURPLE_REQUEST_FIELD_CHOICE)
376 	{
377 		if (field->u.choice.labels != NULL)
378 		{
379 			g_list_free_full(field->u.choice.labels, (GDestroyNotify)g_free);
380 		}
381 	}
382 	else if (field->type == PURPLE_REQUEST_FIELD_LIST)
383 	{
384 		if (field->u.list.items != NULL)
385 		{
386 			g_list_free_full(field->u.list.items, (GDestroyNotify)g_free);
387 		}
388 
389 		if (field->u.list.selected != NULL)
390 		{
391 			g_list_free_full(field->u.list.selected, (GDestroyNotify)g_free);
392 		}
393 
394 		g_hash_table_destroy(field->u.list.item_data);
395 		g_hash_table_destroy(field->u.list.selected_table);
396 	}
397 
398 	g_free(field);
399 }
400 
401 void
purple_request_field_set_label(PurpleRequestField * field,const char * label)402 purple_request_field_set_label(PurpleRequestField *field, const char *label)
403 {
404 	g_return_if_fail(field != NULL);
405 
406 	g_free(field->label);
407 	field->label = g_strdup(label);
408 }
409 
410 void
purple_request_field_set_visible(PurpleRequestField * field,gboolean visible)411 purple_request_field_set_visible(PurpleRequestField *field, gboolean visible)
412 {
413 	g_return_if_fail(field != NULL);
414 
415 	field->visible = visible;
416 }
417 
418 void
purple_request_field_set_type_hint(PurpleRequestField * field,const char * type_hint)419 purple_request_field_set_type_hint(PurpleRequestField *field,
420 								 const char *type_hint)
421 {
422 	g_return_if_fail(field != NULL);
423 
424 	g_free(field->type_hint);
425 	field->type_hint = g_strdup(type_hint);
426 }
427 
428 void
purple_request_field_set_required(PurpleRequestField * field,gboolean required)429 purple_request_field_set_required(PurpleRequestField *field, gboolean required)
430 {
431 	g_return_if_fail(field != NULL);
432 
433 	if (field->required == required)
434 		return;
435 
436 	field->required = required;
437 
438 	if (field->group != NULL)
439 	{
440 		if (required)
441 		{
442 			field->group->fields_list->required_fields =
443 				g_list_append(field->group->fields_list->required_fields,
444 							  field);
445 		}
446 		else
447 		{
448 			field->group->fields_list->required_fields =
449 				g_list_remove(field->group->fields_list->required_fields,
450 							  field);
451 		}
452 	}
453 }
454 
455 PurpleRequestFieldType
purple_request_field_get_type(const PurpleRequestField * field)456 purple_request_field_get_type(const PurpleRequestField *field)
457 {
458 	g_return_val_if_fail(field != NULL, PURPLE_REQUEST_FIELD_NONE);
459 
460 	return field->type;
461 }
462 
463 PurpleRequestFieldGroup *
purple_request_field_get_group(const PurpleRequestField * field)464 purple_request_field_get_group(const PurpleRequestField *field)
465 {
466 	g_return_val_if_fail(field != NULL, NULL);
467 
468 	return field->group;
469 }
470 
471 const char *
purple_request_field_get_id(const PurpleRequestField * field)472 purple_request_field_get_id(const PurpleRequestField *field)
473 {
474 	g_return_val_if_fail(field != NULL, NULL);
475 
476 	return field->id;
477 }
478 
479 const char *
purple_request_field_get_label(const PurpleRequestField * field)480 purple_request_field_get_label(const PurpleRequestField *field)
481 {
482 	g_return_val_if_fail(field != NULL, NULL);
483 
484 	return field->label;
485 }
486 
487 gboolean
purple_request_field_is_visible(const PurpleRequestField * field)488 purple_request_field_is_visible(const PurpleRequestField *field)
489 {
490 	g_return_val_if_fail(field != NULL, FALSE);
491 
492 	return field->visible;
493 }
494 
495 const char *
purple_request_field_get_type_hint(const PurpleRequestField * field)496 purple_request_field_get_type_hint(const PurpleRequestField *field)
497 {
498 	g_return_val_if_fail(field != NULL, NULL);
499 
500 	return field->type_hint;
501 }
502 
503 gboolean
purple_request_field_is_required(const PurpleRequestField * field)504 purple_request_field_is_required(const PurpleRequestField *field)
505 {
506 	g_return_val_if_fail(field != NULL, FALSE);
507 
508 	return field->required;
509 }
510 
511 PurpleRequestField *
purple_request_field_string_new(const char * id,const char * text,const char * default_value,gboolean multiline)512 purple_request_field_string_new(const char *id, const char *text,
513 							  const char *default_value, gboolean multiline)
514 {
515 	PurpleRequestField *field;
516 
517 	g_return_val_if_fail(id   != NULL, NULL);
518 	g_return_val_if_fail(text != NULL, NULL);
519 
520 	field = purple_request_field_new(id, text, PURPLE_REQUEST_FIELD_STRING);
521 
522 	field->u.string.multiline = multiline;
523 	field->u.string.editable  = TRUE;
524 
525 	purple_request_field_string_set_default_value(field, default_value);
526 	purple_request_field_string_set_value(field, default_value);
527 
528 	return field;
529 }
530 
531 void
purple_request_field_string_set_default_value(PurpleRequestField * field,const char * default_value)532 purple_request_field_string_set_default_value(PurpleRequestField *field,
533 											const char *default_value)
534 {
535 	g_return_if_fail(field != NULL);
536 	g_return_if_fail(field->type == PURPLE_REQUEST_FIELD_STRING);
537 
538 	g_free(field->u.string.default_value);
539 	field->u.string.default_value = g_strdup(default_value);
540 }
541 
542 void
purple_request_field_string_set_value(PurpleRequestField * field,const char * value)543 purple_request_field_string_set_value(PurpleRequestField *field, const char *value)
544 {
545 	g_return_if_fail(field != NULL);
546 	g_return_if_fail(field->type == PURPLE_REQUEST_FIELD_STRING);
547 
548 	g_free(field->u.string.value);
549 	field->u.string.value = g_strdup(value);
550 }
551 
552 void
purple_request_field_string_set_masked(PurpleRequestField * field,gboolean masked)553 purple_request_field_string_set_masked(PurpleRequestField *field, gboolean masked)
554 {
555 	g_return_if_fail(field != NULL);
556 	g_return_if_fail(field->type == PURPLE_REQUEST_FIELD_STRING);
557 
558 	field->u.string.masked = masked;
559 }
560 
561 void
purple_request_field_string_set_editable(PurpleRequestField * field,gboolean editable)562 purple_request_field_string_set_editable(PurpleRequestField *field,
563 									   gboolean editable)
564 {
565 	g_return_if_fail(field != NULL);
566 	g_return_if_fail(field->type == PURPLE_REQUEST_FIELD_STRING);
567 
568 	field->u.string.editable = editable;
569 }
570 
571 const char *
purple_request_field_string_get_default_value(const PurpleRequestField * field)572 purple_request_field_string_get_default_value(const PurpleRequestField *field)
573 {
574 	g_return_val_if_fail(field != NULL, NULL);
575 	g_return_val_if_fail(field->type == PURPLE_REQUEST_FIELD_STRING, NULL);
576 
577 	return field->u.string.default_value;
578 }
579 
580 const char *
purple_request_field_string_get_value(const PurpleRequestField * field)581 purple_request_field_string_get_value(const PurpleRequestField *field)
582 {
583 	g_return_val_if_fail(field != NULL, NULL);
584 	g_return_val_if_fail(field->type == PURPLE_REQUEST_FIELD_STRING, NULL);
585 
586 	return field->u.string.value;
587 }
588 
589 gboolean
purple_request_field_string_is_multiline(const PurpleRequestField * field)590 purple_request_field_string_is_multiline(const PurpleRequestField *field)
591 {
592 	g_return_val_if_fail(field != NULL, FALSE);
593 	g_return_val_if_fail(field->type == PURPLE_REQUEST_FIELD_STRING, FALSE);
594 
595 	return field->u.string.multiline;
596 }
597 
598 gboolean
purple_request_field_string_is_masked(const PurpleRequestField * field)599 purple_request_field_string_is_masked(const PurpleRequestField *field)
600 {
601 	g_return_val_if_fail(field != NULL, FALSE);
602 	g_return_val_if_fail(field->type == PURPLE_REQUEST_FIELD_STRING, FALSE);
603 
604 	return field->u.string.masked;
605 }
606 
607 gboolean
purple_request_field_string_is_editable(const PurpleRequestField * field)608 purple_request_field_string_is_editable(const PurpleRequestField *field)
609 {
610 	g_return_val_if_fail(field != NULL, FALSE);
611 	g_return_val_if_fail(field->type == PURPLE_REQUEST_FIELD_STRING, FALSE);
612 
613 	return field->u.string.editable;
614 }
615 
616 PurpleRequestField *
purple_request_field_int_new(const char * id,const char * text,int default_value)617 purple_request_field_int_new(const char *id, const char *text,
618 						   int default_value)
619 {
620 	PurpleRequestField *field;
621 
622 	g_return_val_if_fail(id   != NULL, NULL);
623 	g_return_val_if_fail(text != NULL, NULL);
624 
625 	field = purple_request_field_new(id, text, PURPLE_REQUEST_FIELD_INTEGER);
626 
627 	purple_request_field_int_set_default_value(field, default_value);
628 	purple_request_field_int_set_value(field, default_value);
629 
630 	return field;
631 }
632 
633 void
purple_request_field_int_set_default_value(PurpleRequestField * field,int default_value)634 purple_request_field_int_set_default_value(PurpleRequestField *field,
635 										 int default_value)
636 {
637 	g_return_if_fail(field != NULL);
638 	g_return_if_fail(field->type == PURPLE_REQUEST_FIELD_INTEGER);
639 
640 	field->u.integer.default_value = default_value;
641 }
642 
643 void
purple_request_field_int_set_value(PurpleRequestField * field,int value)644 purple_request_field_int_set_value(PurpleRequestField *field, int value)
645 {
646 	g_return_if_fail(field != NULL);
647 	g_return_if_fail(field->type == PURPLE_REQUEST_FIELD_INTEGER);
648 
649 	field->u.integer.value = value;
650 }
651 
652 int
purple_request_field_int_get_default_value(const PurpleRequestField * field)653 purple_request_field_int_get_default_value(const PurpleRequestField *field)
654 {
655 	g_return_val_if_fail(field != NULL, 0);
656 	g_return_val_if_fail(field->type == PURPLE_REQUEST_FIELD_INTEGER, 0);
657 
658 	return field->u.integer.default_value;
659 }
660 
661 int
purple_request_field_int_get_value(const PurpleRequestField * field)662 purple_request_field_int_get_value(const PurpleRequestField *field)
663 {
664 	g_return_val_if_fail(field != NULL, 0);
665 	g_return_val_if_fail(field->type == PURPLE_REQUEST_FIELD_INTEGER, 0);
666 
667 	return field->u.integer.value;
668 }
669 
670 PurpleRequestField *
purple_request_field_bool_new(const char * id,const char * text,gboolean default_value)671 purple_request_field_bool_new(const char *id, const char *text,
672 							gboolean default_value)
673 {
674 	PurpleRequestField *field;
675 
676 	g_return_val_if_fail(id   != NULL, NULL);
677 	g_return_val_if_fail(text != NULL, NULL);
678 
679 	field = purple_request_field_new(id, text, PURPLE_REQUEST_FIELD_BOOLEAN);
680 
681 	purple_request_field_bool_set_default_value(field, default_value);
682 	purple_request_field_bool_set_value(field, default_value);
683 
684 	return field;
685 }
686 
687 void
purple_request_field_bool_set_default_value(PurpleRequestField * field,gboolean default_value)688 purple_request_field_bool_set_default_value(PurpleRequestField *field,
689 										  gboolean default_value)
690 {
691 	g_return_if_fail(field != NULL);
692 	g_return_if_fail(field->type == PURPLE_REQUEST_FIELD_BOOLEAN);
693 
694 	field->u.boolean.default_value = default_value;
695 }
696 
697 void
purple_request_field_bool_set_value(PurpleRequestField * field,gboolean value)698 purple_request_field_bool_set_value(PurpleRequestField *field, gboolean value)
699 {
700 	g_return_if_fail(field != NULL);
701 	g_return_if_fail(field->type == PURPLE_REQUEST_FIELD_BOOLEAN);
702 
703 	field->u.boolean.value = value;
704 }
705 
706 gboolean
purple_request_field_bool_get_default_value(const PurpleRequestField * field)707 purple_request_field_bool_get_default_value(const PurpleRequestField *field)
708 {
709 	g_return_val_if_fail(field != NULL, FALSE);
710 	g_return_val_if_fail(field->type == PURPLE_REQUEST_FIELD_BOOLEAN, FALSE);
711 
712 	return field->u.boolean.default_value;
713 }
714 
715 gboolean
purple_request_field_bool_get_value(const PurpleRequestField * field)716 purple_request_field_bool_get_value(const PurpleRequestField *field)
717 {
718 	g_return_val_if_fail(field != NULL, FALSE);
719 	g_return_val_if_fail(field->type == PURPLE_REQUEST_FIELD_BOOLEAN, FALSE);
720 
721 	return field->u.boolean.value;
722 }
723 
724 PurpleRequestField *
purple_request_field_choice_new(const char * id,const char * text,int default_value)725 purple_request_field_choice_new(const char *id, const char *text,
726 							  int default_value)
727 {
728 	PurpleRequestField *field;
729 
730 	g_return_val_if_fail(id   != NULL, NULL);
731 	g_return_val_if_fail(text != NULL, NULL);
732 
733 	field = purple_request_field_new(id, text, PURPLE_REQUEST_FIELD_CHOICE);
734 
735 	purple_request_field_choice_set_default_value(field, default_value);
736 	purple_request_field_choice_set_value(field, default_value);
737 
738 	return field;
739 }
740 
741 void
purple_request_field_choice_add(PurpleRequestField * field,const char * label)742 purple_request_field_choice_add(PurpleRequestField *field, const char *label)
743 {
744 	g_return_if_fail(field != NULL);
745 	g_return_if_fail(label != NULL);
746 	g_return_if_fail(field->type == PURPLE_REQUEST_FIELD_CHOICE);
747 
748 	field->u.choice.labels = g_list_append(field->u.choice.labels,
749 											g_strdup(label));
750 }
751 
752 void
purple_request_field_choice_set_default_value(PurpleRequestField * field,int default_value)753 purple_request_field_choice_set_default_value(PurpleRequestField *field,
754 											int default_value)
755 {
756 	g_return_if_fail(field != NULL);
757 	g_return_if_fail(field->type == PURPLE_REQUEST_FIELD_CHOICE);
758 
759 	field->u.choice.default_value = default_value;
760 }
761 
762 void
purple_request_field_choice_set_value(PurpleRequestField * field,int value)763 purple_request_field_choice_set_value(PurpleRequestField *field,
764 											int value)
765 {
766 	g_return_if_fail(field != NULL);
767 	g_return_if_fail(field->type == PURPLE_REQUEST_FIELD_CHOICE);
768 
769 	field->u.choice.value = value;
770 }
771 
772 int
purple_request_field_choice_get_default_value(const PurpleRequestField * field)773 purple_request_field_choice_get_default_value(const PurpleRequestField *field)
774 {
775 	g_return_val_if_fail(field != NULL, -1);
776 	g_return_val_if_fail(field->type == PURPLE_REQUEST_FIELD_CHOICE, -1);
777 
778 	return field->u.choice.default_value;
779 }
780 
781 int
purple_request_field_choice_get_value(const PurpleRequestField * field)782 purple_request_field_choice_get_value(const PurpleRequestField *field)
783 {
784 	g_return_val_if_fail(field != NULL, -1);
785 	g_return_val_if_fail(field->type == PURPLE_REQUEST_FIELD_CHOICE, -1);
786 
787 	return field->u.choice.value;
788 }
789 
790 GList *
purple_request_field_choice_get_labels(const PurpleRequestField * field)791 purple_request_field_choice_get_labels(const PurpleRequestField *field)
792 {
793 	g_return_val_if_fail(field != NULL, NULL);
794 	g_return_val_if_fail(field->type == PURPLE_REQUEST_FIELD_CHOICE, NULL);
795 
796 	return field->u.choice.labels;
797 }
798 
799 PurpleRequestField *
purple_request_field_list_new(const char * id,const char * text)800 purple_request_field_list_new(const char *id, const char *text)
801 {
802 	PurpleRequestField *field;
803 
804 	g_return_val_if_fail(id   != NULL, NULL);
805 
806 	field = purple_request_field_new(id, text, PURPLE_REQUEST_FIELD_LIST);
807 
808 	field->u.list.item_data = g_hash_table_new_full(g_str_hash, g_str_equal,
809 													g_free, NULL);
810 
811 	field->u.list.selected_table =
812 		g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
813 
814 	return field;
815 }
816 
817 void
purple_request_field_list_set_multi_select(PurpleRequestField * field,gboolean multi_select)818 purple_request_field_list_set_multi_select(PurpleRequestField *field,
819 										 gboolean multi_select)
820 {
821 	g_return_if_fail(field != NULL);
822 	g_return_if_fail(field->type == PURPLE_REQUEST_FIELD_LIST);
823 
824 	field->u.list.multiple_selection = multi_select;
825 }
826 
827 gboolean
purple_request_field_list_get_multi_select(const PurpleRequestField * field)828 purple_request_field_list_get_multi_select(const PurpleRequestField *field)
829 {
830 	g_return_val_if_fail(field != NULL, FALSE);
831 	g_return_val_if_fail(field->type == PURPLE_REQUEST_FIELD_LIST, FALSE);
832 
833 	return field->u.list.multiple_selection;
834 }
835 
836 void *
purple_request_field_list_get_data(const PurpleRequestField * field,const char * text)837 purple_request_field_list_get_data(const PurpleRequestField *field,
838 								 const char *text)
839 {
840 	g_return_val_if_fail(field != NULL, NULL);
841 	g_return_val_if_fail(text  != NULL, NULL);
842 	g_return_val_if_fail(field->type == PURPLE_REQUEST_FIELD_LIST, NULL);
843 
844 	return g_hash_table_lookup(field->u.list.item_data, text);
845 }
846 
847 void
purple_request_field_list_add(PurpleRequestField * field,const char * item,void * data)848 purple_request_field_list_add(PurpleRequestField *field, const char *item,
849 							void *data)
850 {
851 	purple_request_field_list_add_icon(field, item, NULL, data);
852 }
853 
854 void
purple_request_field_list_add_icon(PurpleRequestField * field,const char * item,const char * icon_path,void * data)855 purple_request_field_list_add_icon(PurpleRequestField *field, const char *item, const char* icon_path,
856 							void *data)
857 {
858 	g_return_if_fail(field != NULL);
859 	g_return_if_fail(item  != NULL);
860 	g_return_if_fail(data  != NULL);
861 	g_return_if_fail(field->type == PURPLE_REQUEST_FIELD_LIST);
862 
863 	if (icon_path)
864 	{
865 		if (field->u.list.icons == NULL)
866 		{
867 			GList *l;
868 			for (l = field->u.list.items ; l != NULL ; l = l->next)
869 			{
870 				/* Order doesn't matter, because we're just
871 				 * filing in blank items.  So, we use
872 				 * g_list_prepend() because it's faster. */
873 				field->u.list.icons = g_list_prepend(field->u.list.icons, NULL);
874 			}
875 		}
876 		field->u.list.icons = g_list_append(field->u.list.icons, g_strdup(icon_path));
877 	}
878 	else if (field->u.list.icons)
879 	{
880 		/* Keep this even with the items list. */
881 		field->u.list.icons = g_list_append(field->u.list.icons, NULL);
882 	}
883 
884 	field->u.list.items = g_list_append(field->u.list.items, g_strdup(item));
885 	g_hash_table_insert(field->u.list.item_data, g_strdup(item), data);
886 }
887 
888 void
purple_request_field_list_add_selected(PurpleRequestField * field,const char * item)889 purple_request_field_list_add_selected(PurpleRequestField *field, const char *item)
890 {
891 	g_return_if_fail(field != NULL);
892 	g_return_if_fail(item  != NULL);
893 	g_return_if_fail(field->type == PURPLE_REQUEST_FIELD_LIST);
894 
895 	if (!purple_request_field_list_get_multi_select(field) &&
896 		field->u.list.selected != NULL)
897 	{
898 		purple_debug_warning("request",
899 						   "More than one item added to non-multi-select "
900 						   "field %s\n",
901 						   purple_request_field_get_id(field));
902 		return;
903 	}
904 
905 	field->u.list.selected = g_list_append(field->u.list.selected,
906 										   g_strdup(item));
907 
908 	g_hash_table_insert(field->u.list.selected_table, g_strdup(item), NULL);
909 }
910 
911 void
purple_request_field_list_clear_selected(PurpleRequestField * field)912 purple_request_field_list_clear_selected(PurpleRequestField *field)
913 {
914 	g_return_if_fail(field != NULL);
915 	g_return_if_fail(field->type == PURPLE_REQUEST_FIELD_LIST);
916 
917 	if (field->u.list.selected != NULL)
918 	{
919 		g_list_free_full(field->u.list.selected, (GDestroyNotify)g_free);
920 		field->u.list.selected = NULL;
921 	}
922 
923 	g_hash_table_destroy(field->u.list.selected_table);
924 
925 	field->u.list.selected_table =
926 		g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
927 }
928 
929 void
purple_request_field_list_set_selected(PurpleRequestField * field,GList * items)930 purple_request_field_list_set_selected(PurpleRequestField *field, GList *items)
931 {
932 	GList *l;
933 
934 	g_return_if_fail(field != NULL);
935 	g_return_if_fail(items != NULL);
936 	g_return_if_fail(field->type == PURPLE_REQUEST_FIELD_LIST);
937 
938 	purple_request_field_list_clear_selected(field);
939 
940 	if (!purple_request_field_list_get_multi_select(field) &&
941 		items && items->next)
942 	{
943 		purple_debug_warning("request",
944 						   "More than one item added to non-multi-select "
945 						   "field %s\n",
946 						   purple_request_field_get_id(field));
947 		return;
948 	}
949 
950 	for (l = items; l != NULL; l = l->next)
951 	{
952 		field->u.list.selected = g_list_append(field->u.list.selected,
953 					g_strdup(l->data));
954 		g_hash_table_insert(field->u.list.selected_table,
955 							g_strdup((char *)l->data), NULL);
956 	}
957 }
958 
959 gboolean
purple_request_field_list_is_selected(const PurpleRequestField * field,const char * item)960 purple_request_field_list_is_selected(const PurpleRequestField *field,
961 									const char *item)
962 {
963 	g_return_val_if_fail(field != NULL, FALSE);
964 	g_return_val_if_fail(item  != NULL, FALSE);
965 	g_return_val_if_fail(field->type == PURPLE_REQUEST_FIELD_LIST, FALSE);
966 
967 	return g_hash_table_lookup_extended(field->u.list.selected_table,
968 										item, NULL, NULL);
969 }
970 
971 GList *
purple_request_field_list_get_selected(const PurpleRequestField * field)972 purple_request_field_list_get_selected(const PurpleRequestField *field)
973 {
974 	g_return_val_if_fail(field != NULL, NULL);
975 	g_return_val_if_fail(field->type == PURPLE_REQUEST_FIELD_LIST, NULL);
976 
977 	return field->u.list.selected;
978 }
979 
980 GList *
purple_request_field_list_get_items(const PurpleRequestField * field)981 purple_request_field_list_get_items(const PurpleRequestField *field)
982 {
983 	g_return_val_if_fail(field != NULL, NULL);
984 	g_return_val_if_fail(field->type == PURPLE_REQUEST_FIELD_LIST, NULL);
985 
986 	return field->u.list.items;
987 }
988 
989 GList *
purple_request_field_list_get_icons(const PurpleRequestField * field)990 purple_request_field_list_get_icons(const PurpleRequestField *field)
991 {
992 	g_return_val_if_fail(field != NULL, NULL);
993 	g_return_val_if_fail(field->type == PURPLE_REQUEST_FIELD_LIST, NULL);
994 
995 	return field->u.list.icons;
996 }
997 
998 PurpleRequestField *
purple_request_field_label_new(const char * id,const char * text)999 purple_request_field_label_new(const char *id, const char *text)
1000 {
1001 	PurpleRequestField *field;
1002 
1003 	g_return_val_if_fail(id   != NULL, NULL);
1004 	g_return_val_if_fail(text != NULL, NULL);
1005 
1006 	field = purple_request_field_new(id, text, PURPLE_REQUEST_FIELD_LABEL);
1007 
1008 	return field;
1009 }
1010 
1011 PurpleRequestField *
purple_request_field_image_new(const char * id,const char * text,const char * buf,gsize size)1012 purple_request_field_image_new(const char *id, const char *text, const char *buf, gsize size)
1013 {
1014 	PurpleRequestField *field;
1015 
1016 	g_return_val_if_fail(id   != NULL, NULL);
1017 	g_return_val_if_fail(text != NULL, NULL);
1018 	g_return_val_if_fail(buf  != NULL, NULL);
1019 	g_return_val_if_fail(size > 0, NULL);
1020 
1021 	field = purple_request_field_new(id, text, PURPLE_REQUEST_FIELD_IMAGE);
1022 
1023 	field->u.image.buffer  = g_memdup2(buf, size);
1024 	field->u.image.size    = size;
1025 	field->u.image.scale_x = 1;
1026 	field->u.image.scale_y = 1;
1027 
1028 	return field;
1029 }
1030 
1031 void
purple_request_field_image_set_scale(PurpleRequestField * field,unsigned int x,unsigned int y)1032 purple_request_field_image_set_scale(PurpleRequestField *field, unsigned int x, unsigned int y)
1033 {
1034 	g_return_if_fail(field != NULL);
1035 	g_return_if_fail(field->type == PURPLE_REQUEST_FIELD_IMAGE);
1036 
1037 	field->u.image.scale_x = x;
1038 	field->u.image.scale_y = y;
1039 }
1040 
1041 const char *
purple_request_field_image_get_buffer(PurpleRequestField * field)1042 purple_request_field_image_get_buffer(PurpleRequestField *field)
1043 {
1044 	g_return_val_if_fail(field != NULL, NULL);
1045 	g_return_val_if_fail(field->type == PURPLE_REQUEST_FIELD_IMAGE, NULL);
1046 
1047 	return field->u.image.buffer;
1048 }
1049 
1050 gsize
purple_request_field_image_get_size(PurpleRequestField * field)1051 purple_request_field_image_get_size(PurpleRequestField *field)
1052 {
1053 	g_return_val_if_fail(field != NULL, 0);
1054 	g_return_val_if_fail(field->type == PURPLE_REQUEST_FIELD_IMAGE, 0);
1055 
1056 	return field->u.image.size;
1057 }
1058 
1059 unsigned int
purple_request_field_image_get_scale_x(PurpleRequestField * field)1060 purple_request_field_image_get_scale_x(PurpleRequestField *field)
1061 {
1062 	g_return_val_if_fail(field != NULL, 0);
1063 	g_return_val_if_fail(field->type == PURPLE_REQUEST_FIELD_IMAGE, 0);
1064 
1065 	return field->u.image.scale_x;
1066 }
1067 
1068 unsigned int
purple_request_field_image_get_scale_y(PurpleRequestField * field)1069 purple_request_field_image_get_scale_y(PurpleRequestField *field)
1070 {
1071 	g_return_val_if_fail(field != NULL, 0);
1072 	g_return_val_if_fail(field->type == PURPLE_REQUEST_FIELD_IMAGE, 0);
1073 
1074 	return field->u.image.scale_y;
1075 }
1076 
1077 PurpleRequestField *
purple_request_field_account_new(const char * id,const char * text,PurpleAccount * account)1078 purple_request_field_account_new(const char *id, const char *text,
1079 							   PurpleAccount *account)
1080 {
1081 	PurpleRequestField *field;
1082 
1083 	g_return_val_if_fail(id   != NULL, NULL);
1084 	g_return_val_if_fail(text != NULL, NULL);
1085 
1086 	field = purple_request_field_new(id, text, PURPLE_REQUEST_FIELD_ACCOUNT);
1087 
1088 	if (account == NULL && purple_connections_get_all() != NULL)
1089 	{
1090 		account = purple_connection_get_account(
1091 			(PurpleConnection *)purple_connections_get_all()->data);
1092 	}
1093 
1094 	purple_request_field_account_set_default_value(field, account);
1095 	purple_request_field_account_set_value(field, account);
1096 
1097 	return field;
1098 }
1099 
1100 void
purple_request_field_account_set_default_value(PurpleRequestField * field,PurpleAccount * default_value)1101 purple_request_field_account_set_default_value(PurpleRequestField *field,
1102 											 PurpleAccount *default_value)
1103 {
1104 	g_return_if_fail(field != NULL);
1105 	g_return_if_fail(field->type == PURPLE_REQUEST_FIELD_ACCOUNT);
1106 
1107 	field->u.account.default_account = default_value;
1108 }
1109 
1110 void
purple_request_field_account_set_value(PurpleRequestField * field,PurpleAccount * value)1111 purple_request_field_account_set_value(PurpleRequestField *field,
1112 									 PurpleAccount *value)
1113 {
1114 	g_return_if_fail(field != NULL);
1115 	g_return_if_fail(field->type == PURPLE_REQUEST_FIELD_ACCOUNT);
1116 
1117 	field->u.account.account = value;
1118 }
1119 
1120 void
purple_request_field_account_set_show_all(PurpleRequestField * field,gboolean show_all)1121 purple_request_field_account_set_show_all(PurpleRequestField *field,
1122 										gboolean show_all)
1123 {
1124 	g_return_if_fail(field != NULL);
1125 	g_return_if_fail(field->type == PURPLE_REQUEST_FIELD_ACCOUNT);
1126 
1127 	if (field->u.account.show_all == show_all)
1128 		return;
1129 
1130 	field->u.account.show_all = show_all;
1131 
1132 	if (!show_all)
1133 	{
1134 		if (purple_account_is_connected(field->u.account.default_account))
1135 		{
1136 			purple_request_field_account_set_default_value(field,
1137 				(PurpleAccount *)purple_connections_get_all()->data);
1138 		}
1139 
1140 		if (purple_account_is_connected(field->u.account.account))
1141 		{
1142 			purple_request_field_account_set_value(field,
1143 				(PurpleAccount *)purple_connections_get_all()->data);
1144 		}
1145 	}
1146 }
1147 
1148 void
purple_request_field_account_set_filter(PurpleRequestField * field,PurpleFilterAccountFunc filter_func)1149 purple_request_field_account_set_filter(PurpleRequestField *field,
1150 									  PurpleFilterAccountFunc filter_func)
1151 {
1152 	g_return_if_fail(field != NULL);
1153 	g_return_if_fail(field->type == PURPLE_REQUEST_FIELD_ACCOUNT);
1154 
1155 	field->u.account.filter_func = filter_func;
1156 }
1157 
1158 PurpleAccount *
purple_request_field_account_get_default_value(const PurpleRequestField * field)1159 purple_request_field_account_get_default_value(const PurpleRequestField *field)
1160 {
1161 	g_return_val_if_fail(field != NULL, NULL);
1162 	g_return_val_if_fail(field->type == PURPLE_REQUEST_FIELD_ACCOUNT, NULL);
1163 
1164 	return field->u.account.default_account;
1165 }
1166 
1167 PurpleAccount *
purple_request_field_account_get_value(const PurpleRequestField * field)1168 purple_request_field_account_get_value(const PurpleRequestField *field)
1169 {
1170 	g_return_val_if_fail(field != NULL, NULL);
1171 	g_return_val_if_fail(field->type == PURPLE_REQUEST_FIELD_ACCOUNT, NULL);
1172 
1173 	return field->u.account.account;
1174 }
1175 
1176 gboolean
purple_request_field_account_get_show_all(const PurpleRequestField * field)1177 purple_request_field_account_get_show_all(const PurpleRequestField *field)
1178 {
1179 	g_return_val_if_fail(field != NULL, FALSE);
1180 	g_return_val_if_fail(field->type == PURPLE_REQUEST_FIELD_ACCOUNT, FALSE);
1181 
1182 	return field->u.account.show_all;
1183 }
1184 
1185 PurpleFilterAccountFunc
purple_request_field_account_get_filter(const PurpleRequestField * field)1186 purple_request_field_account_get_filter(const PurpleRequestField *field)
1187 {
1188 	g_return_val_if_fail(field != NULL, FALSE);
1189 	g_return_val_if_fail(field->type == PURPLE_REQUEST_FIELD_ACCOUNT, FALSE);
1190 
1191 	return field->u.account.filter_func;
1192 }
1193 
1194 /* -- */
1195 
1196 void *
purple_request_input(void * handle,const char * title,const char * primary,const char * secondary,const char * default_value,gboolean multiline,gboolean masked,gchar * hint,const char * ok_text,GCallback ok_cb,const char * cancel_text,GCallback cancel_cb,PurpleAccount * account,const char * who,PurpleConversation * conv,void * user_data)1197 purple_request_input(void *handle, const char *title, const char *primary,
1198 				   const char *secondary, const char *default_value,
1199 				   gboolean multiline, gboolean masked, gchar *hint,
1200 				   const char *ok_text, GCallback ok_cb,
1201 				   const char *cancel_text, GCallback cancel_cb,
1202 				   PurpleAccount *account, const char *who, PurpleConversation *conv,
1203 				   void *user_data)
1204 {
1205 	PurpleRequestUiOps *ops;
1206 
1207 	g_return_val_if_fail(ok_text != NULL, NULL);
1208 	g_return_val_if_fail(ok_cb   != NULL, NULL);
1209 
1210 	ops = purple_request_get_ui_ops();
1211 
1212 	if (ops != NULL && ops->request_input != NULL) {
1213 		PurpleRequestInfo *info;
1214 
1215 		info            = g_new0(PurpleRequestInfo, 1);
1216 		info->type      = PURPLE_REQUEST_INPUT;
1217 		info->handle    = handle;
1218 		info->ui_handle = ops->request_input(title, primary, secondary,
1219 											 default_value,
1220 											 multiline, masked, hint,
1221 											 ok_text, ok_cb,
1222 											 cancel_text, cancel_cb,
1223 											 account, who, conv,
1224 											 user_data);
1225 
1226 		handles = g_list_append(handles, info);
1227 
1228 		return info->ui_handle;
1229 	}
1230 
1231 	return NULL;
1232 }
1233 
1234 void *
purple_request_choice(void * handle,const char * title,const char * primary,const char * secondary,int default_value,const char * ok_text,GCallback ok_cb,const char * cancel_text,GCallback cancel_cb,PurpleAccount * account,const char * who,PurpleConversation * conv,void * user_data,...)1235 purple_request_choice(void *handle, const char *title, const char *primary,
1236 					const char *secondary, int default_value,
1237 					const char *ok_text, GCallback ok_cb,
1238 					const char *cancel_text, GCallback cancel_cb,
1239 					PurpleAccount *account, const char *who, PurpleConversation *conv,
1240 					void *user_data, ...)
1241 {
1242 	void *ui_handle;
1243 	va_list args;
1244 
1245 	g_return_val_if_fail(ok_text != NULL,  NULL);
1246 	g_return_val_if_fail(ok_cb   != NULL,  NULL);
1247 
1248 	va_start(args, user_data);
1249 	ui_handle = purple_request_choice_varg(handle, title, primary, secondary,
1250 					     default_value, ok_text, ok_cb,
1251 					     cancel_text, cancel_cb,
1252 					     account, who, conv, user_data, args);
1253 	va_end(args);
1254 
1255 	return ui_handle;
1256 }
1257 
1258 void *
purple_request_choice_varg(void * handle,const char * title,const char * primary,const char * secondary,int default_value,const char * ok_text,GCallback ok_cb,const char * cancel_text,GCallback cancel_cb,PurpleAccount * account,const char * who,PurpleConversation * conv,void * user_data,va_list choices)1259 purple_request_choice_varg(void *handle, const char *title,
1260 			 const char *primary, const char *secondary,
1261 			 int default_value,
1262 			 const char *ok_text, GCallback ok_cb,
1263 			 const char *cancel_text, GCallback cancel_cb,
1264 			 PurpleAccount *account, const char *who, PurpleConversation *conv,
1265 			 void *user_data, va_list choices)
1266 {
1267 	PurpleRequestUiOps *ops;
1268 
1269 	g_return_val_if_fail(ok_text != NULL,  NULL);
1270 	g_return_val_if_fail(ok_cb   != NULL,  NULL);
1271 	g_return_val_if_fail(cancel_text != NULL,  NULL);
1272 
1273 	ops = purple_request_get_ui_ops();
1274 
1275 	if (ops != NULL && ops->request_choice != NULL) {
1276 		PurpleRequestInfo *info;
1277 
1278 		info            = g_new0(PurpleRequestInfo, 1);
1279 		info->type      = PURPLE_REQUEST_CHOICE;
1280 		info->handle    = handle;
1281 		info->ui_handle = ops->request_choice(title, primary, secondary,
1282 						      default_value,
1283 						      ok_text, ok_cb,
1284 						      cancel_text, cancel_cb,
1285 							  account, who, conv,
1286 						      user_data, choices);
1287 
1288 		handles = g_list_append(handles, info);
1289 
1290 		return info->ui_handle;
1291 	}
1292 
1293 	return NULL;
1294 }
1295 
1296 void *
purple_request_action(void * handle,const char * title,const char * primary,const char * secondary,int default_action,PurpleAccount * account,const char * who,PurpleConversation * conv,void * user_data,size_t action_count,...)1297 purple_request_action(void *handle, const char *title, const char *primary,
1298 					const char *secondary, int default_action,
1299 					PurpleAccount *account, const char *who, PurpleConversation *conv,
1300 					void *user_data, size_t action_count, ...)
1301 {
1302 	void *ui_handle;
1303 	va_list args;
1304 
1305 	g_return_val_if_fail(action_count > 0, NULL);
1306 
1307 	va_start(args, action_count);
1308 	ui_handle = purple_request_action_varg(handle, title, primary, secondary,
1309 										 default_action, account, who, conv,
1310 										 user_data, action_count, args);
1311 	va_end(args);
1312 
1313 	return ui_handle;
1314 }
1315 
1316 void *
purple_request_action_with_icon(void * handle,const char * title,const char * primary,const char * secondary,int default_action,PurpleAccount * account,const char * who,PurpleConversation * conv,gconstpointer icon_data,gsize icon_size,void * user_data,size_t action_count,...)1317 purple_request_action_with_icon(void *handle, const char *title,
1318 					const char *primary,
1319 					const char *secondary, int default_action,
1320 					PurpleAccount *account, const char *who,
1321 					PurpleConversation *conv, gconstpointer icon_data,
1322 					gsize icon_size, void *user_data, size_t action_count, ...)
1323 {
1324 	void *ui_handle;
1325 	va_list args;
1326 
1327 	g_return_val_if_fail(action_count > 0, NULL);
1328 
1329 	va_start(args, action_count);
1330 	ui_handle = purple_request_action_with_icon_varg(handle, title, primary,
1331 		secondary, default_action, account, who, conv, icon_data, icon_size,
1332 		user_data, action_count, args);
1333 	va_end(args);
1334 
1335 	return ui_handle;
1336 }
1337 
1338 
1339 void *
purple_request_action_varg(void * handle,const char * title,const char * primary,const char * secondary,int default_action,PurpleAccount * account,const char * who,PurpleConversation * conv,void * user_data,size_t action_count,va_list actions)1340 purple_request_action_varg(void *handle, const char *title,
1341 						 const char *primary, const char *secondary,
1342 						 int default_action,
1343 						 PurpleAccount *account, const char *who, PurpleConversation *conv,
1344 						  void *user_data, size_t action_count, va_list actions)
1345 {
1346 	PurpleRequestUiOps *ops;
1347 
1348 	g_return_val_if_fail(action_count > 0, NULL);
1349 
1350 	ops = purple_request_get_ui_ops();
1351 
1352 	if (ops != NULL && ops->request_action != NULL) {
1353 		PurpleRequestInfo *info;
1354 
1355 		info            = g_new0(PurpleRequestInfo, 1);
1356 		info->type      = PURPLE_REQUEST_ACTION;
1357 		info->handle    = handle;
1358 		info->ui_handle = ops->request_action(title, primary, secondary,
1359 											  default_action, account, who, conv,
1360 											  user_data, action_count, actions);
1361 
1362 		handles = g_list_append(handles, info);
1363 
1364 		return info->ui_handle;
1365 	}
1366 
1367 	return NULL;
1368 }
1369 
1370 void *
purple_request_action_with_icon_varg(void * handle,const char * title,const char * primary,const char * secondary,int default_action,PurpleAccount * account,const char * who,PurpleConversation * conv,gconstpointer icon_data,gsize icon_size,void * user_data,size_t action_count,va_list actions)1371 purple_request_action_with_icon_varg(void *handle, const char *title,
1372 						 const char *primary, const char *secondary,
1373 						 int default_action,
1374 						 PurpleAccount *account, const char *who,
1375 						 PurpleConversation *conv, gconstpointer icon_data,
1376 						 gsize icon_size,
1377 						 void *user_data, size_t action_count, va_list actions)
1378 {
1379 	PurpleRequestUiOps *ops;
1380 
1381 	g_return_val_if_fail(action_count > 0, NULL);
1382 
1383 	ops = purple_request_get_ui_ops();
1384 
1385 	if (ops != NULL && ops->request_action_with_icon != NULL) {
1386 		PurpleRequestInfo *info;
1387 
1388 		info            = g_new0(PurpleRequestInfo, 1);
1389 		info->type      = PURPLE_REQUEST_ACTION;
1390 		info->handle    = handle;
1391 		info->ui_handle = ops->request_action_with_icon(title, primary, secondary,
1392 											  default_action, account, who, conv,
1393 											  icon_data, icon_size,
1394 											  user_data, action_count, actions);
1395 
1396 		handles = g_list_append(handles, info);
1397 
1398 		return info->ui_handle;
1399 	} else {
1400 		/* Fall back on the non-icon request if the UI doesn't support icon
1401 		 requests */
1402 		return purple_request_action_varg(handle, title, primary, secondary,
1403 			default_action, account, who, conv, user_data, action_count, actions);
1404 	}
1405 
1406 	return NULL;
1407 }
1408 
1409 
1410 void *
purple_request_fields(void * handle,const char * title,const char * primary,const char * secondary,PurpleRequestFields * fields,const char * ok_text,GCallback ok_cb,const char * cancel_text,GCallback cancel_cb,PurpleAccount * account,const char * who,PurpleConversation * conv,void * user_data)1411 purple_request_fields(void *handle, const char *title, const char *primary,
1412 					const char *secondary, PurpleRequestFields *fields,
1413 					const char *ok_text, GCallback ok_cb,
1414 					const char *cancel_text, GCallback cancel_cb,
1415 					PurpleAccount *account, const char *who, PurpleConversation *conv,
1416 					void *user_data)
1417 {
1418 	PurpleRequestUiOps *ops;
1419 
1420 	g_return_val_if_fail(fields  != NULL, NULL);
1421 	g_return_val_if_fail(ok_text != NULL, NULL);
1422 	g_return_val_if_fail(ok_cb   != NULL, NULL);
1423 	g_return_val_if_fail(cancel_text != NULL, NULL);
1424 
1425 	ops = purple_request_get_ui_ops();
1426 
1427 	if (ops != NULL && ops->request_fields != NULL) {
1428 		PurpleRequestInfo *info;
1429 
1430 		info            = g_new0(PurpleRequestInfo, 1);
1431 		info->type      = PURPLE_REQUEST_FIELDS;
1432 		info->handle    = handle;
1433 		info->ui_handle = ops->request_fields(title, primary, secondary,
1434 											  fields, ok_text, ok_cb,
1435 											  cancel_text, cancel_cb,
1436 											  account, who, conv,
1437 											  user_data);
1438 
1439 		handles = g_list_append(handles, info);
1440 
1441 		return info->ui_handle;
1442 	}
1443 
1444 	return NULL;
1445 }
1446 
1447 void *
purple_request_file(void * handle,const char * title,const char * filename,gboolean savedialog,GCallback ok_cb,GCallback cancel_cb,PurpleAccount * account,const char * who,PurpleConversation * conv,void * user_data)1448 purple_request_file(void *handle, const char *title, const char *filename,
1449 				  gboolean savedialog,
1450 				  GCallback ok_cb, GCallback cancel_cb,
1451 				  PurpleAccount *account, const char *who, PurpleConversation *conv,
1452 				  void *user_data)
1453 {
1454 	PurpleRequestUiOps *ops;
1455 
1456 	ops = purple_request_get_ui_ops();
1457 
1458 	if (ops != NULL && ops->request_file != NULL) {
1459 		PurpleRequestInfo *info;
1460 
1461 		info            = g_new0(PurpleRequestInfo, 1);
1462 		info->type      = PURPLE_REQUEST_FILE;
1463 		info->handle    = handle;
1464 		info->ui_handle = ops->request_file(title, filename, savedialog,
1465 											ok_cb, cancel_cb,
1466 											account, who, conv, user_data);
1467 		handles = g_list_append(handles, info);
1468 		return info->ui_handle;
1469 	}
1470 
1471 	return NULL;
1472 }
1473 
1474 void *
purple_request_folder(void * handle,const char * title,const char * dirname,GCallback ok_cb,GCallback cancel_cb,PurpleAccount * account,const char * who,PurpleConversation * conv,void * user_data)1475 purple_request_folder(void *handle, const char *title, const char *dirname,
1476 				  GCallback ok_cb, GCallback cancel_cb,
1477 				  PurpleAccount *account, const char *who, PurpleConversation *conv,
1478 				  void *user_data)
1479 {
1480 	PurpleRequestUiOps *ops;
1481 
1482 	ops = purple_request_get_ui_ops();
1483 
1484 	if (ops != NULL && ops->request_file != NULL) {
1485 		PurpleRequestInfo *info;
1486 
1487 		info            = g_new0(PurpleRequestInfo, 1);
1488 		info->type      = PURPLE_REQUEST_FOLDER;
1489 		info->handle    = handle;
1490 		info->ui_handle = ops->request_folder(title, dirname,
1491 											ok_cb, cancel_cb,
1492 											account, who, conv,
1493 											user_data);
1494 		handles = g_list_append(handles, info);
1495 		return info->ui_handle;
1496 	}
1497 
1498 	return NULL;
1499 }
1500 
1501 void *
purple_request_screenshare_media(void * handle,const char * title,const char * primary,const char * secondary,PurpleAccount * account,GCallback cb,void * user_data)1502 purple_request_screenshare_media(void *handle, const char *title,
1503 				 const char *primary, const char *secondary,
1504 				 PurpleAccount *account, GCallback cb,
1505 				 void *user_data)
1506 {
1507 	PurpleRequestUiOps *ops;
1508 
1509 	ops = purple_request_get_ui_ops();
1510 
1511 	if (ops != NULL && ops->request_screenshare_media != NULL) {
1512 		PurpleRequestInfo *info;
1513 
1514 		info            = g_new0(PurpleRequestInfo, 1);
1515 		info->type      = PURPLE_REQUEST_SCREENSHARE;
1516 		info->handle    = handle;
1517 		info->ui_handle = ops->request_screenshare_media(title, primary, secondary,
1518 								 account, cb, user_data);
1519 		handles = g_list_append(handles, info);
1520 		return info->ui_handle;
1521 	}
1522 
1523 	return NULL;
1524 }
1525 
1526 static void
purple_request_close_info(PurpleRequestInfo * info)1527 purple_request_close_info(PurpleRequestInfo *info)
1528 {
1529 	PurpleRequestUiOps *ops;
1530 
1531 	ops = purple_request_get_ui_ops();
1532 
1533 	purple_notify_close_with_handle(info->ui_handle);
1534 	purple_request_close_with_handle(info->ui_handle);
1535 
1536 	if (ops != NULL && ops->close_request != NULL)
1537 		ops->close_request(info->type, info->ui_handle);
1538 
1539 	g_free(info);
1540 }
1541 
1542 void
purple_request_close(PurpleRequestType type,void * ui_handle)1543 purple_request_close(PurpleRequestType type, void *ui_handle)
1544 {
1545 	GList *l;
1546 
1547 	g_return_if_fail(ui_handle != NULL);
1548 
1549 	for (l = handles; l != NULL; l = l->next) {
1550 		PurpleRequestInfo *info = l->data;
1551 
1552 		if (info->ui_handle == ui_handle) {
1553 			handles = g_list_remove(handles, info);
1554 			purple_request_close_info(info);
1555 			break;
1556 		}
1557 	}
1558 }
1559 
1560 void
purple_request_close_with_handle(void * handle)1561 purple_request_close_with_handle(void *handle)
1562 {
1563 	GList *l, *l_next;
1564 
1565 	g_return_if_fail(handle != NULL);
1566 
1567 	for (l = handles; l != NULL; l = l_next) {
1568 		PurpleRequestInfo *info = l->data;
1569 
1570 		l_next = l->next;
1571 
1572 		if (info->handle == handle) {
1573 			handles = g_list_remove(handles, info);
1574 			purple_request_close_info(info);
1575 		}
1576 	}
1577 }
1578 
1579 void
purple_request_set_ui_ops(PurpleRequestUiOps * ops)1580 purple_request_set_ui_ops(PurpleRequestUiOps *ops)
1581 {
1582 	request_ui_ops = ops;
1583 }
1584 
1585 PurpleRequestUiOps *
purple_request_get_ui_ops(void)1586 purple_request_get_ui_ops(void)
1587 {
1588 	return request_ui_ops;
1589 }
1590