libpushover.c 7.26 KB
Newer Older
Shawn Webb's avatar
Shawn Webb committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
/*-
 * Copyright (c) 2020 HardenedBSD Foundation Corp.
 * Author: Shawn Webb <shawn.webb@hardenedbsd.org>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

32
33
34
#include <sys/types.h>
#include <sys/sbuf.h>

Shawn Webb's avatar
Shawn Webb committed
35
36
37
#include "libpushover.h"

static char *msg_to_str(pushover_ctx_t *, pushover_message_t *, CURL *);
Shawn Webb's avatar
Shawn Webb committed
38
static size_t pushover_curl_write_data(void *, size_t, size_t, void *);
Shawn Webb's avatar
Shawn Webb committed
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59

EXPORTED_SYM
pushover_ctx_t *
pushover_init_ctx(const char *token)
{
	pushover_ctx_t *res;

	res = calloc(1, sizeof(*res));
	if (res == NULL)
		return (NULL);

	res->psh_uri = strdup(PUSHOVER_URI);
	if (res->psh_uri == NULL) {
		free(res);
		res = NULL;
		goto out;
	}

	if (token != NULL)
		res->psh_token = strdup(token);

Shawn Webb's avatar
Shawn Webb committed
60
61
	res->psh_version = LIBPUSHOVER_VERSION;

Shawn Webb's avatar
Shawn Webb committed
62
63
64
65
out:
	return (res);
}

Shawn Webb's avatar
Shawn Webb committed
66
67
68
69
70
71
72
73
74
75
76
77
78
EXPORTED_SYM
void
pushover_free_ctx(pushover_ctx_t **ctx)
{
	pushover_ctx_t *ctxp;

	if (ctx == NULL || *ctx == NULL)
		return;

	ctxp = *ctx;

	free(ctxp->psh_uri);
	free(ctxp->psh_token);
Shawn Webb's avatar
Shawn Webb committed
79
	memset(ctxp, 0, sizeof(*ctxp));
Shawn Webb's avatar
Shawn Webb committed
80
81
82
83
	free(ctxp);
	*ctx = NULL;
}

Shawn Webb's avatar
Shawn Webb committed
84
85
86
87
88
89
90
EXPORTED_SYM
bool
pushover_set_uri(pushover_ctx_t *ctx, const char *uri)
{

	assert(ctx != NULL);
	assert(uri != NULL);
Shawn Webb's avatar
Shawn Webb committed
91
	assert(ctx->psh_uri == NULL);
Shawn Webb's avatar
Shawn Webb committed
92
93
94
95
96

	ctx->psh_uri = strdup(uri);
	return (ctx->psh_uri != NULL);
}

97
98
99
100
101
102
103
EXPORTED_SYM
bool
pushover_set_token(pushover_ctx_t *ctx, const char *token)
{

	assert(ctx != NULL);
	assert(token != NULL);
Shawn Webb's avatar
Shawn Webb committed
104
	assert(ctx->psh_token == NULL);
105
106
107
108
109

	ctx->psh_token = strdup(token);
	return (ctx->psh_token != NULL);
}

Shawn Webb's avatar
Shawn Webb committed
110
111
112
113
EXPORTED_SYM
pushover_message_t *
pushover_init_message(pushover_message_t *msg)
{
114
	uint64_t flags;
Shawn Webb's avatar
Shawn Webb committed
115

116
117
118
	flags = 0;

	if (msg == NULL) {
Shawn Webb's avatar
Shawn Webb committed
119
		msg = calloc(1, sizeof(*msg));
120
121
		flags |= PUSHOVER_FLAGS_ALLOC;
	} else {
Shawn Webb's avatar
Shawn Webb committed
122
		memset(msg, 0, sizeof(*msg));
123
	}
Shawn Webb's avatar
Shawn Webb committed
124
125
126
127

	if (msg == NULL)
		return (NULL);

Shawn Webb's avatar
Shawn Webb committed
128
129
	msg->psh_flags = flags;

Shawn Webb's avatar
Shawn Webb committed
130
131
132
	return (msg);
}

133
134
135
136
137
EXPORTED_SYM
void
pushover_free_message(pushover_message_t **msg)
{
	pushover_message_t *msgp;
Shawn Webb's avatar
Shawn Webb committed
138
	uint64_t flags;
139
140
141
142
143

	if (msg == NULL || *msg == NULL)
		return;

	msgp = *msg;
Shawn Webb's avatar
Shawn Webb committed
144
	flags = msgp->psh_flags;
145

146
	free(msgp->psh_dest);
147
148
149
	free(msgp->psh_msg);
	free(msgp->psh_title);
	free(msgp->psh_device);
Shawn Webb's avatar
Shawn Webb committed
150
	memset(msgp, 0, sizeof(*msgp));
151

Shawn Webb's avatar
Shawn Webb committed
152
	if (flags & PUSHOVER_FLAGS_ALLOC) {
153
154
155
156
157
		free(msgp);
		*msg = NULL;
	}
}

Shawn Webb's avatar
Shawn Webb committed
158
159
160
161
162
163
164
EXPORTED_SYM
bool
pushover_message_set_msg(pushover_message_t *msg, char *data)
{

	assert(msg != NULL);
	assert(data != NULL);
Shawn Webb's avatar
Shawn Webb committed
165
	assert(msg->psh_msg == NULL);
Shawn Webb's avatar
Shawn Webb committed
166
167
168
169
170
171
172

	msg->psh_msg = strdup(data);
	return (msg->psh_msg != NULL);
}

EXPORTED_SYM
bool
173
pushover_message_set_dest(pushover_message_t *msg, char *dest)
Shawn Webb's avatar
Shawn Webb committed
174
175
176
{

	assert(msg != NULL);
177
	assert(dest != NULL);
Shawn Webb's avatar
Shawn Webb committed
178
	assert(msg->psh_dest == NULL);
Shawn Webb's avatar
Shawn Webb committed
179

180
181
	msg->psh_dest = strdup(dest);
	return (msg->psh_dest != NULL);
Shawn Webb's avatar
Shawn Webb committed
182
183
184
185
186
187
188
189
190
}

EXPORTED_SYM
bool
pushover_message_set_title(pushover_message_t *msg, char *title)
{

	assert(msg != NULL);
	assert(title != NULL);
Shawn Webb's avatar
Shawn Webb committed
191
	assert(msg->psh_title == NULL);
Shawn Webb's avatar
Shawn Webb committed
192
193
194
195
196
197
198
199
200
201
202
203

	msg->psh_title = strdup(title);
	return (msg->psh_title != NULL);
}

EXPORTED_SYM
bool
pushover_message_set_device(pushover_message_t *msg, char *device)
{

	assert(msg != NULL);
	assert(device != NULL);
Shawn Webb's avatar
Shawn Webb committed
204
	assert(msg->psh_device == NULL);
Shawn Webb's avatar
Shawn Webb committed
205
206
207
208
209
210
211
212
213
214
215
216

	msg->psh_device = strdup(device);
	return (msg->psh_device != NULL);
}

EXPORTED_SYM
bool
pushover_message_set_priority(pushover_message_t *msg,
    pushover_priority_t prio)
{

	assert(msg != NULL);
217

Shawn Webb's avatar
Shawn Webb committed
218
	if (!pushover_message_priority_sane(prio))
Shawn Webb's avatar
Shawn Webb committed
219
220
221
222
223
		return (false);

	msg->psh_priority = prio;

	return (true);
Shawn Webb's avatar
Shawn Webb committed
224
225
226
227
228
229
230
231
}

EXPORTED_SYM
bool
pushover_submit_message(pushover_ctx_t *ctx, pushover_message_t *msg)
{
	CURLcode curl_code;
	char *post_str;
232
	CURL *curl;
Shawn Webb's avatar
Shawn Webb committed
233
234
235
	bool res;

	assert(ctx != NULL);
Shawn Webb's avatar
Shawn Webb committed
236
	assert(ctx->psh_uri != NULL);
Shawn Webb's avatar
Shawn Webb committed
237
	assert(ctx->psh_token != NULL);
Shawn Webb's avatar
Shawn Webb committed
238
239

	assert(msg != NULL);
240
	assert(msg->psh_dest != NULL);
Shawn Webb's avatar
Shawn Webb committed
241
	assert(msg->psh_msg != NULL);
242
	assert(pushover_message_priority_sane(msg->psh_priority));
Shawn Webb's avatar
Shawn Webb committed
243
244

	res = false;
Shawn Webb's avatar
Shawn Webb committed
245
	post_str = NULL;
Shawn Webb's avatar
Shawn Webb committed
246
247
248
249
250
251
252
253

	curl = curl_easy_init();
	if (curl == NULL)
		goto end;

	curl_easy_setopt(curl, CURLOPT_URL, ctx->psh_uri);

	post_str = msg_to_str(ctx, msg, curl);
254
	if (post_str == NULL)
Shawn Webb's avatar
Shawn Webb committed
255
256
		goto end;
	curl_easy_setopt(curl, CURLOPT_POSTFIELDS, post_str);
257
258
	curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1);
	curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1);
Shawn Webb's avatar
Shawn Webb committed
259
260
	curl_easy_setopt(curl, CURLOPT_STDERR, NULL);
	curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, pushover_curl_write_data);
Shawn Webb's avatar
Shawn Webb committed
261
262
263
264
265
266
267
268
269
270
271
272
273

	curl_code = curl_easy_perform(curl);
	res = (curl_code == CURLE_OK);

end:
	curl_easy_cleanup(curl);
	free(post_str);
	return (res);
}

static char *
msg_to_str(pushover_ctx_t *ctx, pushover_message_t *msg, CURL *curl)
{
274
	struct sbuf *sb;
Shawn Webb's avatar
Shawn Webb committed
275
	char *p, *res;
Shawn Webb's avatar
Shawn Webb committed
276
277
278
279

	assert(ctx != NULL);
	assert(msg != NULL);

280
281
282
283
284
	sb = sbuf_new_auto();
	if (sb == NULL) {
		goto end;
	}

Shawn Webb's avatar
Shawn Webb committed
285
	res = NULL;
286
287
288
289
290
291
292
293
	if (msg->psh_device != NULL) {
		p = curl_easy_escape(curl, msg->psh_device, 0);
		if (p == NULL) {
			goto end;
		}
		if (sbuf_printf(sb, "&device=%s", p)) {
			goto end;
		}
Shawn Webb's avatar
Shawn Webb committed
294
		curl_free(p);
295
296
297
298
299
300
301
302
303
	}
	if (msg->psh_msg != NULL) {
		p = curl_easy_escape(curl, msg->psh_msg, 0);
		if (p == NULL) {
			goto end;
		}
		if (sbuf_printf(sb, "&message=%s", p)) {
			goto end;
		}
Shawn Webb's avatar
Shawn Webb committed
304
		curl_free(p);
305
306
307
308
309
310
311
312
313
	}
	if (msg->psh_title != NULL) {
		p = curl_easy_escape(curl, msg->psh_title, 0);
		if (p == NULL) {
			goto end;
		}
		if (sbuf_printf(sb, "&title=%s", p)) {
			goto end;
		}
Shawn Webb's avatar
Shawn Webb committed
314
		curl_free(p);
315
316
317
318
319
320
321
322
323
	}
	if (ctx->psh_token != NULL) {
		p = curl_easy_escape(curl, ctx->psh_token, 0);
		if (p == NULL) {
			goto end;
		}
		if (sbuf_printf(sb, "&token=%s", p)) {
			goto end;
		}
Shawn Webb's avatar
Shawn Webb committed
324
		curl_free(p);
325
326
327
328
329
330
331
332
333
	}
	if (msg->psh_dest != NULL) {
		p = curl_easy_escape(curl, msg->psh_dest, 0);
		if (p == NULL) {
			goto end;
		}
		if (sbuf_printf(sb, "&user=%s", p)) {
			goto end;
		}
Shawn Webb's avatar
Shawn Webb committed
334
		curl_free(p);
335
	}
Shawn Webb's avatar
Shawn Webb committed
336

337
	if (sbuf_printf(sb, "&priority=%d", msg->psh_priority)) {
Shawn Webb's avatar
Shawn Webb committed
338
339
340
341
		goto end;
	}

end:
342
343
344
345
346
	if (sb != NULL) {
		if (sbuf_finish(sb)) {
			return (NULL);
		}
		res = strdup(sbuf_data(sb));
Shawn Webb's avatar
Shawn Webb committed
347
		sbuf_delete(sb);
348
	}
Shawn Webb's avatar
Shawn Webb committed
349
350
351
	return (res);
}

Shawn Webb's avatar
Shawn Webb committed
352
353
354
355
356
357
358
359
static size_t
pushover_curl_write_data(void *buffer, size_t sz, size_t nmemb,
    void *usrp)
{

	return (sz * nmemb);
}

Shawn Webb's avatar
Shawn Webb committed
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
__attribute__((constructor))
static void
init_libpushover(void)
{

	curl_global_init(CURL_GLOBAL_ALL);
}

__attribute__((destructor))
static void
destroy_libpushover(void)
{

	curl_global_cleanup();
}