major Makefile and build process improvements, including removal of all hardcoded...
[asterisk/asterisk.git] / image.c
1 /*
2  * Asterisk -- A telephony toolkit for Linux.
3  *
4  * Channel Management
5  * 
6  * Copyright (C) 1999, Mark Spencer
7  *
8  * Mark Spencer <markster@linux-support.net>
9  *
10  * This program is free software, distributed under the terms of
11  * the GNU General Public License
12  */
13
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <sys/time.h>
18 #include <sys/stat.h>
19 #include <signal.h>
20 #include <errno.h>
21 #include <unistd.h>
22
23 #include "asterisk/sched.h"
24 #include "asterisk/options.h"
25 #include "asterisk/channel.h"
26 #include "asterisk/logger.h"
27 #include "asterisk/file.h"
28 #include "asterisk/image.h"
29 #include "asterisk/translate.h"
30 #include "asterisk/cli.h"
31 #include "asterisk/lock.h"
32 #include "asterisk.h"
33
34 static struct ast_imager *list;
35 AST_MUTEX_DEFINE_STATIC(listlock);
36
37 int ast_image_register(struct ast_imager *img)
38 {
39         if (option_verbose > 1)
40                 ast_verbose(VERBOSE_PREFIX_2 "Registered format '%s' (%s)\n", img->name, img->desc);
41         ast_mutex_lock(&listlock);
42         img->next = list;
43         list = img;
44         ast_mutex_unlock(&listlock);
45         return 0;
46 }
47
48 void ast_image_unregister(struct ast_imager *img)
49 {
50         struct ast_imager *i, *prev = NULL;
51         ast_mutex_lock(&listlock);
52         i = list;
53         while(i) {
54                 if (i == img) {
55                         if (prev) 
56                                 prev->next = i->next;
57                         else
58                                 list = i->next;
59                         break;
60                 }
61                 prev = i;
62                 i = i->next;
63         }
64         ast_mutex_unlock(&listlock);
65         if (i && (option_verbose > 1))
66                 ast_verbose(VERBOSE_PREFIX_2 "Unregistered format '%s' (%s)\n", img->name, img->desc);
67 }
68
69 int ast_supports_images(struct ast_channel *chan)
70 {
71         if (!chan || !chan->tech)
72                 return 0;
73         if (!chan->tech->send_image)
74                 return 0;
75         return 1;
76 }
77
78 static int file_exists(char *filename)
79 {
80         int res;
81         struct stat st;
82         res = stat(filename, &st);
83         if (!res)
84                 return st.st_size;
85         return 0;
86 }
87
88 static void make_filename(char *buf, int len, char *filename, char *preflang, char *ext)
89 {
90         if (filename[0] == '/') {
91                 if (preflang && strlen(preflang))
92                         snprintf(buf, len, "%s-%s.%s", filename, preflang, ext);
93                 else
94                         snprintf(buf, len, "%s.%s", filename, ext);
95         } else {
96                 if (preflang && strlen(preflang))
97                         snprintf(buf, len, "%s/%s/%s-%s.%s", ast_config_AST_VAR_DIR, "images", filename, preflang, ext);
98                 else
99                         snprintf(buf, len, "%s/%s/%s.%s", ast_config_AST_VAR_DIR, "images", filename, ext);
100         }
101 }
102
103 struct ast_frame *ast_read_image(char *filename, char *preflang, int format)
104 {
105         struct ast_imager *i;
106         char buf[256];
107         char tmp[80];
108         char *e;
109         struct ast_imager *found = NULL;
110         int fd;
111         int len=0;
112         struct ast_frame *f = NULL;
113 #if 0 /* We need to have some sort of read-only lock */
114         ast_mutex_lock(&listlock);
115 #endif  
116         i = list;
117         while(!found && i) {
118                 if (i->format & format) {
119                         char *stringp=NULL;
120                         strncpy(tmp, i->exts, sizeof(tmp)-1);
121                         stringp=tmp;
122                         e = strsep(&stringp, "|");
123                         while(e) {
124                                 make_filename(buf, sizeof(buf), filename, preflang, e);
125                                 if ((len = file_exists(buf))) {
126                                         found = i;
127                                         break;
128                                 }
129                                 make_filename(buf, sizeof(buf), filename, NULL, e);
130                                 if ((len = file_exists(buf))) {
131                                         found = i;
132                                         break;
133                                 }
134                                 e = strsep(&stringp, "|");
135                         }
136                 }
137                 i = i->next;
138         }
139         if (found) {
140                 fd = open(buf, O_RDONLY);
141                 if (fd > -1) {
142                         if (!found->identify || found->identify(fd)) {
143                                 /* Reset file pointer */
144                                 lseek(fd, 0, SEEK_SET);
145                                 f = found->read_image(fd,len); 
146                         } else
147                                 ast_log(LOG_WARNING, "%s does not appear to be a %s file\n", buf, i->name);
148                         close(fd);
149                 } else
150                         ast_log(LOG_WARNING, "Unable to open '%s': %s\n", buf, strerror(errno));
151         } else
152                 ast_log(LOG_WARNING, "Image file '%s' not found\n", filename);
153 #if 0
154         ast_mutex_unlock(&listlock);
155 #endif  
156         return f;
157 }
158
159
160 int ast_send_image(struct ast_channel *chan, char *filename)
161 {
162         struct ast_frame *f;
163         int res = -1;
164         if (chan->tech->send_image) {
165                 f = ast_read_image(filename, chan->language, -1);
166                 if (f) {
167                         res = chan->tech->send_image(chan, f);
168                         ast_frfree(f);
169                 }
170         }
171         return res;
172 }
173
174 static int show_image_formats(int fd, int argc, char *argv[])
175 {
176 #define FORMAT "%10s %10s %50s %10s\n"
177 #define FORMAT2 "%10s %10s %50s %10s\n"
178         struct ast_imager *i;
179         if (argc != 3)
180                 return RESULT_SHOWUSAGE;
181         ast_cli(fd, FORMAT, "Name", "Extensions", "Description", "Format");
182         i = list;
183         while(i) {
184                 ast_cli(fd, FORMAT2, i->name, i->exts, i->desc, ast_getformatname(i->format));
185                 i = i->next;
186         };
187         return RESULT_SUCCESS;
188 }
189
190 struct ast_cli_entry show_images =
191 {
192         { "show", "image", "formats" },
193         show_image_formats,
194         "Displays image formats",
195 "Usage: show image formats\n"
196 "       displays currently registered image formats (if any)\n"
197 };
198
199
200 int ast_image_init(void)
201 {
202         ast_cli_register(&show_images);
203         return 0;
204 }
205