acmecert: Added a simple built-in DER decoder to not have to rely on external openssl.
[utils.git] / cidd.c
CommitLineData
1c2fdcc2
FT
1#include <stdio.h>
2#include <stdarg.h>
3#include <string.h>
4#include <stdlib.h>
5#include <unistd.h>
6#include <termios.h>
7#include <fcntl.h>
8#include <sys/socket.h>
9#include <netinet/in.h>
10#include <errno.h>
11#include <sys/poll.h>
12#include <sys/select.h>
13#include <signal.h>
14#include <syslog.h>
15
16#define MODEM_DEV "/dev/modem"
17#define PIDFILE "/var/run/cidd.pid"
18#define PORT 5001
19
20int mdm, sock;
21int ibuflen = 0;
22unsigned char ibuf[1024];
23unsigned char tmpbuf[1024];
24fd_set cfds;
25int isdaemon;
26
27void write2(int fd, unsigned char *buf, int len)
28{
29 int ret;
30
31 while(len)
32 {
33 ret = write(fd, buf, len);
34 if(ret < 0)
35 {
36 perror("write");
37 exit(1);
38 }
39 buf += ret;
40 len -= ret;
41 }
42}
43
44void sendcmd(unsigned char *cmd)
45{
46 unsigned char *lbuf;
47
48 lbuf = strcpy(malloc(strlen(cmd) + 3), cmd);
49 strcat(lbuf, "\r\n");
50 write2(mdm, lbuf, strlen(cmd) + 2);
51 free(lbuf);
52}
53
54unsigned char *getline(int block)
55{
56 int i;
57 unsigned char *p;
58 int ret, len;
59 static unsigned char retbuf[1024];
60 struct pollfd pf;
61
62 while(1)
63 {
64 while((p = memchr(ibuf, '\r', ibuflen)) != NULL)
65 {
66 memcpy(retbuf, ibuf, len = (p - ibuf));
67 retbuf[len] = 0;
68 memmove(ibuf, p + 1, ibuflen -= (len + 1));
69 for(p = retbuf; *p; p++)
70 {
71 while(*p == '\n')
72 memmove(p, p + 1, len--);
73 }
74 if(len && (memcmp(retbuf, "AT", 2)))
75 return(retbuf);
76 }
77 if(!block)
78 {
79 pf.fd = mdm;
80 pf.events = POLLIN;
81 pf.revents = 0;
82 if(poll(&pf, 1, 0) == 0)
83 return(NULL);
84 }
85 ret = read(mdm, ibuf + ibuflen, 1024 - ibuflen);
86 if(ret < 0)
87 {
88 perror("read");
89 exit(1);
90 }
91 ibuflen += ret;
92 }
93}
94
95void broadcast(unsigned char *buf, ...)
96{
97 int i;
98 va_list args;
99
100 va_start(args, buf);
101 vsprintf(tmpbuf, buf, args);
102 va_end(args);
103 strcat(tmpbuf, "\n");
104 for(i = 0; i < FD_SETSIZE; i++)
105 {
106 if(FD_ISSET(i, &cfds) && (i != mdm) && (i != sock))
107 write2(i, tmpbuf, strlen(tmpbuf));
108 }
109}
110
111void initmodem(void)
112{
113 sendcmd("ATZ");
114 if(strcmp(getline(1), "OK"))
115 {
116 if(isdaemon)
117 syslog(LOG_CRIT, "Could not reset modem");
118 else
119 fprintf(stderr, "Could not reset modem\n");
120 exit(1);
121 }
122 sendcmd("AT#CID=1");
123 if(strcmp(getline(1), "OK"))
124 {
125 if(isdaemon)
126 syslog(LOG_CRIT, "Could not activate called ID\n");
127 else
128 fprintf(stderr, "Could not activate caller ID\n");
129 exit(1);
130 }
131}
132
133void sighandler(int sig)
134{
135 if(sig == SIGHUP)
136 {
137 initmodem();
138 }
139}
140
141int main(int argc, unsigned char **argv)
142{
143 int i;
144 unsigned char *p;
145 int nsock;
146 int ret;
147 struct sockaddr_in name;
148 struct termios tio;
149 fd_set rfds;
150 FILE *pidst;
151
152 isdaemon = 0;
153 if((mdm = open(MODEM_DEV, O_RDWR)) < 0)
154 {
155 perror(MODEM_DEV);
156 return(1);
157 }
158 if(tcgetattr(mdm, &tio) < 0)
159 {
160 perror("tcgetattr");
161 return(1);
162 }
163 cfmakeraw(&tio);
164 cfsetispeed(&tio, B0);
165 cfsetospeed(&tio, B38400);
166 if(tcsetattr(mdm, TCSANOW, &tio) < 0)
167 {
168 perror("tcsetattr");
169 return(1);
170 }
171 if((sock = socket(PF_INET, SOCK_STREAM, 0)) < 0)
172 {
173 perror("socket");
174 return(1);
175 }
176 name.sin_family = AF_INET;
177 name.sin_port = htons(PORT);
178 name.sin_addr.s_addr = 0;
179 if(bind(sock, (struct sockaddr *)&name, sizeof(name)) < 0)
180 {
181 perror("bind");
182 return(1);
183 }
184 if(listen(sock, 16) < 0)
185 {
186 perror("listen");
187 return(1);
188 }
189 initmodem();
190 signal(SIGHUP, sighandler);
191 if((pidst = fopen(PIDFILE, "w")) == NULL)
192 {
193 perror("open " PIDFILE);
194 exit(1);
195 }
196 daemon(0, 0);
197 fprintf(pidst, "%i\n", getpid());
198 fclose(pidst);
199 openlog("cidd", LOG_PID, LOG_DAEMON);
200 isdaemon = 1;
201 FD_ZERO(&cfds);
202 FD_SET(mdm, &cfds);
203 FD_SET(sock, &cfds);
204 while(1)
205 {
206 rfds = cfds;
207 ret = select(FD_SETSIZE, &rfds, NULL, NULL, NULL);
208 if((ret < 0) && (errno != EINTR))
209 {
210 syslog(LOG_CRIT, "select return %m");
211 return(1);
212 }
213 if(ret > 0)
214 {
215 for(i = 0; i < FD_SETSIZE; i++)
216 {
217 if(FD_ISSET(i, &rfds))
218 {
219 if(i == mdm)
220 {
221 while((p = getline(0)) != NULL)
222 {
223 if(!strcmp(p, "RING"))
224 broadcast("R");
225 if(!memcmp(p, "NMBR = ", 7))
226 {
227 p += 7;
228 broadcast("N%s", p);
229 }
230 }
231 } else if(i == sock) {
232 if((nsock = accept(sock, NULL, 0)) >= 0)
233 FD_SET(nsock, &cfds);
234 } else {
235 if(read(i, tmpbuf, 1024) == 0)
236 {
237 FD_CLR(i, &cfds);
238 close(i);
239 }
240 }
241 }
242 }
243 }
244 }
245}