1 /*
2 * Copyright (c) 2013, 2014 Anton Dobkin
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 * THE SOFTWARE.
21 */
22
23 #include "jansson.h"
24
25 #include <stdio.h>
26 #include <string.h>
27 #include <stdlib.h>
28 #include <errno.h>
29
30 #include <fcntl.h>
31
32 #include "apn.h"
33
34 #ifdef HAVE_UNISTD_H
35 #include <unistd.h>
36 #endif
37
38 #ifdef HAVE_NETINET_IN_H
39 #include <netinet/in.h>
40 #endif
41
42 #ifdef HAVE_ARPA_INET_H
43 #include <arpa/inet.h>
44 #endif
45
46 #ifdef HAVE_NETDB_H
47 #include <netdb.h>
48 #endif
49
50 #ifdef HAVE_CTYPE_H
51 #include <ctype.h>
52 #endif
53
54 #ifdef HAVE_SYS_SOCKET_H
55 #include <sys/socket.h>
56 #endif
57
58 #include <openssl/err.h>
59
60 #define DIAGNOSTIC_MAKE_STRING(x) #x
61 #define DIAGNOSTIC_JOIN_STRING(x, y) DIAGNOSTIC_MAKE_STRING(x ## y)
62 #define DIAGNOSTIC_DO_PRAGMA(p) _Pragma (#p)
63
64 #if defined(__clang__)
65 #define DIAGNOSTIC_PRAGMA(x) DIAGNOSTIC_DO_PRAGMA(clang diagnostic x)
66 #define DIAGNOSTIC_OFF(x) \
67 DIAGNOSTIC_PRAGMA(push) \
68 DIAGNOSTIC_PRAGMA(ignored DIAGNOSTIC_JOIN_STRING(-W, x))
69 #define DIAGNOSTIC_ON(x) \
70 DIAGNOSTIC_PRAGMA(pop)
71 #elif defined(__GNUC__)
72 #define GNUC_NUM_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)
73 #define DIAGNOSTIC_PRAGMA(x) DIAGNOSTIC_DO_PRAGMA(GCC diagnostic x)
74 #if GNUC_NUM_VERSION >= 402
75 #if GNUC_NUM_VERSION >= 406
76 #define DIAGNOSTIC_OFF(x) \
77 DIAGNOSTIC_PRAGMA(push) \
78 DIAGNOSTIC_PRAGMA(ignored DIAGNOSTIC_JOIN_STRING(-W, x))
79 #define DIAGNOSTIC_ON(x) \
80 DIAGNOSTIC_PRAGMA(pop)
81 #else
82 #define DIAGNOSTIC_OFF(x) \
83 DIAGNOSTIC_PRAGMA(ignored DIAGNOSTIC_JOIN_STRING(-W, x))
84 #define DIAGNOSTIC_ON(x) \
85 DIAGNOSTIC_PRAGMA(warning DIAGNOSTIC_JOIN_STRING(-W, x))
86 #endif
87 #endif
88 #endif
89
90 #if !defined(DIAGNOSTIC_OFF) && !defined(DIAGNOSTIC_ON)
91 #define DIAGNOSTIC_OFF(x)
92 #define DIAGNOSTIC_ON(x)
93 #endif
94
95 #include "apn_strings.h"
96 #include "version.h"
97
98 #define APN_TOKEN_BINARY_SIZE 32
99 #define APN_PAYLOAD_MAX_SIZE 256
100 #define APN_RETURN_SUCCESS return APN_SUCCESS
101 #define APN_RETURN_ERROR return APN_ERROR
102
103 #define APN_SET_ERROR(__err, __err_code, __err_msg) \
104 __apn_error_set(__err, __err_code, __err_msg);
105
106 static uint8_t __ssl_lib_initialized = 0;
107
108 enum __apn_apns_errors {
109 APN_APNS_ERR_NO_ERRORS = 0,
110 APN_APNS_ERR_PROCESSING_ERROR = 1,
111 APN_APNS_ERR_MISSING_DEVICE_TOKEN,
112 APN_APNS_ERR_MISSING_TOPIC,
113 APN_APNS_ERR_MISSING_PAYLOAD,
114 APN_APNS_ERR_INVALID_TOKEN_SIZE,
115 APN_APNS_ERR_INVALID_TOPIC_SIZE,
116 APN_APNS_ERR_INVALID_PAYLOAD_SIZE,
117 APN_APNS_ERR_INVALID_TOKEN,
118 APN_APNS_ERR_SERVICE_SHUTDOWN = 10,
119 APN_APNS_ERR_NONE = 255
120 };
121
122 static char *__apn_errors[APN_ERR_COUNT] = {
123 "out of memory", // APN_ERR_NOMEM
124 "connection context is not initialized. Expected poninter to initialize apn_ctx structure, passed NULL", // APN_ERR_CTX_NOT_INITIALIZED
125 "no opened connection to Apple Push Notification Service",
126 "no opened connection to Apple Feedback Service",
127 "connection was closed", // APN_ERR_CONNECTION_CLOSED
128 "invalid argument", // APN_ERR_INVALID_ARGUMENT
129 "certificate is not set", // APN_ERR_CERTIFICATE_IS_NOT_SET
130 "private key is not set", // APN_ERR_PRIVATE_KEY_IS_NOT_SET
131 "notification payload is not set", // APN_ERR_PAYLOAD_IS_NOT_SET
132 "no device tokens given", // APN_ERR_TOKEN_IS_NOT_SET
133 "invalid device token", // APN_ERR_TOKEN_INVALID
134 "too many device tokens",
135 "unable to use specified SSL certificate", // APN_ERR_UNABLE_TO_USE_SPECIFIED_CERTIFICATE
136 "unable to use specified private key", // APN_ERR_UNABLE_TO_USE_SPECIFIED_PRIVATE_KEY
137 "could not reslove host", // APN_ERR_COULD_NOT_RESOLVE_HOST
138 "could not create socket", // APN_ERR_COULD_NOT_CREATE_SOCKET
139 "system call select() returned error", // APN_ERR_SELECT_ERROR
140 "could not initialize connection", // APN_ERR_COULD_NOT_INITIALIZE_CONNECTION
141 "could not initialize ssl connection", // APN_ERR_COULD_NOT_INITIALIZE_SSL_CONNECTION
142 "SSL_write failed", // APN_ERR_SSL_WRITE_FAILED
143 "SSL_read failed", // APN_ERR_SSL_READ_FAILED
144 "invalid notification payload size", // APN_ERR_INVALID_PAYLOAD_SIZE
145 "payload notification contex is not initialized, Expected poninter to initialize apn_payload_ctx, passed NULL", // APN_ERR_PAYLOAD_CTX_NOT_INITIALIZED
146 "incorrect number to display as the badge on application icon", // APN_ERR_PAYLOAD_BADGE_INVALID_VALUE
147 "too many custom properties, no more than 5", //APN_ERR_PAYLOAD_TOO_MANY_CUSTOM_PROPERTIES
148 "specified custom property key is already used", // APN_ERR_PAYLOAD_CUSTOM_PROPERTY_KEY_IS_ALREADY_USED
149 "could not create json document", // APN_ERR_PAYLOAD_COULD_NOT_CREATE_JSON_DOCUMENT
150 "alert message text and key used to get a localized alert-message string are not set", // APN_ERR_PAYLOAD_ALERT_IS_NOT_SET
151 "non-UTF8 symbols detected in a string",
152 "processing error", // APN_ERR_PROCESSING_ERROR
153 "server closed the connection", // APN_ERR_SERVICE_SHUTDOWN
154 "unknown error" // APN_ERR_UNKNOWN
155 };
156
157 struct __apn_appl_server {
158 char *host;
159 int port;
160 };
161
162 static struct __apn_appl_server __apn_appl_servers[4] = {
163 {"gateway.sandbox.push.apple.com", 2195},
164 {"gateway.push.apple.com", 2195},
165 {"feedback.sandbox.push.apple.com", 2196},
166 {"feedback.push.apple.com", 2196}
167 };
168
169 static void * __apn_realloc(void *, size_t);
170 static uint8_t * __token_hex_to_binary(const char *);
171 static char * __token_binary_to_hex(const uint8_t *);
172 static uint8_t __apn_payload_alert_init(apn_payload_alert_ref *, apn_error_ref *);
173 static void __apn_payload_custom_property_free(apn_payload_custom_property_ref *);
174 static uint8_t __apn_payload_custom_key_is_already_used(apn_payload_ctx_ref, const char *);
175 static uint8_t __apn_payload_custom_property_init(apn_payload_ctx_ref, const char *, apn_error_ref *);
176 static char * __apn_create_json_document_from_payload(apn_payload_ctx_ref, apn_error_ref *);
177 static uint8_t __apn_connect(const apn_ctx_ref, struct __apn_appl_server, apn_error_ref *);
178 static int __ssl_read(const apn_ctx_ref, char *, size_t, apn_error_ref *);
179 static size_t __ssl_write(const apn_ctx_ref, const uint8_t *, size_t, apn_error_ref *);
180 static void __apn_tokens_array_free(uint8_t **, uint32_t);
181 static uint8_t** __apn_tokens_array_copy(uint8_t **, uint32_t, apn_error_ref *);
182 static void __apn_error_set(apn_error_ref *, uint32_t, const char *);
183 static uint8_t __apn_is_error(const apn_error_ref);
184 static uint8_t __apn_check_hex_token(const char *);
185 static size_t __apn_create_binary_message(uint8_t *, const char * const, uint32_t, uint32_t, apn_notification_priority, uint8_t **, apn_error_ref *);
186
__apn_realloc(void * ptr,size_t size)187 static void *__apn_realloc(void *ptr, size_t size) {
188 void *new_ptr = NULL;
189 if (ptr != NULL) {
190 if (size == 0) {
191 free(ptr);
192 return NULL;
193 } else {
194 new_ptr = realloc(ptr, size);
195 if (new_ptr == NULL) {
196 free(ptr);
197 }
198 return new_ptr;
199 }
200 }
201 return malloc(size);
202 }
203
__apn_tokens_array_free(uint8_t ** tokens,uint32_t count)204 static void __apn_tokens_array_free(uint8_t **tokens, uint32_t count) {
205 uint8_t *token = NULL;
206 int64_t i = 0;
207 if (tokens && count > 0) {
208 for (i = 0; i < count; i++) {
209 token = tokens[i];
210 free(token);
211 }
212 free(tokens);
213 }
214 }
215
__apn_tokens_array_copy(uint8_t ** tokens,uint32_t count,apn_error_ref * error)216 static uint8_t ** __apn_tokens_array_copy(uint8_t **tokens, uint32_t count, apn_error_ref *error) {
217 uint8_t **new_tokens = NULL;
218 int64_t i = 0;
219 if (count > 0 && tokens) {
220 new_tokens = (uint8_t **) malloc(count);
221 if (!new_tokens) {
222 APN_SET_ERROR(error, APN_ERR_NOMEM | APN_ERR_CLASS_INTERNAL, __apn_errors[APN_ERR_NOMEM]);
223 return NULL;
224 }
225 for (i = 0; i < count; i++) {
226 new_tokens[i] = (uint8_t *)malloc(APN_TOKEN_BINARY_SIZE);
227 if (!new_tokens[i]) {
228 APN_SET_ERROR(error, APN_ERR_NOMEM | APN_ERR_CLASS_INTERNAL, __apn_errors[APN_ERR_NOMEM]);
229 return NULL;
230 }
231 memcpy(new_tokens[i], tokens[i], APN_TOKEN_BINARY_SIZE);
232 }
233 }
234 return new_tokens;
235 }
236
__token_hex_to_binary(const char * token)237 static uint8_t * __token_hex_to_binary(const char *token) {
238 uint16_t i = 0;
239 uint16_t j = 0;
240 uint8_t *binary_token = NULL;
241 int binary = 0;
242
243 binary_token = malloc(APN_TOKEN_BINARY_SIZE);
244 if (!binary_token) {
245 return NULL;
246 }
247 memset(binary_token, 0, APN_TOKEN_BINARY_SIZE);
248
249 for (i = 0, j = 0; i < APN_TOKEN_BINARY_SIZE * 2; i += 2, j++) {
250 char tmp[3] = {token[i], token[i + 1], '\0'};
251 #ifdef _WIN32
252 sscanf_s(tmp, "%x", &binary);
253 #else
254 sscanf(tmp, "%x", &binary);
255 #endif
256 binary_token[j] = binary;
257 }
258 return binary_token;
259 }
260
__token_binary_to_hex(const uint8_t * binary_token)261 static char * __token_binary_to_hex(const uint8_t *binary_token) {
262 uint16_t i = 0;
263 size_t token_size = (APN_TOKEN_BINARY_SIZE * 2) + 1;
264 char *token = malloc(token_size);
265 char *p = token;
266
267 if (!token) {
268 return NULL;
269 }
270
271 for (i = 0; i < APN_TOKEN_BINARY_SIZE; i++) {
272 #ifdef _WIN32
273 _snprintf_s(p, token_size, 3, "%2.2hhX", (unsigned char) binary_token[i]);
274 #else
275 snprintf(p, 3, "%2.2hhX", (unsigned char) binary_token[i]);
276 #endif
277 p += 2;
278 }
279 return token;
280 }
281
__apn_check_hex_token(const char * token)282 static uint8_t __apn_check_hex_token(const char *token) {
283 char *p = (char *) token;
284
285 while (*p != '\0') {
286 if (!isxdigit(*p)) {
287 return 0;
288 }
289 p++;
290 }
291 return 1;
292 }
293
__apn_error_set(apn_error_ref * error,uint32_t code,const char * message)294 static void __apn_error_set(apn_error_ref *error, uint32_t code, const char *message) {
295 apn_error_ref _error = NULL;
296
297 if (error) {
298 _error = malloc(sizeof (apn_error));
299 if (!_error) {
300 return;
301 }
302 _error->code = code;
303 _error->message = apn_strndup(message, strlen(message));
304 _error->invalid_token = NULL;
305 *error = _error;
306 }
307 }
308
__apn_is_error(const apn_error_ref error)309 static uint8_t __apn_is_error(const apn_error_ref error) {
310 if (error != NULL && error->code > 0) {
311 return 1;
312 }
313 return 0;
314 }
315
__apn_payload_alert_init(apn_payload_alert_ref * alert,apn_error_ref * error)316 static uint8_t __apn_payload_alert_init(apn_payload_alert_ref *alert, apn_error_ref *error) {
317 apn_payload_alert_ref _alert = NULL;
318
319 *alert = NULL;
320
321 _alert = malloc(sizeof (apn_payload_alert));
322 if (!_alert) {
323 APN_SET_ERROR(error, APN_ERR_NOMEM | APN_ERR_CLASS_INTERNAL, __apn_errors[APN_ERR_NOMEM]);
324 APN_RETURN_ERROR;
325 }
326
327 _alert->action_loc_key = NULL;
328 _alert->body = NULL;
329 _alert->launch_image = NULL;
330 _alert->loc_args = NULL;
331 _alert->loc_key = NULL;
332 _alert->__loc_args_count = 0;
333
334 *alert = _alert;
335
336 APN_RETURN_SUCCESS;
337 }
338
__apn_payload_custom_property_free(apn_payload_custom_property_ref * property)339 static void __apn_payload_custom_property_free(apn_payload_custom_property_ref *property) {
340 apn_payload_custom_property_ref _property = NULL;
341 uint8_t array_size = 0;
342 uint8_t i = 0;
343
344 if (property && *property) {
345 _property = *property;
346 free(_property->key);
347
348 switch (_property->value_type) {
349 case APN_CUSTOM_PROPERTY_TYPE_STRING:
350 {
351 if (_property->value.string_value.value) {
352 free(_property->value.string_value.value);
353 }
354 }
355 break;
356 case APN_CUSTOM_PROPERTY_TYPE_ARRAY:
357 {
358 array_size = _property->value.array_value.array_size;
359 if (_property->value.array_value.array && array_size > 0) {
360 for (i = 0; i < array_size; i++) {
361 free(*(_property->value.array_value.array + i));
362 }
363 free(_property->value.array_value.array);
364 }
365 }
366 break;
367 default:
368 break;
369
370 }
371 free(_property);
372 }
373 }
374
__apn_payload_custom_key_is_already_used(apn_payload_ctx_ref payload_ctx,const char * property_key)375 static uint8_t __apn_payload_custom_key_is_already_used(apn_payload_ctx_ref payload_ctx, const char *property_key) {
376 apn_payload_custom_property_ref property = NULL;
377 uint8_t i = 0;
378
379 if (payload_ctx->__custom_properties_count == 0 || payload_ctx->custom_properties == NULL) {
380 return 0;
381 }
382 for (i = 0; i < payload_ctx->__custom_properties_count; i++) {
383 property = *(payload_ctx->custom_properties + 0);
384 if (strcmp(property->key, property_key) == 0) {
385 return 1;
386 }
387 }
388
389 return 0;
390 }
391
__apn_payload_custom_property_init(apn_payload_ctx_ref payload_ctx,const char * property_key,apn_error_ref * error)392 static uint8_t __apn_payload_custom_property_init(apn_payload_ctx_ref payload_ctx, const char *property_key,
393 apn_error_ref *error) {
394
395 apn_payload_custom_property_ref *properties = NULL;
396 char *key = NULL;
397
398 if (!payload_ctx) {
399 APN_SET_ERROR(error, APN_ERR_PAYLOAD_CTX_NOT_INITIALIZED | APN_ERR_CLASS_USER, __apn_errors[APN_ERR_PAYLOAD_CTX_NOT_INITIALIZED]);
400 APN_RETURN_ERROR;
401 }
402
403 if (payload_ctx->__custom_properties_count >= 5) {
404 APN_SET_ERROR(error, APN_ERR_PAYLOAD_TOO_MANY_CUSTOM_PROPERTIES | APN_ERR_CLASS_USER, __apn_errors[APN_ERR_PAYLOAD_TOO_MANY_CUSTOM_PROPERTIES]);
405 APN_RETURN_ERROR;
406 }
407
408 if (!property_key || strlen(property_key) == 0) {
409 APN_SET_ERROR(error, APN_ERR_INVALID_ARGUMENT | APN_ERR_CLASS_USER, "key of custom property is NULL");
410 APN_RETURN_ERROR;
411 }
412
413 if (!apn_string_is_utf8(property_key)) {
414 APN_SET_ERROR(error, APN_ERR_INVALID_ARGUMENT | APN_ERR_CLASS_USER, "key of custom property contains non-utf8 symbols");
415 APN_RETURN_ERROR;
416 }
417
418 if ((key = apn_strndup(property_key, strlen(property_key))) == NULL) {
419 APN_SET_ERROR(error, APN_ERR_NOMEM | APN_ERR_CLASS_INTERNAL, __apn_errors[APN_ERR_NOMEM]);
420 APN_RETURN_ERROR;
421 }
422
423 if (__apn_payload_custom_key_is_already_used(payload_ctx, key)) {
424 APN_SET_ERROR(error, APN_ERR_PAYLOAD_CUSTOM_PROPERTY_KEY_IS_ALREADY_USED | APN_ERR_CLASS_USER, __apn_errors[APN_ERR_PAYLOAD_CUSTOM_PROPERTY_KEY_IS_ALREADY_USED]);
425 free(key);
426 APN_RETURN_ERROR;
427 }
428 free(key);
429
430 if (payload_ctx->__custom_properties_count == 0) {
431 payload_ctx->custom_properties = (apn_payload_custom_property_ref *) malloc(sizeof (apn_payload_custom_property_ref *));
432 if (!payload_ctx->custom_properties) {
433 APN_SET_ERROR(error, APN_ERR_NOMEM | APN_ERR_CLASS_INTERNAL, __apn_errors[APN_ERR_NOMEM]);
434 APN_RETURN_ERROR;
435 }
436 } else {
437 properties = (apn_payload_custom_property_ref *) __apn_realloc(payload_ctx->custom_properties, (payload_ctx->__custom_properties_count + 1) * sizeof (apn_payload_custom_property_ref));
438 if (!properties) {
439 APN_SET_ERROR(error, APN_ERR_NOMEM | APN_ERR_CLASS_INTERNAL, __apn_errors[APN_ERR_NOMEM]);
440 APN_RETURN_ERROR;
441 }
442 payload_ctx->custom_properties = properties;
443 }
444
445 APN_RETURN_SUCCESS;
446 }
447
__apn_create_binary_message(uint8_t * token,const char * const payload,uint32_t id,uint32_t expiry,apn_notification_priority priority,uint8_t ** message,apn_error_ref * error)448 static size_t __apn_create_binary_message(uint8_t *token, const char * const payload, uint32_t id, uint32_t expiry, apn_notification_priority priority, uint8_t ** message, apn_error_ref *error) {
449 uint8_t * frame = NULL;
450 uint8_t * frame_ref = NULL;
451 size_t frame_size = 0;
452 size_t payload_size = 0;
453
454 uint32_t id_n = htonl(id); // ID (network ordered)
455 uint32_t expiry_n = htonl(expiry); // expiry time (network ordered)
456
457 uint8_t item_id = 1; // Item ID
458 uint16_t item_data_size_n = 0; // Item data size (network ordered)
459
460 size_t binary_message_size = 0;
461 uint8_t *binary_message = NULL;
462 uint8_t *binary_message_ref = NULL;
463 uint32_t frame_size_n; // Frame size (network ordered)
464
465 payload_size = strlen(payload);
466 frame_size = ((sizeof (uint8_t) + sizeof (uint16_t)) * 5)
467 + APN_TOKEN_BINARY_SIZE
468 + payload_size
469 + sizeof (uint32_t)
470 + sizeof (uint32_t)
471 + sizeof (uint8_t);
472
473 frame_size_n = htonl(frame_size);
474
475 frame = (uint8_t *) malloc(frame_size);
476 if (!frame) {
477 APN_SET_ERROR(error, APN_ERR_NOMEM | APN_ERR_CLASS_INTERNAL, __apn_errors[APN_ERR_NOMEM]);
478 *message = NULL;
479 return 0;
480 }
481 frame_ref = frame;
482
483 binary_message_size = frame_size + sizeof (uint32_t) + sizeof (uint8_t);
484 binary_message = (uint8_t *) malloc(binary_message_size);
485 if (!binary_message) {
486 APN_SET_ERROR(error, APN_ERR_NOMEM | APN_ERR_CLASS_INTERNAL, __apn_errors[APN_ERR_NOMEM]);
487 *message = NULL;
488 free(frame);
489 return 0;
490 }
491 binary_message_ref = binary_message;
492
493 /* Token */
494 *frame_ref++ = item_id++;
495 item_data_size_n = htons(APN_TOKEN_BINARY_SIZE);
496 memcpy(frame_ref, &item_data_size_n, sizeof (uint16_t));
497 frame_ref += sizeof (uint16_t);
498 memcpy(frame_ref, token, APN_TOKEN_BINARY_SIZE);
499 frame_ref += APN_TOKEN_BINARY_SIZE;
500
501 /* Payload */
502 *frame_ref++ = item_id++;
503 item_data_size_n = htons(payload_size);
504 memcpy(frame_ref, &item_data_size_n, sizeof (uint16_t));
505 frame_ref += sizeof (uint16_t);
506 memcpy(frame_ref, payload, payload_size);
507 frame_ref += payload_size;
508
509 /* Message ID */
510 *frame_ref++ = item_id++;
511 item_data_size_n = htons(sizeof (uint32_t));
512 memcpy(frame_ref, &item_data_size_n, sizeof (uint16_t));
513 frame_ref += sizeof (uint16_t);
514 memcpy(frame_ref, &id_n, sizeof (uint32_t));
515 frame_ref += sizeof (uint32_t);
516
517 /* Expires */
518 *frame_ref++ = item_id++;
519 item_data_size_n = htons(sizeof (uint32_t));
520 memcpy(frame_ref, &item_data_size_n, sizeof (uint16_t));
521 frame_ref += sizeof (uint16_t);
522 memcpy(frame_ref, &expiry_n, sizeof (uint32_t));
523 frame_ref += sizeof (uint32_t);
524
525 /* Priority */
526 *frame_ref++ = item_id;
527 item_data_size_n = htons(sizeof (uint8_t));
528 memcpy(frame_ref, &item_data_size_n, sizeof (uint16_t));
529 frame_ref += sizeof (uint16_t);
530 *frame_ref++ = (uint8_t) priority;
531
532 /* Binary message */
533 *binary_message_ref++ = 2;
534
535 memcpy(binary_message_ref, &frame_size_n, sizeof (uint32_t));
536 binary_message_ref += sizeof (uint32_t);
537 memcpy(binary_message_ref, frame, frame_size);
538
539 free(frame);
540
541 *message = binary_message;
542 return binary_message_size;
543 }
544
__apn_create_json_document_from_payload(apn_payload_ctx_ref payload_ctx,apn_error_ref * error)545 static char * __apn_create_json_document_from_payload(apn_payload_ctx_ref payload_ctx, apn_error_ref *error) {
546 json_t *root = NULL;
547 json_t *aps = NULL;
548 json_t *alert = NULL;
549 json_t *args = NULL;
550 json_t *array = NULL;
551 char *json_document = NULL;
552 uint16_t i = 0;
553 uint8_t array_i = 0;
554
555 root = json_object();
556 if (!root) {
557 APN_SET_ERROR(error, APN_ERR_PAYLOAD_COULD_NOT_CREATE_JSON_DOCUMENT | APN_ERR_CLASS_INTERNAL, __apn_errors[APN_ERR_PAYLOAD_COULD_NOT_CREATE_JSON_DOCUMENT]);
558 return NULL;
559 }
560
561 aps = json_object();
562 if (!aps) {
563 APN_SET_ERROR(error, APN_ERR_PAYLOAD_COULD_NOT_CREATE_JSON_DOCUMENT | APN_ERR_CLASS_INTERNAL, __apn_errors[APN_ERR_PAYLOAD_COULD_NOT_CREATE_JSON_DOCUMENT]);
564 return NULL;
565 }
566
567 if (!payload_ctx->alert || (!payload_ctx->alert->loc_key && !payload_ctx->alert->body && !payload_ctx->content_available)) {
568 APN_SET_ERROR(error, APN_ERR_PAYLOAD_ALERT_IS_NOT_SET | APN_ERR_CLASS_USER, __apn_errors[APN_ERR_PAYLOAD_ALERT_IS_NOT_SET]);
569 return NULL;
570 }
571
572 if (!payload_ctx->alert->action_loc_key && !payload_ctx->alert->launch_image &&
573 !payload_ctx->alert->loc_args && !payload_ctx->alert->loc_key) {
574
575 json_object_set_new(aps, "alert", json_string(payload_ctx->alert->body));
576 } else {
577 alert = json_object();
578
579 if (payload_ctx->alert->body) {
580 json_object_set_new(alert, "body", json_string(payload_ctx->alert->body));
581 }
582
583 if (payload_ctx->alert->launch_image) {
584 json_object_set_new(alert, "launch-image", json_string(payload_ctx->alert->launch_image));
585 }
586
587 if (payload_ctx->alert->action_loc_key) {
588 json_object_set_new(alert, "action-loc-key", json_string(payload_ctx->alert->action_loc_key));
589 }
590
591 if (payload_ctx->alert->loc_key) {
592 json_object_set_new(alert, "loc-key", json_string(payload_ctx->alert->loc_key));
593 }
594
595 if (payload_ctx->alert->__loc_args_count > 0 && payload_ctx->alert->loc_args) {
596 args = json_array();
597 for (i = 0; i < payload_ctx->alert->__loc_args_count; i++) {
598 json_array_append(args, json_string(*(payload_ctx->alert->loc_args + i)));
599 }
600 json_object_set_new(alert, "loc-args", args);
601 }
602
603 json_object_set_new(aps, "alert", alert);
604 }
605
606 if (payload_ctx->content_available == 1) {
607 json_object_set_new(aps, "content-available", json_integer(payload_ctx->content_available));
608 }
609
610 if (payload_ctx->badge > -1) {
611 json_object_set_new(aps, "badge", json_integer(payload_ctx->badge));
612 }
613
614 if (payload_ctx->sound) {
615 json_object_set_new(aps, "sound", json_string(payload_ctx->sound));
616 }
617
618 json_object_set_new(root, "aps", aps);
619
620 if (payload_ctx->custom_properties && payload_ctx->__custom_properties_count) {
621 for (i = 0; i < payload_ctx->__custom_properties_count; i++) {
622 apn_payload_custom_property_ref property = *(payload_ctx->custom_properties + i);
623 switch (property->value_type) {
624 case APN_CUSTOM_PROPERTY_TYPE_BOOL:
625 json_object_set_new(root, property->key, ((property->value.bool_value == 0) ? json_false() : json_true()));
626 break;
627 case APN_CUSTOM_PROPERTY_TYPE_NUMERIC:
628 json_object_set_new(root, property->key, json_integer((json_int_t) property->value.numeric_value));
629 break;
630 case APN_CUSTOM_PROPERTY_TYPE_NULL:
631 json_object_set_new(root, property->key, json_null());
632 break;
633 case APN_CUSTOM_PROPERTY_TYPE_STRING:
634 json_object_set_new(root, property->key, json_string(property->value.string_value.value));
635 break;
636 case APN_CUSTOM_PROPERTY_TYPE_DOUBLE:
637 json_object_set_new(root, property->key, json_real(property->value.double_value));
638 break;
639 case APN_CUSTOM_PROPERTY_TYPE_ARRAY:
640 {
641 for (array_i = 0; array_i < property->value.array_value.array_size; array_i++) {
642 json_array_append(array, json_string(*(property->value.array_value.array + array_i)));
643 }
644 json_object_set_new(root, property->key, array);
645 }
646 break;
647 }
648 }
649 }
650
651 json_document = json_dumps(root, JSON_COMPACT);
652 json_decref(root);
653 return json_document;
654 }
655
__apn_password_cd(char * buf,int size,int rwflag,void * password)656 static int __apn_password_cd(char *buf, int size, int rwflag, void *password) {
657 if (password == NULL) {
658 return 0;
659 }
660 #ifdef _WIN32
661 strncpy_s(buf, size, (char *) password, size);
662 #else
663 strncpy(buf, (char *) password, size);
664 #endif
665 buf[size - 1] = '\0';
666
667 return strlen(buf);
668 }
669
670 #if defined(__APPLE__) && defined(__MACH__)
671 /* Apple deprecated SSL functions on Mac OS X >= 10.7.
672 * Disable deprecated warnings
673 */
674 DIAGNOSTIC_OFF(deprecated-declarations)
675 #endif
676
__apn_connect(const apn_ctx_ref ctx,struct __apn_appl_server server,apn_error_ref * error)677 static uint8_t __apn_connect(const apn_ctx_ref ctx, struct __apn_appl_server server, apn_error_ref *error) {
678 struct hostent * hostent = NULL;
679 struct sockaddr_in socket_address;
680 SOCKET sock = -1; /* File descriptor for socket connection */
681 int sock_flags = 0; /* Socket flags */
682 SSL_CTX *ssl_ctx = NULL; /* Pointer to the SSL context */
683 char *password = NULL;
684
685 #ifdef _WIN32
686 WSADATA wsa_data;
687 #endif
688
689 if (ctx->sock == -1) {
690 #ifdef _WIN32
691 if (WSAStartup(MAKEWORD(2, 2), &wsa_data) != 0) {
692 APN_SET_ERROR(error, -100, "WSAStartup failed");
693 APN_RETURN_ERROR;
694 }
695 #endif
696
697 hostent = gethostbyname(server.host);
698
699 if (!hostent) {
700 APN_SET_ERROR(error, APN_ERR_COULD_NOT_RESOLVE_HOST | APN_ERR_CLASS_INTERNAL, __apn_errors[APN_ERR_COULD_NOT_RESOLVE_HOST]);
701 APN_RETURN_ERROR;
702 }
703
704 memset(&socket_address, 0, sizeof (socket_address));
705 socket_address.sin_addr = *(struct in_addr*) hostent->h_addr_list[0];
706 socket_address.sin_family = AF_INET;
707 socket_address.sin_port = htons(server.port);
708
709 sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
710
711 if (sock < 0) {
712 APN_SET_ERROR(error, APN_ERR_COULD_NOT_CREATE_SOCKET | APN_ERR_CLASS_INTERNAL, __apn_errors[APN_ERR_COULD_NOT_CREATE_SOCKET]);
713 APN_RETURN_ERROR;
714 }
715
716 if (connect(sock, (struct sockaddr *) &socket_address, sizeof (socket_address)) < 0) {
717 APN_SET_ERROR(error, APN_ERR_COULD_NOT_INITIALIZE_CONNECTION | APN_ERR_CLASS_INTERNAL, __apn_errors[APN_ERR_COULD_NOT_INITIALIZE_CONNECTION]);
718 APN_RETURN_ERROR;
719 }
720
721 ctx->sock = sock;
722 ssl_ctx = SSL_CTX_new(TLSv1_client_method());
723
724 if (!SSL_CTX_use_certificate_file(ssl_ctx, ctx->certificate_file, SSL_FILETYPE_PEM)) {
725 APN_SET_ERROR(error, APN_ERR_UNABLE_TO_USE_SPECIFIED_CERTIFICATE | APN_ERR_CLASS_USER, __apn_errors[APN_ERR_UNABLE_TO_USE_SPECIFIED_CERTIFICATE]);
726 SSL_CTX_free(ssl_ctx);
727 APN_RETURN_ERROR;
728 }
729
730 SSL_CTX_set_default_passwd_cb(ssl_ctx, __apn_password_cd);
731
732 if (ctx->private_key_pass) {
733 password = apn_strndup(ctx->private_key_pass, strlen(ctx->private_key_pass));
734 if (password == NULL) {
735 APN_SET_ERROR(error, APN_ERR_NOMEM | APN_ERR_CLASS_INTERNAL, __apn_errors[APN_ERR_NOMEM]);
736 APN_RETURN_ERROR;
737 }
738 SSL_CTX_set_default_passwd_cb_userdata(ssl_ctx, password);
739 } else {
740 SSL_CTX_set_default_passwd_cb_userdata(ssl_ctx, NULL);
741 }
742
743 if (!SSL_CTX_use_PrivateKey_file(ssl_ctx, ctx->private_key_file, SSL_FILETYPE_PEM)) {
744 APN_SET_ERROR(error, APN_ERR_UNABLE_TO_USE_SPECIFIED_PRIVATE_KEY | APN_ERR_CLASS_USER, __apn_errors[APN_ERR_UNABLE_TO_USE_SPECIFIED_PRIVATE_KEY]);
745 SSL_CTX_free(ssl_ctx);
746 if (password) {
747 free(password);
748 }
749 APN_RETURN_ERROR;
750 }
751
752 if (password) {
753 free(password);
754 }
755
756 if (!SSL_CTX_check_private_key(ssl_ctx)) {
757 APN_SET_ERROR(error, APN_ERR_UNABLE_TO_USE_SPECIFIED_PRIVATE_KEY | APN_ERR_CLASS_USER, __apn_errors[APN_ERR_UNABLE_TO_USE_SPECIFIED_PRIVATE_KEY]);
758 SSL_CTX_free(ssl_ctx);
759 APN_RETURN_ERROR;
760 }
761
762 ctx->ssl = SSL_new(ssl_ctx);
763 SSL_CTX_free(ssl_ctx);
764
765 if (!ctx->ssl) {
766 APN_SET_ERROR(error, APN_ERR_COULD_NOT_INITIALIZE_SSL_CONNECTION | APN_ERR_CLASS_INTERNAL, __apn_errors[APN_ERR_COULD_NOT_INITIALIZE_SSL_CONNECTION]);
767 APN_RETURN_ERROR;
768 }
769
770 if (SSL_set_fd(ctx->ssl, ctx->sock) == -1) {
771 APN_SET_ERROR(error, APN_ERR_COULD_NOT_INITIALIZE_SSL_CONNECTION | APN_ERR_CLASS_INTERNAL, __apn_errors[APN_ERR_COULD_NOT_INITIALIZE_SSL_CONNECTION]);
772 APN_RETURN_ERROR;
773 }
774
775 if (SSL_connect(ctx->ssl) < 1) {
776 APN_SET_ERROR(error, APN_ERR_COULD_NOT_INITIALIZE_SSL_CONNECTION | APN_ERR_CLASS_INTERNAL, __apn_errors[APN_ERR_COULD_NOT_INITIALIZE_SSL_CONNECTION]);
777 APN_RETURN_ERROR;
778 }
779
780 #ifndef _WIN32
781 sock_flags = fcntl(ctx->sock, F_GETFL, 0);
782 fcntl(ctx->sock, F_SETFL, sock_flags | O_NONBLOCK);
783 #else
784 sock_flags = 1;
785 ioctlsocket(ctx->sock, FIONBIO, (u_long *) & sock_flags);
786 #endif
787 }
788
789 APN_RETURN_SUCCESS;
790 }
791
apn_close(apn_ctx_ref ctx)792 void apn_close(apn_ctx_ref ctx) {
793 if (ctx) {
794 if (ctx->ssl) {
795 SSL_shutdown(ctx->ssl);
796 SSL_free(ctx->ssl);
797 ctx->ssl = NULL;
798 }
799
800 if (ctx->sock != -1) {
801 CLOSE_SOCKET(ctx->sock);
802 ctx->sock = -1;
803 }
804
805 #ifdef _WIN32
806 WSACleanup();
807 #endif
808 }
809 }
810
__apn_parse_apns_error(char * apns_error,uint32_t * id,apn_error_ref * error)811 static void __apn_parse_apns_error(char *apns_error, uint32_t *id, apn_error_ref *error) {
812 uint8_t cmd = 0;
813 uint8_t error_code = 0;
814 uint32_t notification_id = 0;
815
816 memcpy(&cmd, apns_error, sizeof (uint8_t));
817 apns_error += sizeof (cmd);
818
819 if (cmd == 8) {
820 memcpy(&error_code, apns_error, sizeof (uint8_t));
821 apns_error += sizeof (error_code);
822
823 switch (error_code) {
824 case APN_APNS_ERR_PROCESSING_ERROR:
825 APN_SET_ERROR(error, APN_ERR_PROCESSING_ERROR | APN_ERR_CLASS_INTERNAL, __apn_errors[APN_ERR_PROCESSING_ERROR]);
826 break;
827 case APN_APNS_ERR_INVALID_PAYLOAD_SIZE:
828 APN_SET_ERROR(error, APN_ERR_INVALID_PAYLOAD_SIZE | APN_ERR_CLASS_USER, __apn_errors[APN_ERR_INVALID_PAYLOAD_SIZE]);
829 break;
830 case APN_APNS_ERR_SERVICE_SHUTDOWN:
831 APN_SET_ERROR(error, APN_ERR_SERVICE_SHUTDOWN | APN_ERR_CLASS_USER, __apn_errors[APN_ERR_SERVICE_SHUTDOWN]);
832 break;
833 case APN_APNS_ERR_INVALID_TOKEN:
834 APN_SET_ERROR(error, APN_ERR_TOKEN_INVALID | APN_ERR_CLASS_USER, __apn_errors[APN_ERR_TOKEN_INVALID]);
835 break;
836 default: break;
837 }
838
839 if (id) {
840 memcpy(¬ification_id, apns_error, sizeof (uint32_t));
841 *id = ntohl(notification_id);
842 }
843 }
844 }
845
__ssl_write(const apn_ctx_ref ctx,const uint8_t * message,size_t length,apn_error_ref * error)846 static size_t __ssl_write(const apn_ctx_ref ctx, const uint8_t *message, size_t length, apn_error_ref *error) {
847 int bytes_written = 0;
848 int bytes_written_total = 0;
849
850 while (length > 0) {
851 bytes_written = SSL_write(ctx->ssl, message, length);
852
853 if (bytes_written <= 0) {
854 switch (SSL_get_error(ctx->ssl, bytes_written)) {
855 case SSL_ERROR_WANT_WRITE:
856 case SSL_ERROR_WANT_READ:
857 #ifdef _WIN32
858 Sleep(1000);
859 #else
860 sleep(1);
861 #endif
862 continue;
863 case SSL_ERROR_SYSCALL:
864 switch (errno) {
865 case EINTR:
866 continue;
867 case EPIPE:
868 APN_SET_ERROR(error, APN_ERR_CONNECTION_CLOSED | APN_ERR_CLASS_INTERNAL, "network unreachable (SSL_ERROR_SYSCALL, errno => EPIPE)");
869 return -1;
870 case ETIMEDOUT:
871 APN_SET_ERROR(error, APN_ERR_CONNECTION_CLOSED | APN_ERR_CLASS_INTERNAL, "connection timeout (SSL_ERROR_SYSCALL, errno => ETIMEDOUT)");
872 return -1;
873 default:
874 APN_SET_ERROR(error, APN_ERR_SSL_WRITE_FAILED | APN_ERR_CLASS_INTERNAL, __apn_errors[APN_ERR_SSL_WRITE_FAILED]);
875 return -1;
876 }
877 case SSL_ERROR_ZERO_RETURN:
878 APN_SET_ERROR(error, APN_ERR_CONNECTION_CLOSED | APN_ERR_CLASS_INTERNAL, "server closed connection (SSL_ERROR_ZERO_RETURN)");
879 return -1;
880 default:
881 APN_SET_ERROR(error, APN_ERR_SSL_WRITE_FAILED | APN_ERR_CLASS_INTERNAL, __apn_errors[APN_ERR_SSL_WRITE_FAILED]);
882 return -1;
883 }
884 }
885
886 message += bytes_written;
887 bytes_written_total += bytes_written;
888 length -= bytes_written;
889 }
890
891 return bytes_written_total;
892 }
893
__ssl_read(const apn_ctx_ref ctx,char * buff,size_t buff_length,apn_error_ref * error)894 static int __ssl_read(const apn_ctx_ref ctx, char *buff, size_t buff_length, apn_error_ref *error) {
895 int read = -1;
896 for (;;) {
897 read = SSL_read(ctx->ssl, buff, buff_length);
898 if (read > 0) {
899 break;
900 }
901 switch (SSL_get_error(ctx->ssl, read)) {
902 case SSL_ERROR_WANT_WRITE:
903 case SSL_ERROR_WANT_READ:
904 #ifdef _WIN32
905 Sleep(1000);
906 #else
907 sleep(1);
908 #endif
909 continue;
910 case SSL_ERROR_SYSCALL:
911 switch (errno) {
912 case EINTR:
913 continue;
914 case EPIPE:
915 APN_SET_ERROR(error, APN_ERR_CONNECTION_CLOSED | APN_ERR_CLASS_INTERNAL, "network unreachable (SSL_ERROR_SYSCALL, errno => EPIPE)");
916 return -1;
917 case ETIMEDOUT:
918 APN_SET_ERROR(error, APN_ERR_CONNECTION_CLOSED | APN_ERR_CLASS_INTERNAL, "connection timeout (SSL_ERROR_SYSCALL, errno => ETIMEDOUT)");
919 return -1;
920 default:
921 APN_SET_ERROR(error, APN_ERR_SSL_READ_FAILED | APN_ERR_CLASS_INTERNAL, __apn_errors[APN_ERR_SSL_READ_FAILED]);
922 return -1;
923 }
924
925 case SSL_ERROR_ZERO_RETURN:
926 //APN_SET_ERROR(error, APN_ERR_CONNECTION_CLOSED | APN_ERR_CLASS_INTERNAL, "server closed connection (SSL_ERROR_ZERO_RETURN)");
927 return 0;
928 default:
929 APN_SET_ERROR(error, APN_ERR_SSL_READ_FAILED | APN_ERR_CLASS_INTERNAL, __apn_errors[APN_ERR_SSL_READ_FAILED]);
930 return -1;
931 }
932 }
933
934 return read;
935 }
936
apn_feedback(const apn_ctx_ref ctx,char *** tokens_array,uint32_t * tokens_array_count,apn_error_ref * error)937 uint8_t apn_feedback(const apn_ctx_ref ctx, char ***tokens_array, uint32_t *tokens_array_count, apn_error_ref *error) {
938 char buffer[38]; /* Buffer to read data */
939 char *buffer_ref = buffer; /* Pointer to buffer */
940 fd_set read_set;
941 struct timeval timeout = {3, 0};
942 uint16_t token_length = 0;
943 uint8_t binary_token[APN_TOKEN_BINARY_SIZE];
944 int bytes_read = 0; /* Number of bytes read */
945 char **tokens = NULL; /* Array of HEX tokens */
946 uint32_t tokens_count = 0; /* Tokens count */
947 char *token_hex = NULL; /* Token as HEX string */
948 int select_returned = 0;
949
950 if (!ctx) {
951 APN_SET_ERROR(error, APN_ERR_CTX_NOT_INITIALIZED | APN_ERR_CLASS_USER, __apn_errors[APN_ERR_CTX_NOT_INITIALIZED]);
952 APN_RETURN_ERROR;
953 }
954
955 if (!ctx->ssl || !ctx->feedback) {
956 APN_SET_ERROR(error, APN_ERR_NOT_CONNECTED_FEEDBACK | APN_ERR_CLASS_USER, __apn_errors[APN_ERR_NOT_CONNECTED_FEEDBACK]);
957 APN_RETURN_ERROR;
958 }
959
960 if (!ctx->certificate_file) {
961 APN_SET_ERROR(error, APN_ERR_CERTIFICATE_IS_NOT_SET | APN_ERR_CLASS_USER, __apn_errors[APN_ERR_CERTIFICATE_IS_NOT_SET]);
962 APN_RETURN_ERROR;
963 }
964
965 if (!ctx->private_key_file) {
966 APN_SET_ERROR(error, APN_ERR_PRIVATE_KEY_IS_NOT_SET | APN_ERR_CLASS_USER, __apn_errors[APN_ERR_PRIVATE_KEY_IS_NOT_SET]);
967 APN_RETURN_ERROR;
968 }
969
970 for (;;) {
971 FD_ZERO(&read_set);
972 FD_SET(ctx->sock, &read_set);
973
974 select_returned = select(ctx->sock + 1, &read_set, NULL, NULL, &timeout);
975 if (select_returned < 0) {
976 if (errno == EINTR) {
977 continue;
978 }
979 APN_SET_ERROR(error, APN_ERR_SELECT | APN_ERR_CLASS_INTERNAL, __apn_errors[APN_ERR_SELECT]);
980 APN_RETURN_ERROR;
981 }
982
983 if (select_returned == 0) {
984 /* select() timed out */
985 break;
986 }
987
988 if (FD_ISSET(ctx->sock, &read_set)) {
989 bytes_read = __ssl_read(ctx, buffer, sizeof (buffer), error);
990
991 if (bytes_read < 0) {
992 APN_RETURN_ERROR;
993 }
994
995 if (bytes_read > 0) {
996 buffer_ref += sizeof (uint32_t);
997 memcpy(&token_length, buffer_ref, sizeof (token_length));
998 buffer_ref += sizeof (token_length);
999 token_length = ntohs(token_length);
1000
1001 memcpy(&binary_token, buffer_ref, sizeof (binary_token));
1002
1003 token_hex = __token_binary_to_hex(binary_token);
1004 if (token_hex == NULL) {
1005 APN_SET_ERROR(error, APN_ERR_NOMEM | APN_ERR_CLASS_INTERNAL, __apn_errors[APN_ERR_NOMEM]);
1006 APN_RETURN_ERROR;
1007 }
1008
1009 tokens = (char **) __apn_realloc(tokens, (tokens_count + 1) * sizeof (char *));
1010 if (!tokens) {
1011 APN_SET_ERROR(error, APN_ERR_NOMEM | APN_ERR_CLASS_INTERNAL, __apn_errors[APN_ERR_NOMEM]);
1012 APN_RETURN_ERROR;
1013 }
1014 tokens[tokens_count] = token_hex;
1015 tokens_count++;
1016 }
1017 break;
1018 }
1019 }
1020
1021 if (tokens_array != NULL && tokens_count > 0) {
1022 *tokens_array = tokens;
1023 }
1024
1025 if (tokens_array_count != NULL) {
1026 *tokens_array_count = tokens_count;
1027 }
1028
1029 APN_RETURN_SUCCESS;
1030 }
1031
apn_send(const apn_ctx_ref ctx,apn_payload_ctx_ref payload,apn_error_ref * error)1032 uint8_t apn_send(const apn_ctx_ref ctx, apn_payload_ctx_ref payload, apn_error_ref *error) {
1033 char *json = NULL;
1034 size_t json_size = 0; /* Payload size */
1035
1036 size_t message_size = 0;
1037 uint8_t *message = NULL;
1038
1039 uint8_t **tokens = NULL;
1040 uint8_t *token = NULL;
1041 char apple_error[6];
1042 int bytes_read = 0; /* Number of bytes read */
1043 int bytes_written = 0; /* Number of bytes written */
1044 uint8_t has_error = 0;
1045 uint32_t tokens_count = 0;
1046 uint32_t invalid_id = 0;
1047 fd_set write_set, read_set;
1048 int select_returned = 0;
1049 uint32_t i = 0;
1050 struct timeval timeout = {10, 0};
1051
1052 if (!ctx) {
1053 APN_SET_ERROR(error, APN_ERR_CTX_NOT_INITIALIZED | APN_ERR_CLASS_USER, __apn_errors[APN_ERR_CTX_NOT_INITIALIZED]);
1054 APN_RETURN_ERROR;
1055 }
1056
1057 if (!ctx->ssl || ctx->feedback) {
1058 APN_SET_ERROR(error, APN_ERR_NOT_CONNECTED | APN_ERR_CLASS_USER, __apn_errors[APN_ERR_NOT_CONNECTED]);
1059 APN_RETURN_ERROR;
1060 }
1061
1062 if (!ctx->certificate_file) {
1063 APN_SET_ERROR(error, APN_ERR_CERTIFICATE_IS_NOT_SET | APN_ERR_CLASS_USER, __apn_errors[APN_ERR_CERTIFICATE_IS_NOT_SET]);
1064 APN_RETURN_ERROR;
1065 }
1066 if (!ctx->private_key_file) {
1067 APN_SET_ERROR(error, APN_ERR_PRIVATE_KEY_IS_NOT_SET | APN_ERR_CLASS_USER, __apn_errors[APN_ERR_PRIVATE_KEY_IS_NOT_SET]);
1068 APN_RETURN_ERROR;
1069 }
1070
1071 if (!payload) {
1072 APN_SET_ERROR(error, APN_ERR_PAYLOAD_IS_NOT_SET | APN_ERR_CLASS_USER, __apn_errors[APN_ERR_PAYLOAD_IS_NOT_SET]);
1073 APN_RETURN_ERROR;
1074 }
1075
1076 if (payload->__tokens_count > 0 && payload->tokens != NULL) {
1077 tokens = payload->tokens;
1078 tokens_count = payload->__tokens_count;
1079 } else if (ctx->__tokens_count > 0 && ctx->tokens != NULL) {
1080 tokens = ctx->tokens;
1081 tokens_count = ctx->__tokens_count;
1082 }
1083
1084 if (tokens_count == 0) {
1085 APN_SET_ERROR(error, APN_ERR_TOKEN_IS_NOT_SET | APN_ERR_CLASS_USER, __apn_errors[APN_ERR_TOKEN_IS_NOT_SET]);
1086 APN_RETURN_ERROR;
1087 }
1088
1089 json = __apn_create_json_document_from_payload(payload, error);
1090
1091 if (!json) {
1092 APN_RETURN_ERROR;
1093 }
1094
1095 json_size = strlen(json);
1096
1097 if (json_size > APN_PAYLOAD_MAX_SIZE) {
1098 APN_SET_ERROR(error, APN_ERR_INVALID_PAYLOAD_SIZE | APN_ERR_CLASS_USER, __apn_errors[APN_ERR_INVALID_PAYLOAD_SIZE]);
1099 free(json);
1100 APN_RETURN_ERROR;
1101 }
1102
1103 while (1) {
1104 if (i == tokens_count) {
1105 break;
1106 }
1107 token = tokens[i];
1108 message_size = __apn_create_binary_message(token, json, i, payload->expiry, payload->priority, &message, error);
1109 if (message_size == 0) {
1110 free(json);
1111 APN_RETURN_ERROR;
1112 }
1113
1114 FD_ZERO(&write_set);
1115 FD_ZERO(&read_set);
1116 FD_SET(ctx->sock, &write_set);
1117 FD_SET(ctx->sock, &read_set);
1118
1119 select_returned = select(ctx->sock + 1, &read_set, &write_set, NULL, &timeout);
1120
1121 if (select_returned <= 0) {
1122 if (errno == EINTR) {
1123 continue;
1124 }
1125 APN_SET_ERROR(error, APN_ERR_SELECT | APN_ERR_CLASS_INTERNAL, __apn_errors[APN_ERR_SELECT]);
1126 APN_RETURN_ERROR;
1127 }
1128
1129 if (FD_ISSET(ctx->sock, &read_set)) {
1130 bytes_read = __ssl_read(ctx, apple_error, sizeof (apple_error), error);
1131 if (bytes_read < 0) {
1132 if (message) {
1133 free(message);
1134 }
1135 free(json);
1136 APN_RETURN_ERROR;
1137 }
1138 free(message);
1139 has_error = 1;
1140 break;
1141 }
1142
1143 if (FD_ISSET(ctx->sock, &write_set)) {
1144 bytes_written = __ssl_write(ctx, message, message_size, error);
1145 free(message);
1146 if (bytes_written <= 0) {
1147 free(json);
1148 APN_RETURN_ERROR;
1149 }
1150 i++;
1151 }
1152 }
1153
1154 free(json);
1155
1156 if (!has_error) {
1157 timeout.tv_sec = 1;
1158 for (;;) {
1159 FD_ZERO(&read_set);
1160 FD_SET(ctx->sock, &read_set);
1161
1162 select_returned = select(ctx->sock + 1, &read_set, NULL, NULL, &timeout);
1163
1164 if (select_returned < 0) {
1165 if (errno == EINTR) {
1166 continue;
1167 }
1168
1169 APN_SET_ERROR(error, APN_ERR_SELECT | APN_ERR_CLASS_INTERNAL, __apn_errors[APN_ERR_SELECT]);
1170 APN_RETURN_ERROR;
1171 }
1172
1173 if (select_returned == 0) {
1174 /* select() timed out */
1175 break;
1176 }
1177
1178 if (FD_ISSET(ctx->sock, &read_set)) {
1179 bytes_read = __ssl_read(ctx, apple_error, sizeof (apple_error), error);
1180 if (bytes_read > 0) {
1181 has_error = 1;
1182 } else {
1183 APN_RETURN_ERROR;
1184 }
1185 break;
1186 }
1187 }
1188 }
1189
1190 if (has_error) {
1191 __apn_parse_apns_error(apple_error, &invalid_id, error);
1192 if (apn_error_code(*error) == APN_ERR_TOKEN_INVALID) {
1193 (*error)->invalid_token = __token_binary_to_hex(tokens[invalid_id]);
1194 }
1195 APN_RETURN_ERROR;
1196 }
1197
1198 APN_RETURN_SUCCESS;
1199 }
1200
apn_init(apn_ctx_ref * ctx,const char * cert,const char * private_key,const char * private_key_pass,apn_error_ref * error)1201 uint8_t apn_init(apn_ctx_ref *ctx, const char *cert, const char *private_key, const char *private_key_pass, apn_error_ref *error) {
1202 apn_ctx_ref _ctx = NULL;
1203
1204 if (!ctx) {
1205 APN_SET_ERROR(error, APN_ERR_INVALID_ARGUMENT | APN_ERR_CLASS_USER, "invalid argument ctx. Expected pointer to pointer to apn_ctx struct, passed NULL");
1206 APN_RETURN_ERROR;
1207 }
1208
1209 *ctx = NULL;
1210 _ctx = malloc(sizeof (apn_ctx));
1211
1212 if (!_ctx) {
1213 APN_SET_ERROR(error, APN_ERR_NOMEM | APN_ERR_CLASS_INTERNAL, __apn_errors[APN_ERR_NOMEM]);
1214 APN_RETURN_ERROR;
1215 }
1216
1217 _ctx->sock = -1;
1218 _ctx->ssl = NULL;
1219 _ctx->__tokens_count = 0;
1220 _ctx->certificate_file = NULL;
1221 _ctx->private_key_file = NULL;
1222 _ctx->tokens = NULL;
1223 _ctx->feedback = 0;
1224 _ctx->private_key_pass = NULL;
1225 _ctx->mode = APN_MODE_PRODUCTION;
1226
1227 if (cert && strlen(cert) > 0) {
1228 if (apn_set_certificate(_ctx, cert, error) != APN_SUCCESS) {
1229 apn_free(&_ctx);
1230 APN_RETURN_ERROR;
1231 }
1232 }
1233
1234 if (private_key && strlen(private_key) > 0) {
1235 if (private_key_pass && strlen(private_key_pass) > 0) {
1236 if (apn_set_private_key(_ctx, private_key, private_key_pass, error) != APN_SUCCESS) {
1237 apn_free(&_ctx);
1238 APN_RETURN_ERROR;
1239 }
1240 } else {
1241 if (apn_set_private_key(_ctx, private_key, NULL, error) != APN_SUCCESS) {
1242 apn_free(&_ctx);
1243 APN_RETURN_ERROR;
1244 }
1245 }
1246 }
1247
1248 if (!__ssl_lib_initialized) {
1249 SSL_library_init();
1250 SSL_load_error_strings();
1251 __ssl_lib_initialized = 1;
1252 }
1253
1254 *ctx = _ctx;
1255 APN_RETURN_SUCCESS;
1256 }
1257
1258 #if defined(__APPLE__) && defined(__MACH__)
1259 DIAGNOSTIC_ON(deprecated-declarations)
1260 #endif
1261
apn_copy(const apn_ctx_ref ctx,apn_error_ref * error)1262 apn_ctx_ref apn_copy(const apn_ctx_ref ctx, apn_error_ref *error) {
1263 apn_ctx_ref _ctx = NULL;
1264
1265 if (!ctx) {
1266 APN_SET_ERROR(error, APN_ERR_CTX_NOT_INITIALIZED | APN_ERR_CLASS_USER, __apn_errors[APN_ERR_CTX_NOT_INITIALIZED]);
1267 return NULL;
1268 }
1269
1270 if (apn_init(&_ctx, NULL, NULL, NULL, error)) {
1271 return NULL;
1272 }
1273
1274 if (ctx->certificate_file) {
1275 if ((_ctx->certificate_file = apn_strndup(ctx->certificate_file, strlen(ctx->certificate_file))) == NULL) {
1276 APN_SET_ERROR(error, APN_ERR_NOMEM | APN_ERR_CLASS_INTERNAL, __apn_errors[APN_ERR_NOMEM]);
1277 return NULL;
1278 }
1279 }
1280
1281 if (ctx->private_key_file) {
1282 if ((_ctx->private_key_file = apn_strndup(ctx->private_key_file, strlen(ctx->private_key_file))) == NULL) {
1283 APN_SET_ERROR(error, APN_ERR_NOMEM | APN_ERR_CLASS_INTERNAL, __apn_errors[APN_ERR_NOMEM]);
1284 return NULL;
1285 }
1286 }
1287
1288 if (ctx->private_key_pass) {
1289 if ((_ctx->private_key_pass = apn_strndup(ctx->private_key_pass, strlen(ctx->private_key_pass))) == NULL) {
1290 APN_SET_ERROR(error, APN_ERR_NOMEM | APN_ERR_CLASS_INTERNAL, __apn_errors[APN_ERR_NOMEM]);
1291 return NULL;
1292 }
1293 }
1294
1295 _ctx->tokens = __apn_tokens_array_copy(ctx->tokens, ctx->__tokens_count, error);
1296 if (_ctx->tokens == NULL && __apn_is_error((*error))) {
1297 apn_free(&_ctx);
1298 return NULL;
1299 }
1300 _ctx->__tokens_count = ctx->__tokens_count;
1301
1302 _ctx->feedback = ctx->feedback;
1303 _ctx->mode = ctx->mode;
1304
1305 return _ctx;
1306 }
1307
apn_free(apn_ctx_ref * ctx)1308 void apn_free(apn_ctx_ref *ctx) {
1309 apn_ctx_ref _ctx = NULL;
1310
1311 if (!ctx || !(*ctx)) {
1312 return;
1313 }
1314
1315 _ctx = *ctx;
1316
1317 if (_ctx) {
1318 apn_close(_ctx);
1319 }
1320
1321 if (_ctx->certificate_file) {
1322 free(_ctx->certificate_file);
1323 }
1324
1325 if (_ctx->private_key_file) {
1326 free(_ctx->private_key_file);
1327 }
1328
1329 if (_ctx->private_key_pass) {
1330 free(_ctx->private_key_pass);
1331 }
1332
1333 __apn_tokens_array_free(_ctx->tokens, _ctx->__tokens_count);
1334
1335 free(_ctx);
1336 *ctx = NULL;
1337 }
1338
apn_connect(const apn_ctx_ref ctx,apn_error_ref * error)1339 uint8_t apn_connect(const apn_ctx_ref ctx, apn_error_ref *error) {
1340 struct __apn_appl_server server;
1341 if (ctx->mode == APN_MODE_SANDBOX) {
1342 server = __apn_appl_servers[0];
1343 } else {
1344 server = __apn_appl_servers[1];
1345 }
1346
1347 return __apn_connect(ctx, server, error);
1348 }
1349
apn_feedback_connect(const apn_ctx_ref ctx,apn_error_ref * error)1350 uint8_t apn_feedback_connect(const apn_ctx_ref ctx, apn_error_ref *error) {
1351 struct __apn_appl_server server;
1352 if (ctx->mode == APN_MODE_SANDBOX) {
1353 server = __apn_appl_servers[2];
1354 } else {
1355 server = __apn_appl_servers[3];
1356 }
1357
1358 ctx->feedback = 1;
1359 return __apn_connect(ctx, server, error);
1360 }
1361
apn_set_certificate(apn_ctx_ref ctx,const char * cert,apn_error_ref * error)1362 uint8_t apn_set_certificate(apn_ctx_ref ctx, const char *cert, apn_error_ref *error) {
1363 if (!ctx) {
1364 APN_SET_ERROR(error, APN_ERR_CTX_NOT_INITIALIZED | APN_ERR_CLASS_USER, __apn_errors[APN_ERR_CTX_NOT_INITIALIZED]);
1365 APN_RETURN_ERROR;
1366 }
1367 if (ctx->certificate_file) {
1368 apn_strfree(&ctx->certificate_file);
1369 }
1370 if (cert && strlen(cert) > 0) {
1371 if ((ctx->certificate_file = apn_strndup(cert, strlen(cert))) == NULL) {
1372 APN_SET_ERROR(error, APN_ERR_NOMEM | APN_ERR_CLASS_INTERNAL, __apn_errors[APN_ERR_NOMEM]);
1373 APN_RETURN_ERROR;
1374 }
1375 }
1376
1377 APN_RETURN_SUCCESS;
1378 }
1379
apn_set_private_key(apn_ctx_ref ctx,const char * key,const char * pass,apn_error_ref * error)1380 uint8_t apn_set_private_key(apn_ctx_ref ctx, const char *key, const char *pass, apn_error_ref *error) {
1381 if (!ctx) {
1382 APN_SET_ERROR(error, APN_ERR_CTX_NOT_INITIALIZED | APN_ERR_CLASS_USER, __apn_errors[APN_ERR_CTX_NOT_INITIALIZED]);
1383 APN_RETURN_ERROR;
1384 }
1385 if (ctx->private_key_file) {
1386 apn_strfree(&ctx->private_key_file);
1387 }
1388 if (key && strlen(key) > 0) {
1389 if ((ctx->private_key_file = apn_strndup(key, strlen(key))) == NULL) {
1390 APN_SET_ERROR(error, APN_ERR_NOMEM | APN_ERR_CLASS_INTERNAL, __apn_errors[APN_ERR_NOMEM]);
1391 APN_RETURN_ERROR;
1392 }
1393 }
1394 if (ctx->private_key_pass) {
1395 apn_strfree(&ctx->private_key_pass);
1396 }
1397 if (pass && strlen(pass) > 0) {
1398 if ((ctx->private_key_pass = apn_strndup(pass, strlen(pass))) == NULL) {
1399 APN_SET_ERROR(error, APN_ERR_NOMEM | APN_ERR_CLASS_INTERNAL, __apn_errors[APN_ERR_NOMEM]);
1400 APN_RETURN_ERROR;
1401 }
1402 }
1403 APN_RETURN_SUCCESS;
1404 }
1405
apn_set_mode(apn_ctx_ref ctx,uint8_t mode,apn_error_ref * error)1406 uint8_t apn_set_mode(apn_ctx_ref ctx, uint8_t mode, apn_error_ref *error) {
1407 if (!ctx) {
1408 APN_SET_ERROR(error, APN_ERR_CTX_NOT_INITIALIZED | APN_ERR_CLASS_USER, __apn_errors[APN_ERR_CTX_NOT_INITIALIZED]);
1409 APN_RETURN_ERROR;
1410 }
1411
1412 if (mode == APN_MODE_SANDBOX) {
1413 ctx->mode = APN_MODE_SANDBOX;
1414 } else {
1415 ctx->mode = APN_MODE_PRODUCTION;
1416 }
1417
1418 APN_RETURN_SUCCESS;
1419 }
1420
apn_add_token(apn_ctx_ref ctx,const char * token,apn_error_ref * error)1421 uint8_t apn_add_token(apn_ctx_ref ctx, const char *token, apn_error_ref *error) {
1422 uint8_t *binary_token = NULL;
1423 uint8_t **tokens = NULL;
1424
1425 if (!ctx) {
1426 APN_SET_ERROR(error, APN_ERR_CTX_NOT_INITIALIZED | APN_ERR_CLASS_USER, __apn_errors[APN_ERR_CTX_NOT_INITIALIZED]);
1427 APN_RETURN_ERROR;
1428 }
1429
1430 if (ctx->__tokens_count >= UINT32_MAX) {
1431 APN_SET_ERROR(error, APN_ERR_TOKEN_TOO_MANY | APN_ERR_CLASS_USER, __apn_errors[APN_ERR_TOKEN_TOO_MANY]);
1432 APN_RETURN_ERROR;
1433 }
1434
1435 if (!token || strlen(token) == 0) {
1436 APN_SET_ERROR(error, APN_ERR_INVALID_ARGUMENT | APN_ERR_CLASS_USER, "invalid value of token. Expected string, passed NULL");
1437 APN_RETURN_ERROR;
1438 }
1439
1440 if (!__apn_check_hex_token(token)) {
1441 APN_SET_ERROR(error, APN_ERR_TOKEN_INVALID | APN_ERR_CLASS_USER, __apn_errors[APN_ERR_TOKEN_INVALID]);
1442 APN_RETURN_ERROR;
1443 }
1444
1445 tokens = (uint8_t **)__apn_realloc(ctx->tokens, (ctx->__tokens_count + 1) * sizeof(uint8_t *));
1446 if (!tokens) {
1447 APN_SET_ERROR(error, APN_ERR_NOMEM | APN_ERR_CLASS_INTERNAL, __apn_errors[APN_ERR_NOMEM]);
1448 APN_RETURN_ERROR;
1449 }
1450 ctx->tokens = tokens;
1451
1452 if (!(binary_token = __token_hex_to_binary(token))) {
1453 APN_SET_ERROR(error, APN_ERR_NOMEM | APN_ERR_CLASS_INTERNAL, __apn_errors[APN_ERR_NOMEM]);
1454 APN_RETURN_ERROR;
1455 }
1456
1457 ctx->tokens[ctx->__tokens_count] = binary_token;
1458 ctx->__tokens_count++;
1459
1460 APN_RETURN_SUCCESS;
1461 }
1462
apn_certificate(const apn_ctx_ref ctx,apn_error_ref * error)1463 const char *apn_certificate(const apn_ctx_ref ctx, apn_error_ref *error) {
1464 char *ret_value = NULL;
1465
1466 if (!ctx) {
1467 APN_SET_ERROR(error, APN_ERR_CTX_NOT_INITIALIZED | APN_ERR_CLASS_USER, __apn_errors[APN_ERR_CTX_NOT_INITIALIZED]);
1468 return NULL;
1469 }
1470 if (ctx->certificate_file) {
1471 ret_value = ctx->certificate_file;
1472 }
1473 return ret_value;
1474 }
1475
apn_private_key(const apn_ctx_ref ctx,apn_error_ref * error)1476 const char *apn_private_key(const apn_ctx_ref ctx, apn_error_ref *error) {
1477 char *ret_value = NULL;
1478
1479 if (!ctx) {
1480 APN_SET_ERROR(error, APN_ERR_CTX_NOT_INITIALIZED | APN_ERR_CLASS_USER, __apn_errors[APN_ERR_CTX_NOT_INITIALIZED]);
1481 return NULL;
1482 }
1483
1484 if (ctx->private_key_file) {
1485 ret_value = ctx->private_key_file;
1486 }
1487 return ret_value;
1488 }
1489
apn_private_key_pass(const apn_ctx_ref ctx,apn_error_ref * error)1490 const char *apn_private_key_pass(const apn_ctx_ref ctx, apn_error_ref *error) {
1491 char *ret_value = NULL;
1492
1493 if (!ctx) {
1494 APN_SET_ERROR(error, APN_ERR_CTX_NOT_INITIALIZED | APN_ERR_CLASS_USER, __apn_errors[APN_ERR_CTX_NOT_INITIALIZED]);
1495 return NULL;
1496 }
1497
1498 if (ctx->private_key_pass) {
1499 ret_value = ctx->private_key_pass;
1500 }
1501 return ret_value;
1502 }
1503
apn_mode(apn_ctx_ref ctx,apn_error_ref * error)1504 int8_t apn_mode(apn_ctx_ref ctx, apn_error_ref *error) {
1505 if (!ctx) {
1506 APN_SET_ERROR(error, APN_ERR_CTX_NOT_INITIALIZED | APN_ERR_CLASS_USER, __apn_errors[APN_ERR_CTX_NOT_INITIALIZED]);
1507 return -1;
1508 }
1509
1510 return ctx->mode;
1511 }
1512
apn_payload_expiry(apn_payload_ctx_ref payload_ctx,apn_error_ref * error)1513 int64_t apn_payload_expiry(apn_payload_ctx_ref payload_ctx, apn_error_ref *error) {
1514 if (!payload_ctx) {
1515 APN_SET_ERROR(error, APN_ERR_PAYLOAD_CTX_NOT_INITIALIZED | APN_ERR_CLASS_USER, __apn_errors[APN_ERR_PAYLOAD_CTX_NOT_INITIALIZED]);
1516 return -1;
1517 }
1518
1519 return payload_ctx->expiry;
1520 }
1521
apn_payload_copy(const apn_payload_ctx_ref payload_ctx,apn_error_ref * error)1522 apn_payload_ctx_ref apn_payload_copy(const apn_payload_ctx_ref payload_ctx, apn_error_ref *error) {
1523 apn_payload_ctx_ref _payload = NULL;
1524 uint16_t i = 0;
1525
1526 if (!payload_ctx) {
1527 APN_SET_ERROR(error, APN_ERR_PAYLOAD_CTX_NOT_INITIALIZED | APN_ERR_CLASS_USER, __apn_errors[APN_ERR_PAYLOAD_CTX_NOT_INITIALIZED]);
1528 return NULL;
1529 }
1530
1531 if (apn_payload_init(&_payload, error)) {
1532 return NULL;
1533 }
1534
1535 _payload->badge = payload_ctx->badge;
1536
1537 if (payload_ctx->sound) {
1538 _payload->sound = apn_strndup(payload_ctx->sound, strlen(payload_ctx->sound));
1539 if (_payload->sound == NULL) {
1540 APN_SET_ERROR(error, APN_ERR_NOMEM | APN_ERR_CLASS_INTERNAL, __apn_errors[APN_ERR_NOMEM]);
1541 return NULL;
1542 }
1543 }
1544
1545 if (payload_ctx->alert) {
1546 if (payload_ctx->alert->action_loc_key) {
1547 if ((_payload->alert->action_loc_key = apn_strndup(payload_ctx->alert->action_loc_key, strlen(payload_ctx->alert->action_loc_key))) == NULL) {
1548 APN_SET_ERROR(error, APN_ERR_NOMEM | APN_ERR_CLASS_INTERNAL, __apn_errors[APN_ERR_NOMEM]);
1549 return NULL;
1550 }
1551 }
1552 if (payload_ctx->alert->body) {
1553 if ((_payload->alert->body = apn_strndup(payload_ctx->alert->body, strlen(payload_ctx->alert->body))) == NULL) {
1554 APN_SET_ERROR(error, APN_ERR_NOMEM | APN_ERR_CLASS_INTERNAL, __apn_errors[APN_ERR_NOMEM]);
1555 return NULL;
1556 }
1557 }
1558 if (payload_ctx->alert->launch_image) {
1559
1560 if ((_payload->alert->launch_image = apn_strndup(payload_ctx->alert->launch_image, strlen(payload_ctx->alert->launch_image))) == NULL) {
1561 APN_SET_ERROR(error, APN_ERR_NOMEM | APN_ERR_CLASS_INTERNAL, __apn_errors[APN_ERR_NOMEM]);
1562 return NULL;
1563 }
1564 }
1565 if (payload_ctx->alert->loc_key) {
1566 if ((_payload->alert->loc_key = apn_strndup(payload_ctx->alert->loc_key, strlen(payload_ctx->alert->loc_key))) == NULL) {
1567 APN_SET_ERROR(error, APN_ERR_NOMEM | APN_ERR_CLASS_INTERNAL, __apn_errors[APN_ERR_NOMEM]);
1568 return NULL;
1569 }
1570 }
1571 if (payload_ctx->alert->__loc_args_count > 0 && payload_ctx->alert->loc_args) {
1572 _payload->alert->loc_args = (char **) malloc((payload_ctx->alert->__loc_args_count) * sizeof (char *));
1573 if (!_payload->alert->loc_args) {
1574 apn_payload_free(&_payload);
1575 APN_SET_ERROR(error, APN_ERR_NOMEM | APN_ERR_CLASS_INTERNAL, __apn_errors[APN_ERR_NOMEM]);
1576 return NULL;
1577 }
1578
1579 for (i = 0; i < payload_ctx->alert->__loc_args_count; i++) {
1580 _payload->alert->loc_args[i] = apn_strndup(payload_ctx->alert->loc_args[i], strlen(payload_ctx->alert->loc_args[i]));
1581
1582 if (_payload->alert->loc_args[i] == NULL) {
1583 APN_SET_ERROR(error, APN_ERR_NOMEM | APN_ERR_CLASS_INTERNAL, __apn_errors[APN_ERR_NOMEM]);
1584 return NULL;
1585 }
1586
1587 _payload->alert->__loc_args_count++;
1588 }
1589 }
1590 }
1591
1592 _payload->expiry = payload_ctx->expiry;
1593 _payload->priority = payload_ctx->priority;
1594
1595 _payload->tokens = __apn_tokens_array_copy(payload_ctx->tokens, payload_ctx->__tokens_count, error);
1596 if (_payload->tokens == NULL && __apn_is_error((*error))) {
1597 apn_payload_free(&_payload);
1598 return NULL;
1599 }
1600 _payload->__tokens_count = payload_ctx->__tokens_count;
1601
1602 if (payload_ctx->__custom_properties_count > 0 && payload_ctx->custom_properties) {
1603 uint8_t i = 0;
1604
1605 _payload->custom_properties = (apn_payload_custom_property_ref *) malloc(payload_ctx->__custom_properties_count * sizeof (apn_payload_custom_property_ref));
1606 if (!_payload->custom_properties) {
1607 apn_payload_free(&_payload);
1608 APN_SET_ERROR(error, APN_ERR_NOMEM | APN_ERR_CLASS_INTERNAL, __apn_errors[APN_ERR_NOMEM]);
1609 return NULL;
1610 }
1611 _payload->__custom_properties_count = 0;
1612 for (i = 0; i < payload_ctx->__custom_properties_count; i++) {
1613 apn_payload_custom_property_ref property = (apn_payload_custom_property_ref) malloc(sizeof (apn_payload_custom_property));
1614 if (!property) {
1615 apn_payload_free(&_payload);
1616 APN_SET_ERROR(error, APN_ERR_NOMEM | APN_ERR_CLASS_INTERNAL, __apn_errors[APN_ERR_NOMEM]);
1617 return NULL;
1618 }
1619
1620 property->value_type = (*(payload_ctx->custom_properties + i))->value_type;
1621 property->key = apn_strndup((*(payload_ctx->custom_properties + i))->key, strlen((*(payload_ctx->custom_properties + i))->key));
1622
1623 if (property->key == NULL) {
1624 APN_SET_ERROR(error, APN_ERR_NOMEM | APN_ERR_CLASS_INTERNAL, __apn_errors[APN_ERR_NOMEM]);
1625 return NULL;
1626 }
1627
1628 switch (property->value_type) {
1629 case APN_CUSTOM_PROPERTY_TYPE_BOOL:
1630 property->value.bool_value = (*(payload_ctx->custom_properties + i))->value.bool_value;
1631 break;
1632 case APN_CUSTOM_PROPERTY_TYPE_NUMERIC:
1633 property->value.numeric_value = (*(payload_ctx->custom_properties + i))->value.numeric_value;
1634 break;
1635 case APN_CUSTOM_PROPERTY_TYPE_DOUBLE:
1636 property->value.double_value = (*(payload_ctx->custom_properties + i))->value.double_value;
1637 break;
1638 case APN_CUSTOM_PROPERTY_TYPE_NULL:
1639 break;
1640 case APN_CUSTOM_PROPERTY_TYPE_STRING:
1641 {
1642 property->value.string_value.value = apn_strndup((*(payload_ctx->custom_properties + i))->value.string_value.value, strlen((*(payload_ctx->custom_properties + i))->value.string_value.value));
1643 if (property->value.string_value.value == NULL) {
1644 APN_SET_ERROR(error, APN_ERR_NOMEM | APN_ERR_CLASS_INTERNAL, __apn_errors[APN_ERR_NOMEM]);
1645 return NULL;
1646 }
1647 property->value.string_value.length = (*(payload_ctx->custom_properties + i))->value.string_value.length;
1648 }
1649 break;
1650 case APN_CUSTOM_PROPERTY_TYPE_ARRAY:
1651 {
1652 uint8_t j = 0;
1653 property->value.array_value.array = (char **) malloc((*(payload_ctx->custom_properties + i))->value.array_value.array_size * sizeof (char *));
1654 if (!property->value.array_value.array) {
1655 apn_payload_free(&_payload);
1656 __apn_payload_custom_property_free(&property);
1657 APN_SET_ERROR(error, APN_ERR_NOMEM | APN_ERR_CLASS_INTERNAL, __apn_errors[APN_ERR_NOMEM]);
1658 return NULL;
1659 }
1660 property->value.array_value.array_size = 0;
1661 for (j = 0; j < (*(payload_ctx->custom_properties + i))->value.array_value.array_size; j++) {
1662 char *array_item = apn_strndup((*(payload_ctx->custom_properties + i))->value.array_value.array[j], strlen((*(payload_ctx->custom_properties + i))->value.array_value.array[j]));
1663
1664 if (array_item == NULL) {
1665 APN_SET_ERROR(error, APN_ERR_NOMEM | APN_ERR_CLASS_INTERNAL, __apn_errors[APN_ERR_NOMEM]);
1666 return NULL;
1667 }
1668
1669 property->value.array_value.array[j] = array_item;
1670 property->value.array_value.array_size++;
1671 }
1672 }
1673 break;
1674 }
1675 _payload->custom_properties[_payload->__custom_properties_count] = property;
1676 _payload->__custom_properties_count++;
1677 }
1678 }
1679 return _payload;
1680 }
1681
apn_payload_init(apn_payload_ctx_ref * payload_ctx,apn_error_ref * error)1682 uint8_t apn_payload_init(apn_payload_ctx_ref *payload_ctx, apn_error_ref *error) {
1683 apn_payload_ctx_ref _payload = NULL;
1684
1685 if (!payload_ctx) {
1686 APN_SET_ERROR(error, APN_ERR_INVALID_ARGUMENT | APN_ERR_CLASS_USER, "invalid payload_ctx. Expected pointer to tointer to apn_payload_ctx structure, passed NULL");
1687 APN_RETURN_ERROR;
1688 }
1689 *payload_ctx = NULL;
1690 _payload = malloc(sizeof (apn_payload_ctx));
1691 if (!_payload) {
1692 APN_SET_ERROR(error, APN_ERR_NOMEM | APN_ERR_CLASS_INTERNAL, __apn_errors[APN_ERR_NOMEM]);
1693 APN_RETURN_ERROR;
1694 }
1695
1696 if (__apn_payload_alert_init(&_payload->alert, error)) {
1697 free(_payload);
1698 APN_SET_ERROR(error, APN_ERR_NOMEM | APN_ERR_CLASS_INTERNAL, __apn_errors[APN_ERR_NOMEM]);
1699 APN_RETURN_ERROR;
1700 }
1701
1702 _payload->badge = -1;
1703 _payload->sound = NULL;
1704 _payload->__custom_properties_count = 0;
1705 _payload->custom_properties = NULL;
1706 _payload->__tokens_count = 0;
1707 _payload->tokens = NULL;
1708 _payload->expiry = 0;
1709 _payload->content_available = 0;
1710 _payload->priority = APN_NOTIFICATION_PRIORITY_DEFAULT;
1711
1712 *payload_ctx = _payload;
1713
1714 APN_RETURN_SUCCESS;
1715 }
1716
apn_payload_free(apn_payload_ctx_ref * payload_ctx)1717 void apn_payload_free(apn_payload_ctx_ref *payload_ctx) {
1718 apn_payload_ctx_ref _payload_ctx = NULL;
1719 if (!payload_ctx || !(*payload_ctx)) {
1720 return;
1721 }
1722 _payload_ctx = *payload_ctx;
1723
1724 if (_payload_ctx->alert) {
1725 if (_payload_ctx->alert->action_loc_key) {
1726 free(_payload_ctx->alert->action_loc_key);
1727 }
1728 if (_payload_ctx->alert->body) {
1729 free(_payload_ctx->alert->body);
1730 }
1731 if (_payload_ctx->alert->launch_image) {
1732 free(_payload_ctx->alert->launch_image);
1733 }
1734 if (_payload_ctx->alert->loc_key) {
1735 free(_payload_ctx->alert->loc_key);
1736 }
1737
1738 if (_payload_ctx->alert->loc_args && _payload_ctx->alert->__loc_args_count > 0) {
1739 uint16_t i = 0;
1740 for (i = 0; i < _payload_ctx->alert->__loc_args_count; i++) {
1741 char *arg = *(_payload_ctx->alert->loc_args + i);
1742 free(arg);
1743 }
1744 free(_payload_ctx->alert->loc_args);
1745 }
1746 free(_payload_ctx->alert);
1747 }
1748
1749 if (_payload_ctx->sound) {
1750 free(_payload_ctx->sound);
1751 }
1752
1753 if (_payload_ctx->custom_properties && _payload_ctx->__custom_properties_count > 0) {
1754 uint8_t i = 0;
1755 for (i = 0; i < _payload_ctx->__custom_properties_count; i++) {
1756 __apn_payload_custom_property_free(_payload_ctx->custom_properties + i);
1757 }
1758 free(_payload_ctx->custom_properties);
1759 }
1760
1761 __apn_tokens_array_free(_payload_ctx->tokens, _payload_ctx->__tokens_count);
1762
1763 free(_payload_ctx);
1764 *payload_ctx = NULL;
1765 }
1766
1767 /* Setters */
1768
apn_payload_set_priority(apn_payload_ctx_ref payload_ctx,apn_notification_priority priority,apn_error_ref * error)1769 uint8_t apn_payload_set_priority(apn_payload_ctx_ref payload_ctx, apn_notification_priority priority, apn_error_ref *error) {
1770 if (!payload_ctx) {
1771 APN_SET_ERROR(error, APN_ERR_PAYLOAD_CTX_NOT_INITIALIZED | APN_ERR_CLASS_USER, __apn_errors[APN_ERR_PAYLOAD_CTX_NOT_INITIALIZED]);
1772 APN_RETURN_ERROR;
1773 }
1774 payload_ctx->priority = priority;
1775 APN_RETURN_SUCCESS;
1776 }
1777
apn_payload_set_expiry(apn_payload_ctx_ref payload_ctx,uint32_t expiry,apn_error_ref * error)1778 uint8_t apn_payload_set_expiry(apn_payload_ctx_ref payload_ctx, uint32_t expiry, apn_error_ref *error) {
1779 if (!payload_ctx) {
1780 APN_SET_ERROR(error, APN_ERR_PAYLOAD_CTX_NOT_INITIALIZED | APN_ERR_CLASS_USER, __apn_errors[APN_ERR_PAYLOAD_CTX_NOT_INITIALIZED]);
1781 APN_RETURN_ERROR;
1782 }
1783
1784 payload_ctx->expiry = expiry;
1785
1786 APN_RETURN_SUCCESS;
1787 }
1788
apn_payload_add_token(apn_payload_ctx_ref payload_ctx,const char * token,apn_error_ref * error)1789 uint8_t apn_payload_add_token(apn_payload_ctx_ref payload_ctx, const char *token, apn_error_ref *error) {
1790 uint8_t *binary_token = NULL;
1791 uint8_t **tokens = NULL;
1792
1793 if (!payload_ctx) {
1794 APN_SET_ERROR(error, APN_ERR_PAYLOAD_CTX_NOT_INITIALIZED | APN_ERR_CLASS_USER, __apn_errors[APN_ERR_PAYLOAD_CTX_NOT_INITIALIZED]);
1795 APN_RETURN_ERROR;
1796 }
1797
1798 if (payload_ctx->__tokens_count >= UINT32_MAX) {
1799 APN_SET_ERROR(error, APN_ERR_TOKEN_TOO_MANY | APN_ERR_CLASS_USER, __apn_errors[APN_ERR_TOKEN_TOO_MANY]);
1800 APN_RETURN_ERROR;
1801 }
1802
1803 if (!token) {
1804 APN_SET_ERROR(error, APN_ERR_INVALID_ARGUMENT | APN_ERR_CLASS_USER, "invalid value of token. Expected string, passed NULL");
1805 APN_RETURN_ERROR;
1806 }
1807
1808 if (!__apn_check_hex_token(token)) {
1809 APN_SET_ERROR(error, APN_ERR_TOKEN_INVALID | APN_ERR_CLASS_USER, __apn_errors[APN_ERR_TOKEN_INVALID]);
1810 APN_RETURN_ERROR;
1811 }
1812
1813 tokens = (uint8_t **) __apn_realloc(payload_ctx->tokens, (payload_ctx->__tokens_count + 1) * sizeof(uint8_t *));
1814 if (!tokens) {
1815 APN_SET_ERROR(error, APN_ERR_NOMEM | APN_ERR_CLASS_INTERNAL, __apn_errors[APN_ERR_NOMEM]);
1816 APN_RETURN_ERROR;
1817 }
1818 payload_ctx->tokens = tokens;
1819
1820 if (!(binary_token = __token_hex_to_binary(token))) {
1821 APN_SET_ERROR(error, APN_ERR_NOMEM | APN_ERR_CLASS_INTERNAL, __apn_errors[APN_ERR_NOMEM]);
1822 APN_RETURN_ERROR;
1823 }
1824
1825 payload_ctx->tokens[payload_ctx->__tokens_count] = binary_token;
1826 payload_ctx->__tokens_count++;
1827
1828 APN_RETURN_SUCCESS;
1829 }
1830
apn_payload_set_badge(apn_payload_ctx_ref payload_ctx,int32_t badge,apn_error_ref * error)1831 uint8_t apn_payload_set_badge(apn_payload_ctx_ref payload_ctx, int32_t badge, apn_error_ref *error) {
1832 if (!payload_ctx) {
1833 APN_SET_ERROR(error, APN_ERR_PAYLOAD_CTX_NOT_INITIALIZED | APN_ERR_CLASS_USER, __apn_errors[APN_ERR_PAYLOAD_CTX_NOT_INITIALIZED]);
1834 APN_RETURN_ERROR;
1835 }
1836 if (badge < 0 || badge > UINT16_MAX) {
1837 APN_SET_ERROR(error, APN_ERR_PAYLOAD_BADGE_INVALID_VALUE | APN_ERR_CLASS_USER, __apn_errors[APN_ERR_PAYLOAD_BADGE_INVALID_VALUE]);
1838 APN_RETURN_ERROR;
1839 }
1840
1841 payload_ctx->badge = badge;
1842 APN_RETURN_SUCCESS;
1843 }
1844
apn_payload_set_sound(apn_payload_ctx_ref payload_ctx,const char * sound,apn_error_ref * error)1845 uint8_t apn_payload_set_sound(apn_payload_ctx_ref payload_ctx, const char *sound, apn_error_ref *error) {
1846 if (!payload_ctx) {
1847 APN_SET_ERROR(error, APN_ERR_PAYLOAD_CTX_NOT_INITIALIZED | APN_ERR_CLASS_USER, __apn_errors[APN_ERR_PAYLOAD_CTX_NOT_INITIALIZED]);
1848 APN_RETURN_ERROR;
1849 }
1850 if (payload_ctx->sound) {
1851 apn_strfree(&payload_ctx->sound);
1852 }
1853 if (sound && strlen(sound)) {
1854 if ((payload_ctx->sound = apn_strndup(sound, strlen(sound))) == NULL) {
1855 APN_SET_ERROR(error, APN_ERR_NOMEM | APN_ERR_CLASS_INTERNAL, __apn_errors[APN_ERR_NOMEM]);
1856 APN_RETURN_ERROR;
1857 }
1858 }
1859 APN_RETURN_SUCCESS;
1860 }
1861
apn_payload_set_content_available(apn_payload_ctx_ref payload_ctx,uint8_t content_available,apn_error_ref * error)1862 uint8_t apn_payload_set_content_available(apn_payload_ctx_ref payload_ctx, uint8_t content_available, apn_error_ref *error) {
1863 if (!payload_ctx) {
1864 APN_SET_ERROR(error, APN_ERR_PAYLOAD_CTX_NOT_INITIALIZED | APN_ERR_CLASS_USER, __apn_errors[APN_ERR_PAYLOAD_CTX_NOT_INITIALIZED]);
1865 APN_RETURN_ERROR;
1866 }
1867 payload_ctx->content_available = (content_available == 1) ? 1 : 0;
1868 APN_RETURN_SUCCESS;
1869 }
1870
apn_payload_set_body(apn_payload_ctx_ref payload_ctx,const char * body,apn_error_ref * error)1871 uint8_t apn_payload_set_body(apn_payload_ctx_ref payload_ctx, const char *body, apn_error_ref *error) {
1872 if (!payload_ctx) {
1873 APN_SET_ERROR(error, APN_ERR_PAYLOAD_CTX_NOT_INITIALIZED | APN_ERR_CLASS_USER, __apn_errors[APN_ERR_PAYLOAD_CTX_NOT_INITIALIZED]);
1874 APN_RETURN_ERROR;
1875 }
1876 if (payload_ctx->alert->body) {
1877 apn_strfree(&payload_ctx->alert->body);
1878 }
1879 if (body && strlen(body) > 0) {
1880 if (!apn_string_is_utf8(body)) {
1881 APN_SET_ERROR(error, APN_ERR_INVALID_ARGUMENT | APN_ERR_CLASS_USER, "body contains non-utf8 symbols");
1882 APN_RETURN_ERROR;
1883 }
1884
1885 if ((payload_ctx->alert->body = apn_strndup(body, strlen(body))) == NULL) {
1886 APN_SET_ERROR(error, APN_ERR_NOMEM | APN_ERR_CLASS_INTERNAL, __apn_errors[APN_ERR_NOMEM]);
1887 APN_RETURN_ERROR;
1888 }
1889 }
1890 APN_RETURN_SUCCESS;
1891 }
1892
apn_payload_set_localized_action_key(apn_payload_ctx_ref payload_ctx,const char * key,apn_error_ref * error)1893 uint8_t apn_payload_set_localized_action_key(apn_payload_ctx_ref payload_ctx, const char *key, apn_error_ref *error) {
1894 if (!payload_ctx) {
1895 APN_SET_ERROR(error, APN_ERR_PAYLOAD_CTX_NOT_INITIALIZED | APN_ERR_CLASS_USER, __apn_errors[APN_ERR_PAYLOAD_CTX_NOT_INITIALIZED]);
1896 APN_RETURN_ERROR;
1897 }
1898 if (payload_ctx->alert->action_loc_key) {
1899 apn_strfree(&payload_ctx->alert->action_loc_key);
1900 }
1901 if (key && strlen(key) > 0) {
1902 if ((payload_ctx->alert->action_loc_key = apn_strndup(key, strlen(key))) == NULL) {
1903 APN_SET_ERROR(error, APN_ERR_NOMEM | APN_ERR_CLASS_INTERNAL, __apn_errors[APN_ERR_NOMEM]);
1904 APN_RETURN_ERROR;
1905 }
1906 }
1907 APN_RETURN_SUCCESS;
1908 }
1909
apn_payload_set_launch_image(apn_payload_ctx_ref payload_ctx,const char * image,apn_error_ref * error)1910 uint8_t apn_payload_set_launch_image(apn_payload_ctx_ref payload_ctx, const char *image, apn_error_ref *error) {
1911 if (!payload_ctx) {
1912 APN_SET_ERROR(error, APN_ERR_PAYLOAD_CTX_NOT_INITIALIZED | APN_ERR_CLASS_USER, __apn_errors[APN_ERR_PAYLOAD_CTX_NOT_INITIALIZED]);
1913 APN_RETURN_ERROR;
1914 }
1915 if (payload_ctx->alert->action_loc_key) {
1916 apn_strfree(&payload_ctx->alert->action_loc_key);
1917 }
1918 if (image && strlen(image)) {
1919 if ((payload_ctx->alert->launch_image = apn_strndup(image, strlen(image))) == NULL) {
1920 APN_SET_ERROR(error, APN_ERR_NOMEM | APN_ERR_CLASS_INTERNAL, __apn_errors[APN_ERR_NOMEM]);
1921 APN_RETURN_ERROR;
1922 }
1923 }
1924 APN_RETURN_SUCCESS;
1925 }
1926
apn_payload_set_localized_key(apn_payload_ctx_ref payload_ctx,const char * key,char ** args,uint16_t args_count,apn_error_ref * error)1927 uint8_t apn_payload_set_localized_key(apn_payload_ctx_ref payload_ctx, const char *key, char **args, uint16_t args_count, apn_error_ref *error) {
1928 char *arg = NULL;
1929 uint16_t i = 0;
1930 uint16_t args_i = 0;
1931
1932 if (!payload_ctx) {
1933 APN_SET_ERROR(error, APN_ERR_PAYLOAD_CTX_NOT_INITIALIZED | APN_ERR_CLASS_USER, __apn_errors[APN_ERR_PAYLOAD_CTX_NOT_INITIALIZED]);
1934 APN_RETURN_ERROR;
1935 }
1936 if (payload_ctx->alert->loc_key) {
1937 apn_strfree(&payload_ctx->alert->loc_key);
1938
1939 if (payload_ctx->alert->loc_args && payload_ctx->alert->__loc_args_count) {
1940 for (i = 0; i < payload_ctx->alert->__loc_args_count; i++) {
1941 arg = *(payload_ctx->alert->loc_args + i);
1942 free(arg);
1943 }
1944 free(payload_ctx->alert->loc_args);
1945 payload_ctx->alert->loc_args = NULL;
1946 }
1947 }
1948
1949 if (key && strlen(key) > 0) {
1950 payload_ctx->alert->loc_key = apn_strndup(key, strlen(key));
1951
1952 if (args && args_count > 0) {
1953 payload_ctx->alert->loc_args = (char **) malloc((args_count) * sizeof (char *));
1954
1955 if (!payload_ctx->alert->loc_args) {
1956 APN_SET_ERROR(error, APN_ERR_NOMEM | APN_ERR_CLASS_INTERNAL, __apn_errors[APN_ERR_NOMEM]);
1957 APN_RETURN_ERROR;
1958 }
1959
1960 for (args_i = 0; args_i < args_count; args_i++) {
1961 if ((payload_ctx->alert->loc_args[args_i] = apn_strndup(args[args_i], strlen(args[args_i]))) == NULL) {
1962 APN_SET_ERROR(error, APN_ERR_NOMEM | APN_ERR_CLASS_INTERNAL, __apn_errors[APN_ERR_NOMEM]);
1963 APN_RETURN_ERROR;
1964 }
1965
1966 payload_ctx->alert->__loc_args_count++;
1967 }
1968 }
1969 }
1970 APN_RETURN_SUCCESS;
1971 }
1972
apn_payload_add_custom_property_integer(apn_payload_ctx_ref payload_ctx,const char * property_key,int64_t property_value,apn_error_ref * error)1973 uint8_t apn_payload_add_custom_property_integer(apn_payload_ctx_ref payload_ctx, const char *property_key,
1974 int64_t property_value,
1975 apn_error_ref *error) {
1976
1977 apn_payload_custom_property_ref property = NULL;
1978
1979 if (__apn_payload_custom_property_init(payload_ctx, property_key, error)) {
1980 APN_RETURN_ERROR;
1981 }
1982
1983 property = malloc(sizeof (apn_payload_custom_property));
1984
1985 if (!property) {
1986 APN_SET_ERROR(error, APN_ERR_NOMEM | APN_ERR_CLASS_INTERNAL, __apn_errors[APN_ERR_NOMEM]);
1987 APN_RETURN_ERROR;
1988 }
1989
1990 if ((property->key = apn_strndup(property_key, strlen(property_key))) == NULL) {
1991 APN_SET_ERROR(error, APN_ERR_NOMEM | APN_ERR_CLASS_INTERNAL, __apn_errors[APN_ERR_NOMEM]);
1992 APN_RETURN_ERROR;
1993 }
1994
1995 property->value_type = APN_CUSTOM_PROPERTY_TYPE_NUMERIC;
1996 property->value.numeric_value = property_value;
1997 payload_ctx->custom_properties[payload_ctx->__custom_properties_count] = property;
1998 payload_ctx->__custom_properties_count++;
1999
2000 APN_RETURN_SUCCESS;
2001 }
2002
apn_payload_add_custom_property_double(apn_payload_ctx_ref payload_ctx,const char * property_key,double property_value,apn_error_ref * error)2003 uint8_t apn_payload_add_custom_property_double(apn_payload_ctx_ref payload_ctx, const char *property_key,
2004 double property_value,
2005 apn_error_ref *error) {
2006
2007 apn_payload_custom_property_ref property = NULL;
2008
2009 if (__apn_payload_custom_property_init(payload_ctx, property_key, error)) {
2010 APN_RETURN_ERROR;
2011 }
2012
2013 property = malloc(sizeof (apn_payload_custom_property));
2014
2015 if (!property) {
2016 APN_SET_ERROR(error, APN_ERR_NOMEM | APN_ERR_CLASS_INTERNAL, __apn_errors[APN_ERR_NOMEM]);
2017 APN_RETURN_ERROR;
2018 }
2019
2020 property->value_type = APN_CUSTOM_PROPERTY_TYPE_DOUBLE;
2021
2022 if ((property->key = apn_strndup(property_key, strlen(property_key))) == NULL) {
2023 APN_SET_ERROR(error, APN_ERR_NOMEM | APN_ERR_CLASS_INTERNAL, __apn_errors[APN_ERR_NOMEM]);
2024 APN_RETURN_ERROR;
2025 }
2026
2027 property->value.double_value = property_value;
2028
2029 payload_ctx->custom_properties[payload_ctx->__custom_properties_count] = property;
2030 payload_ctx->__custom_properties_count++;
2031
2032 APN_RETURN_SUCCESS;
2033 }
2034
apn_payload_add_custom_property_bool(apn_payload_ctx_ref payload_ctx,const char * property_key,unsigned char property_value,apn_error_ref * error)2035 uint8_t apn_payload_add_custom_property_bool(apn_payload_ctx_ref payload_ctx, const char *property_key,
2036 unsigned char property_value,
2037 apn_error_ref *error) {
2038
2039 apn_payload_custom_property_ref property = NULL;
2040
2041 if (__apn_payload_custom_property_init(payload_ctx, property_key, error)) {
2042 APN_RETURN_ERROR;
2043 }
2044
2045 property = malloc(sizeof (apn_payload_custom_property));
2046
2047 if (!property) {
2048 APN_SET_ERROR(error, APN_ERR_NOMEM | APN_ERR_CLASS_INTERNAL, __apn_errors[APN_ERR_NOMEM]);
2049 APN_RETURN_ERROR;
2050 }
2051
2052 property->value_type = APN_CUSTOM_PROPERTY_TYPE_BOOL;
2053
2054 if ((property->key = apn_strndup(property_key, strlen(property_key))) == NULL) {
2055 APN_SET_ERROR(error, APN_ERR_NOMEM | APN_ERR_CLASS_INTERNAL, __apn_errors[APN_ERR_NOMEM]);
2056 APN_RETURN_ERROR;
2057 }
2058
2059 property->value.bool_value = (property_value == 0) ? 0 : 1;
2060
2061 payload_ctx->custom_properties[payload_ctx->__custom_properties_count] = property;
2062 payload_ctx->__custom_properties_count++;
2063
2064 APN_RETURN_SUCCESS;
2065 }
2066
apn_payload_add_custom_property_null(apn_payload_ctx_ref payload_ctx,const char * property_key,apn_error_ref * error)2067 uint8_t apn_payload_add_custom_property_null(apn_payload_ctx_ref payload_ctx, const char *property_key, apn_error_ref *error) {
2068 apn_payload_custom_property_ref property = NULL;
2069
2070 if (__apn_payload_custom_property_init(payload_ctx, property_key, error)) {
2071 APN_RETURN_ERROR;
2072 }
2073
2074 property = malloc(sizeof (apn_payload_custom_property));
2075
2076 if (!property) {
2077 APN_SET_ERROR(error, APN_ERR_NOMEM | APN_ERR_CLASS_INTERNAL, __apn_errors[APN_ERR_NOMEM]);
2078 APN_RETURN_ERROR;
2079 }
2080
2081 property->value_type = APN_CUSTOM_PROPERTY_TYPE_NULL;
2082
2083 if ((property->key = apn_strndup(property_key, strlen(property_key))) == NULL) {
2084 APN_SET_ERROR(error, APN_ERR_NOMEM | APN_ERR_CLASS_INTERNAL, __apn_errors[APN_ERR_NOMEM]);
2085 APN_RETURN_ERROR;
2086 }
2087
2088 property->value.string_value.value = NULL;
2089 property->value.string_value.length = 0;
2090
2091 payload_ctx->custom_properties[payload_ctx->__custom_properties_count] = property;
2092 payload_ctx->__custom_properties_count++;
2093
2094 APN_RETURN_SUCCESS;
2095 }
2096
apn_payload_add_custom_property_string(apn_payload_ctx_ref payload_ctx,const char * property_key,const char * property_value,apn_error_ref * error)2097 uint8_t apn_payload_add_custom_property_string(apn_payload_ctx_ref payload_ctx, const char *property_key,
2098 const char *property_value,
2099 apn_error_ref *error) {
2100
2101 apn_payload_custom_property_ref property = NULL;
2102
2103 if (!property_value) {
2104 APN_SET_ERROR(error, APN_ERR_INVALID_ARGUMENT | APN_ERR_CLASS_USER, "value of custom property is NULL");
2105 APN_RETURN_ERROR;
2106 }
2107
2108 if (!apn_string_is_utf8(property_value)) {
2109 APN_SET_ERROR(error, APN_ERR_INVALID_ARGUMENT | APN_ERR_CLASS_USER, "value contains non-utf8 symbols");
2110 APN_RETURN_ERROR;
2111 }
2112
2113 if (__apn_payload_custom_property_init(payload_ctx, property_key, error)) {
2114 APN_RETURN_ERROR;
2115 }
2116
2117 property = malloc(sizeof (apn_payload_custom_property));
2118 if (!property) {
2119 APN_SET_ERROR(error, APN_ERR_NOMEM | APN_ERR_CLASS_INTERNAL, __apn_errors[APN_ERR_NOMEM]);
2120 APN_RETURN_ERROR;
2121 }
2122
2123 property->value_type = APN_CUSTOM_PROPERTY_TYPE_STRING;
2124
2125 if ((property->key = apn_strndup(property_key, strlen(property_key))) == NULL) {
2126 APN_SET_ERROR(error, APN_ERR_NOMEM | APN_ERR_CLASS_INTERNAL, __apn_errors[APN_ERR_NOMEM]);
2127 APN_RETURN_ERROR;
2128 }
2129
2130 if ((property->value.string_value.value = apn_strndup(property_value, strlen(property_value))) == NULL) {
2131 APN_SET_ERROR(error, APN_ERR_NOMEM | APN_ERR_CLASS_INTERNAL, __apn_errors[APN_ERR_NOMEM]);
2132 APN_RETURN_ERROR;
2133 }
2134
2135 property->value.string_value.length = strlen(property_value);
2136
2137 payload_ctx->custom_properties[payload_ctx->__custom_properties_count] = property;
2138 payload_ctx->__custom_properties_count++;
2139
2140 APN_RETURN_SUCCESS;
2141 }
2142
apn_payload_add_custom_property_array(apn_payload_ctx_ref payload_ctx,const char * property_key,const char ** array,uint8_t array_size,apn_error_ref * error)2143 uint8_t apn_payload_add_custom_property_array(apn_payload_ctx_ref payload_ctx, const char *property_key,
2144 const char **array, uint8_t array_size,
2145 apn_error_ref *error) {
2146
2147 char **_array = NULL;
2148 apn_payload_custom_property_ref property = NULL;
2149 uint8_t i = 0;
2150 uint8_t _array_size = 0;
2151
2152 if (!array) {
2153 APN_SET_ERROR(error, APN_ERR_INVALID_ARGUMENT | APN_ERR_CLASS_USER, "value of custom property is NULL");
2154 APN_RETURN_ERROR;
2155 }
2156
2157 if (__apn_payload_custom_property_init(payload_ctx, property_key, error)) {
2158 APN_RETURN_ERROR;
2159 }
2160
2161 property = malloc(sizeof (apn_payload_custom_property));
2162 if (!property) {
2163 APN_SET_ERROR(error, APN_ERR_NOMEM | APN_ERR_CLASS_INTERNAL, __apn_errors[APN_ERR_NOMEM]);
2164 APN_RETURN_ERROR;
2165 }
2166
2167 property->value_type = APN_CUSTOM_PROPERTY_TYPE_ARRAY;
2168
2169 if ((property->key = apn_strndup(property_key, strlen(property_key))) == NULL) {
2170 APN_SET_ERROR(error, APN_ERR_NOMEM | APN_ERR_CLASS_INTERNAL, __apn_errors[APN_ERR_NOMEM]);
2171 APN_RETURN_ERROR;
2172 }
2173
2174 if (array_size) {
2175 _array = (char **) malloc(sizeof (char *) * array_size);
2176 if (!_array) {
2177 APN_SET_ERROR(error, APN_ERR_NOMEM, __apn_errors[APN_ERR_NOMEM]);
2178 APN_RETURN_ERROR;
2179 }
2180
2181 _array_size = (array_size > 6) ? 6 : array_size;
2182 for (i = 0; i < _array_size; i++) {
2183 if ((_array[i] = apn_strndup(_array[i], strlen(_array[i]))) == NULL) {
2184 APN_SET_ERROR(error, APN_ERR_NOMEM | APN_ERR_CLASS_INTERNAL, __apn_errors[APN_ERR_NOMEM]);
2185 APN_RETURN_ERROR;
2186 }
2187 }
2188 property->value.array_value.array = _array;
2189 property->value.array_value.array_size = _array_size;
2190 }
2191
2192 payload_ctx->custom_properties[payload_ctx->__custom_properties_count] = property;
2193 payload_ctx->__custom_properties_count++;
2194
2195 APN_RETURN_SUCCESS;
2196 }
2197
2198 /** Getters */
2199
apn_payload_content_available(const apn_payload_ctx_ref payload_ctx,apn_error_ref * error)2200 int8_t apn_payload_content_available(const apn_payload_ctx_ref payload_ctx, apn_error_ref *error) {
2201 if (!payload_ctx) {
2202 APN_SET_ERROR(error, APN_ERR_PAYLOAD_CTX_NOT_INITIALIZED | APN_ERR_CLASS_USER, __apn_errors[APN_ERR_PAYLOAD_CTX_NOT_INITIALIZED]);
2203 return -1;
2204 }
2205 return payload_ctx->content_available;
2206 }
2207
apn_payload_badge(const apn_payload_ctx_ref payload_ctx,apn_error_ref * error)2208 int32_t apn_payload_badge(const apn_payload_ctx_ref payload_ctx, apn_error_ref *error) {
2209 if (!payload_ctx) {
2210 APN_SET_ERROR(error, APN_ERR_PAYLOAD_CTX_NOT_INITIALIZED | APN_ERR_CLASS_USER, __apn_errors[APN_ERR_PAYLOAD_CTX_NOT_INITIALIZED]);
2211 return -1;
2212 }
2213 return payload_ctx->badge;
2214 }
2215
apn_payload_sound(const apn_payload_ctx_ref payload_ctx,apn_error_ref * error)2216 const char *apn_payload_sound(const apn_payload_ctx_ref payload_ctx, apn_error_ref *error) {
2217 char *ret_value = NULL;
2218
2219 if (!payload_ctx) {
2220 APN_SET_ERROR(error, APN_ERR_PAYLOAD_CTX_NOT_INITIALIZED | APN_ERR_CLASS_USER, __apn_errors[APN_ERR_PAYLOAD_CTX_NOT_INITIALIZED]);
2221 return NULL;
2222 }
2223
2224 if (payload_ctx->sound) {
2225 ret_value = payload_ctx->sound;
2226 }
2227 return ret_value;
2228 }
2229
apn_payload_launch_image(const apn_payload_ctx_ref payload_ctx,apn_error_ref * error)2230 const char *apn_payload_launch_image(const apn_payload_ctx_ref payload_ctx, apn_error_ref *error) {
2231 char *ret_value = NULL;
2232
2233 if (!payload_ctx) {
2234 APN_SET_ERROR(error, APN_ERR_PAYLOAD_CTX_NOT_INITIALIZED | APN_ERR_CLASS_USER, __apn_errors[APN_ERR_PAYLOAD_CTX_NOT_INITIALIZED]);
2235 return NULL;
2236 }
2237
2238 if (payload_ctx->alert->launch_image) {
2239 ret_value = payload_ctx->alert->launch_image;
2240 }
2241 return ret_value;
2242 }
2243
apn_payload_localized_action_key(const apn_payload_ctx_ref payload_ctx,apn_error_ref * error)2244 const char *apn_payload_localized_action_key(const apn_payload_ctx_ref payload_ctx, apn_error_ref *error) {
2245 char *ret_value = NULL;
2246
2247 if (!payload_ctx) {
2248 APN_SET_ERROR(error, APN_ERR_PAYLOAD_CTX_NOT_INITIALIZED | APN_ERR_CLASS_USER, __apn_errors[APN_ERR_PAYLOAD_CTX_NOT_INITIALIZED]);
2249 return NULL;
2250 }
2251
2252 if (payload_ctx->alert->action_loc_key) {
2253 ret_value = payload_ctx->alert->action_loc_key;
2254 }
2255 return ret_value;
2256 }
2257
apn_payload_body(const apn_payload_ctx_ref payload_ctx,apn_error_ref * error)2258 const char *apn_payload_body(const apn_payload_ctx_ref payload_ctx, apn_error_ref *error) {
2259 char *ret_value = NULL;
2260
2261 if (!payload_ctx) {
2262 APN_SET_ERROR(error, APN_ERR_PAYLOAD_CTX_NOT_INITIALIZED | APN_ERR_CLASS_USER, __apn_errors[APN_ERR_PAYLOAD_CTX_NOT_INITIALIZED]);
2263 return NULL;
2264 }
2265
2266 if (payload_ctx->alert->body) {
2267 ret_value = payload_ctx->alert->body;
2268 }
2269 return ret_value;
2270 }
2271
apn_payload_localized_key(const apn_payload_ctx_ref payload_ctx,apn_error_ref * error)2272 const char *apn_payload_localized_key(const apn_payload_ctx_ref payload_ctx, apn_error_ref *error) {
2273 char *ret_value = NULL;
2274
2275 if (!payload_ctx) {
2276 APN_SET_ERROR(error, APN_ERR_PAYLOAD_CTX_NOT_INITIALIZED | APN_ERR_CLASS_USER, __apn_errors[APN_ERR_PAYLOAD_CTX_NOT_INITIALIZED]);
2277 return NULL;
2278 }
2279
2280 if (payload_ctx->alert->loc_key) {
2281 ret_value = payload_ctx->alert->loc_key;
2282 }
2283 return ret_value;
2284 }
2285
apn_payload_localized_key_args(const apn_payload_ctx_ref payload_ctx,char *** args,apn_error_ref * error)2286 uint16_t apn_payload_localized_key_args(const apn_payload_ctx_ref payload_ctx, char ***args, apn_error_ref *error) {
2287 *args = NULL;
2288
2289 if (!payload_ctx) {
2290 APN_SET_ERROR(error, APN_ERR_PAYLOAD_CTX_NOT_INITIALIZED | APN_ERR_CLASS_USER, __apn_errors[APN_ERR_PAYLOAD_CTX_NOT_INITIALIZED]);
2291 return 0;
2292 }
2293 if (payload_ctx->alert->loc_args && payload_ctx->alert->__loc_args_count) {
2294 *args = payload_ctx->alert->loc_args;
2295 return payload_ctx->alert->__loc_args_count;
2296 }
2297 return 0;
2298 }
2299
apn_version()2300 uint32_t apn_version() {
2301 return APN_VERSION_NUM;
2302 }
2303
apn_version_string()2304 const char * apn_version_string() {
2305 return APN_VERSION_STRING;
2306 }
2307
apn_feedback_tokens_array_free(char ** tokens_array,uint32_t tokens_array_count)2308 void apn_feedback_tokens_array_free(char **tokens_array, uint32_t tokens_array_count) {
2309 uint32_t i = 0;
2310
2311 if (tokens_array != NULL && tokens_array_count > 0) {
2312 for (i = 0; i < tokens_array_count; i++) {
2313 char *token = *(tokens_array + i);
2314 free(token);
2315 }
2316 free(tokens_array);
2317 }
2318 }
2319
apn_error_free(apn_error_ref * error)2320 void apn_error_free(apn_error_ref *error) {
2321 apn_error_ref _error = NULL;
2322 if (error) {
2323 _error = *error;
2324 if (!_error) {
2325 return;
2326 }
2327 if (_error->message) {
2328 free(_error->message);
2329 }
2330 if (_error->invalid_token) {
2331 free(_error->invalid_token);
2332 }
2333 free(_error);
2334 *error = NULL;
2335 }
2336 }
2337
apn_error_message(const apn_error_ref error)2338 const char *apn_error_message(const apn_error_ref error) {
2339 if (!error) {
2340 return NULL;
2341 }
2342 return error->message;
2343 }
2344
apn_error_invalid_token(const apn_error_ref error)2345 const char *apn_error_invalid_token(const apn_error_ref error) {
2346 if (!error) {
2347 return NULL;
2348 }
2349 return error->invalid_token;
2350 }
2351
apn_error_code(const apn_error_ref error)2352 int32_t apn_error_code(const apn_error_ref error) {
2353 if (!error) {
2354 return 0;
2355 }
2356 return error->code;
2357 }
2358