aboutsummaryrefslogtreecommitdiff
path: root/example.c
blob: 4a2fa1c44e7a73245c31becc41163746b6587c28 (plain)
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
#define _POSIX_C_SOURCE 200809L
#include "easy-tg.h"
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
#include <signal.h>

static void read_input(const char *prompt, char *buf, unsigned int len)
{
	printf("%s", prompt);
	fflush(stdout);
	ssize_t size = read(0, buf, len + 1);
	if(size >= 1) buf[size - 1] = '\0';
	printf("Read: %s\n", buf);
}

static void run()
{
	/* In each loop, the action our application needs to take is returned via return code.
	 * Other data, such as current update type and the whole JSON response, are stored in registers.
	 * There are nine registers:
	 * int tg_errno: In case of error, it will store the error code.
	 * const char *tg_update_type: Always stores the parsed type of update.
	 * json_object *tg_update: Always stores the whole tokenized JSON update.
	 * void *tg_reg1: Optional data field.
	 * void *tg_reg2: Optional data field.
	 * void *tg_reg3: Optional data field.
	 * void *tg_reg4: Optional data field.
	 * void *tg_reg5: Optional data field.
	 * void *tg_reg6: Optional data field.
	 * Each register has the lifetime from the end of tg_loop() to the next call of tg_loop().
	 * After calling tg_loop() for the next time, all memory will be released and the registers will be reset to default values, which are 0 for int and NULL for pointers.
	 */
	printf("%s\n", tg_update_type);
}

static void *main_sighandler(void *arg)
{
        pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
        int r = 0;
        sigset_t *set = arg;
        int sig;
        while(true)
        {
                r = sigwait(set, &sig);
                if(r)
                {
                        fprintf(stderr, "Cannot call sigwait(): %d.\n", r);
                        goto cleanup;
                }
                switch(sig)
                {
                        case SIGINT:
                        case SIGTERM:
                                printf("Received SIGINT or SIGTERM, asking TDLib to close.\n");
                                tg_close();
                                goto cleanup;
                }
        }
        goto cleanup;
cleanup:
        pthread_exit(NULL);
        return NULL;
}

int main(int argc, char **argv)
{
	bool sighandler_setup = false;
	pthread_t thread_sighandler;
	int r = 0;
        sigset_t set;
        sigemptyset(&set);
        sigaddset(&set, SIGTERM);
        sigaddset(&set, SIGINT);
        r = pthread_sigmask(SIG_BLOCK, &set, NULL);
        if(r)
        {
                fprintf(stderr, "Cannot call pthread_sigmask(): %d\n", r);
                goto cleanup;
        }
        r = pthread_create(&thread_sighandler, NULL, &main_sighandler, &set);
        if(r)
        {
                fprintf(stderr, "Cannot call pthread_create(): %d\n", r);
                goto cleanup;
        }
        sighandler_setup = true;
	r = tg_init();
	if(r) goto cleanup; /* Fetal errors encountered. */
	while(1)
	{
		switch(tg_loop())
		{
			case TG_IGNORE: /* Invalid response from TDLib. Just ignore it. */
				break;
			case TG_RUN: /* Non-login update received. Run our custom function. */
				run();
				break;
			case TG_CLOSED: /* TDLib is shutting down. We have nothing to do except releasing resources. */
				goto destroy;
			case TG_CLOSING: /* TDLib is closing. Currently we don't need to do nothing. */
			case TG_LOGGING_OUT: /* The account is logging out. No need for now. */
				break;
			case TG_LOGGED_IN: /* Login ready. */
				printf("You are logged in!\n");
				break;
			case TG_LOGIN_PHONE: /* We need to provide the phone number to login. */
				char phone[20];
				read_input("Phone number: ", phone, 19);
				tg_login_phone(phone);
				break;
			case TG_LOGIN_CODE: /* We need to provide the verification code. */
				char code[7];
				read_input("Verification code: ", code, 6);
				tg_login_code(code);
				break;
			case TG_LOGIN_ENC: /* During initialization, TDLib is asking us for database encryption key. */
				tg_login_enc_key(""); /* Just leave it empty for now. */
				break;
			case TG_LOGIN_QR: /* QR login. Currently not supported in the demo. */
				/* The QR link is stored in register 1. */
				/* generate_qr((char*)tg_reg1); */
				printf("QR login not supported.\n");
				break;
			case TG_LOGIN_PW: /* We need to type the password. */
				char pass[257];
				read_input("Password: ", pass, 256);
				tg_login_pass(pass);
				break;
			case TG_LOGIN_REG: /* The phone number is verified but unknown. We need fill in the registration form. In this case, we will ask the user to register in the official client instead. */
				printf("Your phone number is not known.\n");
				break;
			case TG_PARAMS: /* TDLib is not been setup and is asking you for parameters. */
				tg_set_params(
					true, /* Use test datacenter */
					"/tmp/td", /* Database directory */
					NULL, /* Files directory */
					false, /* Use files database */
					false, /* Use message database */
					false, /* Use chat info database */
					false, /* Support secret chats */
					API_ID, /* API ID */
					API_HASH, /* API Hash */
					"en", /* System language code */
					"Desktop", /* Device model */
					"Windoge 114.514", /* System version */
					"Moe Bot", /* Application version */
					false, /* Enable storage optimizer */
					true /* Ignore file names */
				);
				break;
			case TG_ERROR: /* TDLib returned an error. */
				/* Error code is stored in tg_errno;
				 * Request extra (ID) is stored in register 1;
				 * Error message is stored in register 2.
				 */
				/* Built-in request extras */
				if(!strcmp(TG_REQ_SET_PARAMS, tg_reg1))
				{
					printf("Invalid TDLib parameters! %d (%s)\n", tg_errno, tg_reg2);
				} else if(!strcmp(TG_REQ_LOGIN_PHONE, tg_reg1))
				{
					printf("Invalid phone number! %d (%s)\n", tg_errno, tg_reg2);
				} else if(!strcmp(TG_REQ_LOGIN_PASS, tg_reg1))
				{
					printf("Invalid password! %d (%s)\n", tg_errno, tg_reg2);
				} else
				{
					printf("Invalid request: %s! %d (%s)\n", tg_reg1, tg_errno, tg_reg2);
				}
				break;
			case TG_SYSERR: /* Easy-TG encountered an error. */
				/* Error code is stored in tg_errno. */
				printf("Fetal: %d\n", tg_errno);
				break;
			default:
				printf("???\n");
				break;
		}
	}
	goto destroy;
destroy:
	tg_destroy();
	goto cleanup;
cleanup:
	if(sighandler_setup)
        {
                pthread_cancel(thread_sighandler);
                pthread_join(thread_sighandler, NULL);
        }
	return r;
}