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(&notification_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