Opaquify channel stringfields
[asterisk/asterisk.git] / main / image.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2006, Digium, Inc.
5  *
6  * Mark Spencer <markster@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18
19 /*! \file
20  *
21  * \brief Image Management
22  *
23  * \author Mark Spencer <markster@digium.com> 
24  */
25
26 #include "asterisk.h"
27
28 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
29
30 #include <sys/time.h>
31 #include <sys/stat.h>
32 #include <signal.h>
33
34 #include "asterisk/paths.h"     /* use ast_config_AST_DATA_DIR */
35 #include "asterisk/sched.h"
36 #include "asterisk/channel.h"
37 #include "asterisk/file.h"
38 #include "asterisk/image.h"
39 #include "asterisk/translate.h"
40 #include "asterisk/cli.h"
41 #include "asterisk/lock.h"
42
43 /* XXX Why don't we just use the formats struct for this? */
44 static AST_RWLIST_HEAD_STATIC(imagers, ast_imager);
45
46 int ast_image_register(struct ast_imager *img)
47 {
48         AST_RWLIST_WRLOCK(&imagers);
49         AST_RWLIST_INSERT_HEAD(&imagers, img, list);
50         AST_RWLIST_UNLOCK(&imagers);
51         ast_verb(2, "Registered format '%s' (%s)\n", img->name, img->desc);
52         return 0;
53 }
54
55 void ast_image_unregister(struct ast_imager *img)
56 {
57         AST_RWLIST_WRLOCK(&imagers);
58         img = AST_RWLIST_REMOVE(&imagers, img, list);
59         AST_RWLIST_UNLOCK(&imagers);
60
61         if (img)
62                 ast_verb(2, "Unregistered format '%s' (%s)\n", img->name, img->desc);
63 }
64
65 int ast_supports_images(struct ast_channel *chan)
66 {
67         if (!chan || !chan->tech)
68                 return 0;
69         if (!chan->tech->send_image)
70                 return 0;
71         return 1;
72 }
73
74 static int file_exists(char *filename)
75 {
76         int res;
77         struct stat st;
78         res = stat(filename, &st);
79         if (!res)
80                 return st.st_size;
81         return 0;
82 }
83
84 static void make_filename(char *buf, int len, const char *filename, const char *preflang, char *ext)
85 {
86         if (filename[0] == '/') {
87                 if (!ast_strlen_zero(preflang))
88                         snprintf(buf, len, "%s-%s.%s", filename, preflang, ext);
89                 else
90                         snprintf(buf, len, "%s.%s", filename, ext);
91         } else {
92                 if (!ast_strlen_zero(preflang))
93                         snprintf(buf, len, "%s/%s/%s-%s.%s", ast_config_AST_DATA_DIR, "images", filename, preflang, ext);
94                 else
95                         snprintf(buf, len, "%s/%s/%s.%s", ast_config_AST_DATA_DIR, "images", filename, ext);
96         }
97 }
98
99 struct ast_frame *ast_read_image(const char *filename, const char *preflang, struct ast_format *format)
100 {
101         struct ast_imager *i;
102         char buf[256];
103         char tmp[80];
104         char *e;
105         struct ast_imager *found = NULL;
106         int fd;
107         int len=0;
108         struct ast_frame *f = NULL;
109         
110         AST_RWLIST_RDLOCK(&imagers);
111         AST_RWLIST_TRAVERSE(&imagers, i, list) {
112                 /* if NULL image format, just pick the first one, otherwise match it. */
113                 if (!format || (ast_format_cmp(&i->format, format) == AST_FORMAT_CMP_EQUAL)) {
114                         char *stringp=NULL;
115                         ast_copy_string(tmp, i->exts, sizeof(tmp));
116                         stringp = tmp;
117                         e = strsep(&stringp, "|");
118                         while (e) {
119                                 make_filename(buf, sizeof(buf), filename, preflang, e);
120                                 if ((len = file_exists(buf))) {
121                                         found = i;
122                                         break;
123                                 }
124                                 make_filename(buf, sizeof(buf), filename, NULL, e);
125                                 if ((len = file_exists(buf))) {
126                                         found = i;
127                                         break;
128                                 }
129                                 e = strsep(&stringp, "|");
130                         }
131                 }
132                 if (found)
133                         break;  
134         }
135
136         if (found) {
137                 fd = open(buf, O_RDONLY);
138                 if (fd > -1) {
139                         if (!found->identify || found->identify(fd)) {
140                                 /* Reset file pointer */
141                                 lseek(fd, 0, SEEK_SET);
142                                 f = found->read_image(fd, len); 
143                         } else
144                                 ast_log(LOG_WARNING, "%s does not appear to be a %s file\n", buf, found->name);
145                         close(fd);
146                 } else
147                         ast_log(LOG_WARNING, "Unable to open '%s': %s\n", buf, strerror(errno));
148         } else
149                 ast_log(LOG_WARNING, "Image file '%s' not found\n", filename);
150         
151         AST_RWLIST_UNLOCK(&imagers);
152         
153         return f;
154 }
155
156 int ast_send_image(struct ast_channel *chan, const char *filename)
157 {
158         struct ast_frame *f;
159         int res = -1;
160         if (chan->tech->send_image) {
161                 f = ast_read_image(filename, ast_channel_language(chan), NULL);
162                 if (f) {
163                         res = chan->tech->send_image(chan, f);
164                         ast_frfree(f);
165                 }
166         }
167         return res;
168 }
169
170 static char *handle_core_show_image_formats(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
171 {
172 #define FORMAT "%10s %10s %50s %10s\n"
173 #define FORMAT2 "%10s %10s %50s %10s\n"
174         struct ast_imager *i;
175         int count_fmt = 0;
176
177         switch (cmd) {
178         case CLI_INIT:
179                 e->command = "core show image formats";
180                 e->usage =
181                         "Usage: core show image formats\n"
182                         "       Displays currently registered image formats (if any).\n";
183                 return NULL;
184         case CLI_GENERATE:
185                 return NULL;
186         }
187         if (a->argc != 4)
188                 return CLI_SHOWUSAGE;
189         ast_cli(a->fd, FORMAT, "Name", "Extensions", "Description", "Format");
190         ast_cli(a->fd, FORMAT, "----", "----------", "-----------", "------");
191         AST_RWLIST_RDLOCK(&imagers);
192         AST_RWLIST_TRAVERSE(&imagers, i, list) {
193                 ast_cli(a->fd, FORMAT2, i->name, i->exts, i->desc, ast_getformatname(&i->format));
194                 count_fmt++;
195         }
196         AST_RWLIST_UNLOCK(&imagers);
197         ast_cli(a->fd, "\n%d image format%s registered.\n", count_fmt, count_fmt == 1 ? "" : "s");
198         return CLI_SUCCESS;
199 }
200
201 static struct ast_cli_entry cli_image[] = {
202         AST_CLI_DEFINE(handle_core_show_image_formats, "Displays image formats")
203 };
204
205 int ast_image_init(void)
206 {
207         ast_cli_register_multiple(cli_image, ARRAY_LEN(cli_image));
208         return 0;
209 }