4 * Specially written for Malcolm Davenport, but I think I'll use it too
6 * Copyright (C) 2004 - 2005, Digium Inc.
8 * Mark Spencer <markster@digium.com>
10 * Distributed under the terms of the GNU General Public License version 2.0
14 #include <linux/soundcard.h>
22 #include <sys/socket.h>
23 #include <sys/ioctl.h>
24 #include <netinet/in.h>
25 #include <arpa/inet.h>
27 static char *config = "/etc/muted.conf";
29 static char host[256] = "";
30 static char user[256] = "";
31 static char pass[256] = "";
32 static int smoothfade = 0;
33 static int mutelevel = 20;
35 static int needfork = 1;
37 static int stepsize = 3;
38 static int mixchan = SOUND_MIXER_VOLUME;
42 struct subchannel *next;
45 static struct channel {
49 struct subchannel *subs;
52 static void add_channel(char *tech, char *location)
55 chan = malloc(sizeof(struct channel));
57 memset(chan, 0, sizeof(struct channel));
58 chan->tech = strdup(tech);
59 chan->location = strdup(location);
60 chan->next = channels;
66 static int load_config(void)
74 f = fopen(config, "r");
76 fprintf(stderr, "Unable to open config file '%s': %s\n", config, strerror(errno));
80 fgets(buf, sizeof(buf), f);
83 val = strchr(buf, '#');
85 while(strlen(buf) && (buf[strlen(buf) - 1] < 33))
86 buf[strlen(buf) - 1] = '\0';
98 while(*val && (*val < 33)) val++;
100 if (!strcasecmp(buf, "host")) {
101 if (val && strlen(val))
102 strncpy(host, val, sizeof(host) - 1);
104 fprintf(stderr, "host needs an argument (the host) at line %d\n", lineno);
105 } else if (!strcasecmp(buf, "user")) {
106 if (val && strlen(val))
107 strncpy(user, val, sizeof(user) - 1);
109 fprintf(stderr, "user needs an argument (the user) at line %d\n", lineno);
110 } else if (!strcasecmp(buf, "pass")) {
111 if (val && strlen(val))
112 strncpy(pass, val, sizeof(pass) - 1);
114 fprintf(stderr, "pass needs an argument (the password) at line %d\n", lineno);
115 } else if (!strcasecmp(buf, "smoothfade")) {
117 } else if (!strcasecmp(buf, "mutelevel")) {
118 if (val && (sscanf(val, "%d", &x) == 1) && (x > -1) && (x < 101)) {
121 fprintf(stderr, "mutelevel must be a number from 0 (most muted) to 100 (no mute) at line %d\n", lineno);
122 } else if (!strcasecmp(buf, "channel")) {
123 if (val && strlen(val)) {
124 val2 = strchr(val, '/');
128 add_channel(val, val2);
130 fprintf(stderr, "channel needs to be of the format Tech/Location at line %d\n", lineno);
132 fprintf(stderr, "channel needs an argument (the channel) at line %d\n", lineno);
134 fprintf(stderr, "ignoring unknown keyword '%s'\n", buf);
140 fprintf(stderr, "no 'host' specification in config file\n");
141 else if (!strlen(user))
142 fprintf(stderr, "no 'user' specification in config file\n");
144 fprintf(stderr, "no 'channel' specifications in config file\n");
154 static int open_mixer(void)
156 mixfd = open("/dev/mixer", O_RDWR);
158 fprintf(stderr, "Unable to open /dev/mixer: %s\n", strerror(errno));
164 static int connect_asterisk(void)
170 struct sockaddr_in sin;
171 ports = strchr(host, ':');
175 if ((sscanf(ports, "%d", &port) != 1) || (port < 1) || (port > 65535)) {
176 fprintf(stderr, "'%s' is not a valid port number in the hostname\n", ports);
180 hp = gethostbyname(host);
182 fprintf(stderr, "Can't find host '%s'\n", host);
185 sock = socket(AF_INET, SOCK_STREAM, 0);
187 fprintf(stderr, "Failed to create socket: %s\n", strerror(errno));
190 sin.sin_family = AF_INET;
191 sin.sin_port = htons(port);
192 memcpy(&sin.sin_addr, hp->h_addr, sizeof(sin.sin_addr));
193 if (connect(sock, &sin, sizeof(sin))) {
194 fprintf(stderr, "Failed to connect to '%s' port '%d': %s\n", host, port, strerror(errno));
198 astf = fdopen(sock, "r+");
200 fprintf(stderr, "fdopen failed: %s\n", strerror(errno));
207 static char *get_line(void)
209 static char buf[1024];
210 if (fgets(buf, sizeof(buf), astf)) {
211 while(strlen(buf) && (buf[strlen(buf) - 1] < 33))
212 buf[strlen(buf) - 1] = '\0';
218 static int login_asterisk(void)
222 if (!(welcome = get_line())) {
223 fprintf(stderr, "disconnected (1)\n");
229 "Secret: %s\r\n\r\n", user, pass);
230 if (!(welcome = get_line())) {
231 fprintf(stderr, "disconnected (2)\n");
234 if (strcasecmp(welcome, "Response: Success")) {
235 fprintf(stderr, "login failed ('%s')\n", welcome);
238 /* Eat the rest of the event */
239 while((resp = get_line()) && strlen(resp));
241 fprintf(stderr, "disconnected (3)\n");
245 "Action: Status\r\n\r\n");
246 if (!(welcome = get_line())) {
247 fprintf(stderr, "disconnected (4)\n");
250 if (strcasecmp(welcome, "Response: Success")) {
251 fprintf(stderr, "status failed ('%s')\n", welcome);
254 /* Eat the rest of the event */
255 while((resp = get_line()) && strlen(resp));
257 fprintf(stderr, "disconnected (5)\n");
263 static struct channel *find_channel(char *channel)
267 struct channel *chan;
268 strncpy(tmp, channel, sizeof(tmp) - 1);
269 s = strchr(tmp, '/');
278 printf("Searching for '%s' tech, '%s' location\n", tmp, s);
281 if (!strcasecmp(chan->tech, tmp) && !strcasecmp(chan->location, s)) {
283 printf("Found '%s'/'%s'\n", chan->tech, chan->location);
293 static int getvol(void)
296 if (ioctl(mixfd, MIXER_READ(mixchan), &vol)) {
297 fprintf(stderr, "Unable to read mixer volume: %s\n", strerror(errno));
303 static int setvol(int vol)
305 if (ioctl(mixfd, MIXER_WRITE(mixchan), &vol)) {
306 fprintf(stderr, "Unable to write mixer volume: %s\n", strerror(errno));
312 static int oldvol = 0;
313 static int mutevol = 0;
315 static int mutedlevel(int orig, int mutelevel)
319 l = (float)(mutelevel) * (float)(l) / 100.0;
320 r = (float)(mutelevel) * (float)(r) / 100.0;
324 static void mute(void)
335 for (x=start;x>=mutelevel;x-=stepsize) {
336 mutevol = mutedlevel(vol, x);
341 mutevol = mutedlevel(vol, mutelevel);
344 printf("Mute from '%04x' to '%04x'!\n", oldvol, mutevol);
348 static void unmute(void)
355 printf("Unmute from '%04x' (should be '%04x') to '%04x'!\n", vol, mutevol, oldvol);
356 if (vol == mutevol) {
361 for (x=start;x<100;x+=stepsize) {
362 mutevol = mutedlevel(oldvol, x);
369 printf("Whoops, it's already been changed!\n");
373 static void check_mute(void)
376 struct channel *chan;
385 if (offhook && !muted)
387 else if (!offhook && muted)
391 static void delete_sub(struct channel *chan, char *name)
393 struct subchannel *sub, *prev;
397 if (!strcasecmp(sub->name, name)) {
399 prev->next = sub->next;
401 chan->subs = sub->next;
411 static void append_sub(struct channel *chan, char *name)
413 struct subchannel *sub;
416 if (!strcasecmp(sub->name, name))
420 sub = malloc(sizeof(struct subchannel));
422 memset(sub, 0, sizeof(struct subchannel));
423 sub->name = strdup(name);
424 sub->next = chan->subs;
429 static void hangup_chan(char *channel)
431 struct channel *chan;
433 printf("Hangup '%s'\n", channel);
434 chan = find_channel(channel);
436 delete_sub(chan, channel);
440 static void offhook_chan(char *channel)
442 struct channel *chan;
444 printf("Offhook '%s'\n", channel);
445 chan = find_channel(channel);
447 append_sub(chan, channel);
451 static int wait_event(void)
455 char channel[120]="";
456 char oldname[120]="";
457 char newname[120]="";
460 fprintf(stderr, "disconnected (6)\n");
463 if (!strncasecmp(resp, "Event: ", strlen("Event: "))) {
464 strncpy(event, resp + strlen("Event: "), sizeof(event) - 1);
465 /* Consume the rest of the non-event */
466 while((resp = get_line()) && strlen(resp)) {
467 if (!strncasecmp(resp, "Channel: ", strlen("Channel: ")))
468 strncpy(channel, resp + strlen("Channel: "), sizeof(channel) - 1);
469 if (!strncasecmp(resp, "Newname: ", strlen("Newname: ")))
470 strncpy(newname, resp + strlen("Newname: "), sizeof(newname) - 1);
471 if (!strncasecmp(resp, "Oldname: ", strlen("Oldname: ")))
472 strncpy(oldname, resp + strlen("Oldname: "), sizeof(oldname) - 1);
474 if (strlen(channel)) {
475 if (!strcasecmp(event, "Hangup"))
476 hangup_chan(channel);
478 offhook_chan(channel);
480 if (strlen(newname) && strlen(oldname)) {
481 if (!strcasecmp(event, "Rename")) {
482 hangup_chan(oldname);
483 offhook_chan(newname);
487 /* Consume the rest of the non-event */
488 while((resp = get_line()) && strlen(resp));
491 fprintf(stderr, "disconnected (7)\n");
497 static void usage(void)
499 printf("Usage: muted [-f] [-d]\n"
500 " -f : Do not fork\n"
501 " -d : Debug (implies -f)\n");
504 int main(int argc, char *argv[])
507 while((x = getopt(argc, argv, "fhd")) > 0) {
527 if (connect_asterisk()) {
531 if (login_asterisk()) {
541 while(connect_asterisk()) {
544 if (login_asterisk()) {