GCC Code Coverage Report


Directory: src/
File: user/msg-user-service.c
Date: 2025-03-15 02:02:43
Exec Total Coverage
Lines: 103 138 74.6%
Functions: 11 11 100.0%
Branches: 32 64 50.0%

Line Branch Exec Source
1 /* Copyright 2024 Jan-Michael Brummer
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU Lesser General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17 #include <libsoup/soup.h>
18 #include <json-glib/json-glib.h>
19
20 #include <stdio.h>
21
22 #include "msg-authorizer.h"
23 #include "msg-error.h"
24 #include "msg-private.h"
25 #include "msg-service.h"
26 #include "msg-user.h"
27 #include "msg-user-service.h"
28 #include "msg-user-contact-folder.h"
29
30 struct _MsgUserService {
31 MsgService parent_instance;
32 };
33
34
5/6
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 8 times.
14 G_DEFINE_TYPE (MsgUserService, msg_user_service, MSG_TYPE_SERVICE);
35
36 static void
37 1 msg_user_service_init (__attribute__ ((unused)) MsgUserService *self)
38 {
39 1 }
40
41 static void
42 2 msg_user_service_class_init (__attribute__ ((unused)) MsgUserServiceClass *class)
43 {
44 2 }
45
46 MsgUserService *
47 1 msg_user_service_new (MsgAuthorizer *authorizer)
48 {
49 1 return g_object_new (MSG_TYPE_USER_SERVICE, "authorizer", authorizer, NULL);
50 }
51
52 /**
53 * msg_user_service_get_user:
54 * @self: a #MsgUserService
55 * @name: user name (%NULL for me)
56 * @cancellable: a #GCancellable
57 * @error: a #GError
58 *
59 * Get user information
60 *
61 * Returns: (transfer full): request user
62 */
63 MsgUser *
64 3 msg_user_service_get_user (MsgUserService *self,
65 const char *name,
66 GCancellable *cancellable,
67 GError **error)
68 {
69 3 g_autoptr (SoupMessage) message = NULL;
70 3 JsonObject *root_object = NULL;
71 3 g_autofree char *url = NULL;
72 3 g_autoptr (GBytes) response = NULL;
73 3 g_autoptr (JsonParser) parser = NULL;
74
75
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (!msg_service_refresh_authorization (MSG_SERVICE (self), cancellable, error))
76 return NULL;
77
78
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 if (!name)
79 2 url = g_strconcat (MSG_API_ENDPOINT, "/me", NULL);
80 else
81 1 url = g_strconcat (MSG_BETA_API_ENDPOINT, "/me/contacts/users/", name, NULL);
82
83 3 message = msg_service_build_message (MSG_SERVICE (self), "GET", url, NULL, FALSE);
84 3 parser = msg_service_send_and_parse_response (MSG_SERVICE (self), message, &root_object, cancellable, error);
85
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
3 if (!parser)
86 1 return NULL;
87
88 2 return msg_user_new_from_json (root_object, error);
89 }
90
91 /**
92 * msg_user_service_get_photo:
93 * @self: a #MsgUserService
94 * @mail: mail address
95 * @cancellable: a #GCancellable
96 * @error: a #GError
97 *
98 * Try to load user photo using provided %mail address.
99 *
100 * Returns: (transfer full): user photo or %NULL if not found.
101 */
102 GBytes *
103 2 msg_user_service_get_photo (MsgUserService *self,
104 const char *mail,
105 GCancellable *cancellable,
106 GError **error)
107 {
108 2 g_autoptr (SoupMessage) message = NULL;
109 2 g_autofree char *url = NULL;
110 2 g_autoptr (GBytes) photo = NULL;
111
112
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!msg_service_refresh_authorization (MSG_SERVICE (self), cancellable, error))
113 return NULL;
114
115 2 url = g_strconcat (MSG_API_ENDPOINT, "/users/", mail, "/photo/$value", NULL);
116
117 2 message = msg_service_build_message (MSG_SERVICE (self), "GET", url, NULL, FALSE);
118 2 photo = msg_service_send_and_read (MSG_SERVICE (self), message, cancellable, error);
119
120
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (soup_message_get_status (message) == SOUP_STATUS_OK) {
121 1 return g_steal_pointer (&photo);
122 }
123
124 1 g_set_error (error,
125 msg_error_quark (),
126 MSG_ERROR_FAILED,
127 "Could not load photo");
128
129 1 return NULL;
130 }
131
132 /**
133 * msg_user_service_get_contact_folders:
134 * @self: a #MsgUserService
135 * @cancellable: a #GCancellable
136 * @error: a #GError
137 *
138 * Get all folders for given service
139 *
140 * Returns: (element-type MsgUserContactFolder) (transfer full): all user contact folders the user can access
141 */
142 GList *
143 1 msg_user_service_get_contact_folders (MsgUserService *self,
144 GCancellable *cancellable,
145 GError **error)
146 {
147 1 JsonObject *root_object = NULL;
148 1 g_autofree char *url = NULL;
149 1 g_autolist (MsgUserContactFolder) list = NULL;
150 1 JsonArray *array = NULL;
151 1 guint array_length = 0, index = 0;
152 1 g_autoptr (GBytes) response = NULL;
153 1 g_autoptr (JsonParser) parser = NULL;
154
155
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!msg_service_refresh_authorization (MSG_SERVICE (self), cancellable, error))
156 return NULL;
157
158 1 url = g_strconcat (MSG_API_ENDPOINT, "/me/contactFolders", NULL);
159
160 do {
161
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 g_autoptr (SoupMessage) message = NULL;
162
163 1 message = msg_service_build_message (MSG_SERVICE (self), "GET", url, NULL, FALSE);
164 1 parser = msg_service_send_and_parse_response (MSG_SERVICE (self), message, &root_object, cancellable, error);
165
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!parser)
166 return NULL;
167
168 1 array = json_object_get_array_member (root_object, "value");
169
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 g_assert (array != NULL);
170
171 1 array_length = json_array_get_length (array);
172
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 for (index = 0; index < array_length; index++) {
173 g_autoptr (GError) local_error = NULL;
174 MsgUserContactFolder *folder = NULL;
175 JsonObject *object = NULL;
176
177 object = json_array_get_object_element (array, index);
178
179 folder = msg_user_contact_folder_new_from_json (object, &local_error);
180 if (folder) {
181 list = g_list_append (list, folder);
182 } else {
183 g_warning ("Could not parse contact folder object: %s", local_error->message);
184 g_clear_error (&local_error);
185 }
186 }
187
188
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 g_clear_pointer (&url, g_free);
189 1 url = msg_service_get_next_link (root_object);
190
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 } while (url != NULL);
191
192 1 return g_steal_pointer (&list);
193 }
194
195 /**
196 * msg_user_service_get_contacts:
197 * @self: a #MsgUserService
198 * @cancellable: a #GCancellable
199 * @error: a #GError
200 *
201 * Get all contats within users 'Contact' folder.
202 *
203 * Returns: (element-type MsgUserContactFolder) (transfer full): all contact in users contact folder
204 */
205 GList *
206 1 msg_user_service_get_contacts (MsgUserService *self,
207 GCancellable *cancellable,
208 GError **error)
209 {
210 1 g_autoptr (SoupMessage) soup_message = NULL;
211 1 g_autofree char *url = NULL;
212 1 JsonObject *root_object = NULL;
213 1 g_autolist (MsgUser) list = NULL;
214 1 JsonArray *array = NULL;
215 1 guint array_length = 0, index = 0;
216 1 g_autoptr (GBytes) response = NULL;
217 1 g_autoptr (JsonParser) parser = NULL;
218
219
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!msg_service_refresh_authorization (MSG_SERVICE (self), cancellable, error))
220 return NULL;
221
222 1 url = g_strconcat (MSG_API_ENDPOINT, "/me/contacts/", NULL);
223
224 do {
225
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 g_autoptr (SoupMessage) message = NULL;
226
227 1 message = msg_service_build_message (MSG_SERVICE (self), "GET", url, NULL, FALSE);
228 1 parser = msg_service_send_and_parse_response (MSG_SERVICE (self), message, &root_object, cancellable, error);
229
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!parser)
230 return NULL;
231
232 1 array = json_object_get_array_member (root_object, "value");
233
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 g_assert (array != NULL);
234
235 1 array_length = json_array_get_length (array);
236
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 for (index = 0; index < array_length; index++) {
237 1 g_autoptr (GError) local_error = NULL;
238 1 MsgUser *user = NULL;
239 1 JsonObject *object = NULL;
240
241 1 object = json_array_get_object_element (array, index);
242
243 1 user = msg_user_new_from_json (object, &local_error);
244
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (user) {
245 1 list = g_list_append (list, user);
246 } else {
247 g_warning ("Could not parse contact user object: %s", local_error->message);
248 g_clear_error (&local_error);
249 }
250 }
251
252
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 g_clear_pointer (&url, g_free);
253 1 url = msg_service_get_next_link (root_object);
254
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 } while (url != NULL);
255
256 1 return g_steal_pointer (&list);
257 }
258
259 /**
260 * msg_user_service_find_users:
261 * @self: a #MsgUserService
262 * @name: name to search
263 * @cancellable: a #GCancellable
264 * @error: a #GError
265 *
266 * Find all users with the given @name. (Business accounts only!)
267 *
268 * Returns: (element-type MsgUser) (transfer full): a list of contacts with the given name.
269 */
270 GList *
271 1 msg_user_service_find_users (MsgUserService *self,
272 const char *display_name,
273 GCancellable *cancellable,
274 GError **error)
275 {
276 1 g_autoptr (SoupMessage) soup_message = NULL;
277 1 g_autofree char *url = NULL;
278 1 JsonObject *root_object = NULL;
279 1 g_autolist (MsgUser) list = NULL;
280 1 JsonArray *array = NULL;
281 1 guint array_length = 0, index = 0;
282 1 g_autoptr (GBytes) response = NULL;
283 1 g_autoptr (JsonParser) parser = NULL;
284
285
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!msg_service_refresh_authorization (MSG_SERVICE (self), cancellable, error))
286 return NULL;
287
288 1 url = g_strconcat (MSG_API_ENDPOINT, "/users?$search=\"displayName:", display_name, "\"", NULL);
289
290 do {
291
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 g_autoptr (SoupMessage) message = NULL;
292
293 1 message = msg_service_build_message (MSG_SERVICE (self), "GET", url, NULL, FALSE);
294 1 soup_message_headers_append (soup_message_get_request_headers (message), "ConsistencyLevel", "eventual");
295 1 parser = msg_service_send_and_parse_response (MSG_SERVICE (self), message, &root_object, cancellable, error);
296
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (!parser)
297 1 return NULL;
298
299 array = json_object_get_array_member (root_object, "value");
300 g_assert (array != NULL);
301
302 array_length = json_array_get_length (array);
303 for (index = 0; index < array_length; index++) {
304 g_autoptr (GError) local_error = NULL;
305 MsgUser *user = NULL;
306 JsonObject *object = NULL;
307
308 object = json_array_get_object_element (array, index);
309
310 user = msg_user_new_from_json (object, &local_error);
311 if (user) {
312 list = g_list_append (list, user);
313 } else {
314 g_warning ("Could not parse contact user object: %s", local_error->message);
315 g_clear_error (&local_error);
316 }
317 }
318
319 g_clear_pointer (&url, g_free);
320 url = msg_service_get_next_link (root_object);
321 } while (url != NULL);
322
323 return g_steal_pointer (&list);
324 }
325