| |
1 /* |
| |
2 * Purple Satori Plugin - Satori Protocol Plugin for Purple3 |
| |
3 * Copyright (C) 2025 Gong Zhile |
| |
4 * |
| |
5 * This library is free software; you can redistribute it and/or |
| |
6 * modify it under the terms of the GNU Lesser General Public |
| |
7 * License as published by the Free Software Foundation; either |
| |
8 * version 2 of the License, or (at your option) any later version. |
| |
9 * |
| |
10 * This library is distributed in the hope that it will be useful, |
| |
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| |
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| |
13 * Lesser General Public License for more details. |
| |
14 * |
| |
15 * You should have received a copy of the GNU Lesser General Public |
| |
16 * License along with this library; if not, see <https://www.gnu.org/licenses/>. |
| |
17 */ |
| |
18 |
| |
19 #include <glib.h> |
| |
20 #include <gio/gio.h> |
| |
21 #include <glib-object.h> |
| |
22 #include <json-glib/json-glib.h> |
| |
23 #include <libsoup/soup-message.h> |
| |
24 #include <libsoup/soup-session.h> |
| |
25 |
| |
26 |
| |
27 #include "purplesatoriconnection.h" |
| |
28 #include "satorimessage.h" |
| |
29 #include "satoriapi.h" |
| |
30 |
| |
31 static void |
| |
32 satori_on_buddy_contacts_resp(SoupSession *session, |
| |
33 GAsyncResult *res, |
| |
34 PurpleSatoriConnection *con) |
| |
35 { |
| |
36 GError *error = NULL; |
| |
37 GBytes *resp = soup_session_send_and_read_finish(session, res, &error); |
| |
38 |
| |
39 if (error) { |
| |
40 purple_debug_error("satori", |
| |
41 "refresh_buddy_contacts failed: %s", |
| |
42 error->message); |
| |
43 if (resp) |
| |
44 g_bytes_unref(resp); |
| |
45 g_error_free(error); |
| |
46 return; |
| |
47 } |
| |
48 |
| |
49 gsize sz; |
| |
50 const gchar *ptr = g_bytes_get_data(resp, &sz), *next = NULL; |
| |
51 |
| |
52 JsonParser *parser = json_parser_new(); |
| |
53 if (!json_parser_load_from_data(parser, ptr, sz, NULL)) { |
| |
54 purple_debug_warning("satori", "bad json received from ws"); |
| |
55 goto finish; |
| |
56 } |
| |
57 |
| |
58 JsonObject *root = json_node_get_object(json_parser_get_root(parser)); |
| |
59 JsonArray *data = json_object_get_array_member(root, "data"); |
| |
60 next = json_object_get_string_member_with_default( |
| |
61 root, "next", NULL); |
| |
62 |
| |
63 if (!data) goto finish; |
| |
64 |
| |
65 PurpleAccount *acc = \ |
| |
66 purple_connection_get_account(PURPLE_CONNECTION(con)); |
| |
67 PurpleContactManager *manager = \ |
| |
68 purple_contact_manager_get_default(); |
| |
69 |
| |
70 for (guint i = 0; i < json_array_get_length(data); i++) { |
| |
71 JsonObject *user_obj = json_array_get_object_element(data, i); |
| |
72 |
| |
73 SatoriUser user = { 0 }; |
| |
74 satori_user_from_json(user_obj, &user); |
| |
75 |
| |
76 PurpleContact *contact = NULL; |
| |
77 PurpleContactInfo *info = NULL; |
| |
78 PurplePresence *presence = NULL; |
| |
79 PurplePerson *person = NULL; |
| |
80 |
| |
81 gboolean new_contact = FALSE, new_person = FALSE; |
| |
82 |
| |
83 contact = purple_contact_manager_find_with_id(manager, acc, user.id); |
| |
84 if (!PURPLE_IS_CONTACT(contact)) { |
| |
85 contact = purple_contact_new(acc, user.id); |
| |
86 new_contact = TRUE; |
| |
87 } |
| |
88 |
| |
89 /* Initialize PurpleContactInfo */ |
| |
90 info = PURPLE_CONTACT_INFO(contact); |
| |
91 purple_contact_info_set_username(info, user.id); |
| |
92 purple_contact_info_set_display_name(info, user.nick ? |
| |
93 user.nick : user.name); |
| |
94 |
| |
95 /* Initialize PurplePerson */ |
| |
96 person = purple_contact_info_get_person(info); |
| |
97 if (!PURPLE_IS_PERSON(person)) { |
| |
98 person = g_object_new(PURPLE_TYPE_PERSON, |
| |
99 "id", user.id, NULL); |
| |
100 new_person = TRUE; |
| |
101 } |
| |
102 |
| |
103 if (new_person) { |
| |
104 purple_person_add_contact_info(person, info); |
| |
105 purple_contact_info_set_person(info, person); |
| |
106 g_clear_object(&person); |
| |
107 } |
| |
108 |
| |
109 /* Initialize PurplePresence */ |
| |
110 presence = purple_contact_info_get_presence(info); |
| |
111 purple_presence_set_primitive(presence, |
| |
112 PURPLE_PRESENCE_PRIMITIVE_AVAILABLE); |
| |
113 |
| |
114 if (new_contact) { |
| |
115 purple_contact_manager_add(manager, contact); |
| |
116 g_clear_object(&contact); |
| |
117 } |
| |
118 } |
| |
119 |
| |
120 finish: |
| |
121 if (next) |
| |
122 satori_refresh_buddy_contacts(con, next); |
| |
123 |
| |
124 g_bytes_unref(resp); |
| |
125 g_object_unref(parser); |
| |
126 } |
| |
127 |
| |
128 void |
| |
129 satori_refresh_buddy_contacts(PurpleSatoriConnection *con, const gchar *next) |
| |
130 { |
| |
131 GBytes *data = NULL; |
| |
132 |
| |
133 { |
| |
134 JB_BEGIN_OBJ(b); |
| |
135 if (next) |
| |
136 JBA(b, "next", next); |
| |
137 JB_END_OBJ(data, b); |
| |
138 } |
| |
139 |
| |
140 SoupMessage *msg = satori_message_new( |
| |
141 "POST", SATORI_ENDPOINT("/v1/friend.list")); |
| |
142 soup_message_set_request_body_from_bytes(msg, "application/json", data); |
| |
143 |
| |
144 purple_satori_connection_send_and_read_async( |
| |
145 con, msg, 0, NULL, |
| |
146 (GAsyncReadyCallback) satori_on_buddy_contacts_resp, |
| |
147 PURPLE_SATORI_CONNECTION(con)); |
| |
148 |
| |
149 g_object_unref(msg); |
| |
150 g_bytes_unref(data); |
| |
151 } |