acmecert: Reorganized a bit.
[utils.git] / cidd.c
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
20 int mdm, sock;
21 int ibuflen = 0;
22 unsigned char ibuf[1024];
23 unsigned char tmpbuf[1024];
24 fd_set cfds;
25 int isdaemon;
26
27 void 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
44 void 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
54 unsigned 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
95 void 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
111 void 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
133 void sighandler(int sig)
134 {
135     if(sig == SIGHUP)
136     {
137         initmodem();
138     }
139 }
140
141 int 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 }