2 * Copyright (c) 2012, 2013, Intel Corporation
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * * Neither the name of Intel Corporation nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 #include <murphy/common/debug.h>
34 #include "srs/daemon/plugin.h"
35 #include "srs/daemon/client.h"
37 #define SEARCH_NAME "search-client"
38 #define SEARCH_DESCR "A trivial search plugin for SRS."
39 #define SEARCH_AUTHORS "Krisztian Litkey <kli@iki.fi>"
40 #define SEARCH_VERSION "0.0.1"
42 #define DICTIONARY "general"
43 #define COMMAND "google-chrome \"http://google.com/search?q=__url__\""
46 srs_plugin_t *self; /* us */
47 srs_client_t *c; /* our client instance */
48 const char *dict; /* dictionary to use */
49 const char *cmd; /* search command template */
54 static int focus_cb(srs_client_t *c, srs_voice_focus_t focus)
56 srs_context_t *srs = c->srs;
57 search_t *sch = c->user_data;
64 case SRS_VOICE_FOCUS_NONE: state = "none"; break;
65 case SRS_VOICE_FOCUS_SHARED: state = "shared"; break;
66 case SRS_VOICE_FOCUS_EXCLUSIVE: state = "exclusive"; break;
67 default: state = "unknown";
70 mrp_debug("search plugin focus is now: %s", state);
76 static int url_encode(char *buf, size_t size, int ntoken, char **tokens)
78 unsigned char *p, *s, L, H;
81 p = (unsigned char *)buf;
84 for (i = 0; i < ntoken; i++) {
96 s = (unsigned char *)tokens[i];
114 H = (*s & 0xf0) >> 4;
117 if (/*0 <= H && */H <= 9) H += '0';
119 if (/*0 <= L && */L <= 9) L += '0';
143 static int command_cb(srs_client_t *c, int idx, int ntoken, char **tokens,
144 uint32_t *start, uint32_t *end, srs_audiobuf_t *audio)
146 search_t *sch = (search_t *)c->user_data;
147 char qry[1024], cmd[8192];
157 mrp_debug("got search plugin command...");
162 if (url_encode(qry, sizeof(qry), ntoken, tokens) > 0) {
163 mrp_log_info("search-client got query: '%s'", qry);
165 l = snprintf(cmd, sizeof(cmd), sch->cmd, qry);
167 if (l < (int)sizeof(cmd)) {
168 mrp_log_info("search-client executing '%s'", cmd);
173 mrp_log_error("search-client: URL encoding failed");
178 static int create_search(srs_plugin_t *plugin)
182 mrp_debug("creating search plugin");
184 sch = mrp_allocz(sizeof(*sch));
187 plugin->plugin_data = sch;
195 static int config_search(srs_plugin_t *plugin, srs_cfg_t *settings)
197 search_t *sch = (search_t *)plugin->plugin_data;
198 static char cmdbuf[1024];
199 const char *dict, *cmd;
203 mrp_debug("configure search plugin");
205 dict = srs_config_get_string(settings, "search.dictionary", DICTIONARY);
206 cmd = srs_config_get_string(settings, "search.command" , COMMAND);
208 q = (char *)cmd + strlen(cmd);
209 while (q > cmd && (*q == ' ' || *q == '\t'))
216 if ((q = strstr(cmd, "__url__")) == NULL) {
217 mrp_log_error("Invalid search command '%s', has no __url__ tag.", cmd);
225 n = snprintf(p, l, "%*.*s", n, n, cmd);
231 mrp_log_error("Invalid search command '%s', too long.", cmd);
235 n = snprintf(p, l, "%%s");
242 q += strlen("__url__");
243 n = snprintf(p, l, "%s%s", q, nobg ? "&" : "");
253 mrp_log_info("search plugin dictionary: '%s'", sch->dict);
254 mrp_log_info("search plugin command: '%s'", sch->cmd);
260 static int start_search(srs_plugin_t *plugin)
262 static srs_client_ops_t ops = {
263 .notify_focus = focus_cb,
264 .notify_command = command_cb
267 char cmd1[1024], cmd2[1024];
268 search_t *sch = plugin->plugin_data;
269 char *cmds[2]= { &cmd1[0], &cmd2[0] };
270 int ncmd = (int)MRP_ARRAY_SIZE(cmds);
271 srs_context_t *srs = plugin->srs;
274 const char *name, *appcls, *id;
276 mrp_debug("starting search plugin");
282 snprintf(cmd1, sizeof(cmd1), "search for __push_dict__(%s) *", sch->dict);
283 snprintf(cmd2, sizeof(cmd2), "google for __push_dict__(%s) *", sch->dict);
285 c = client_create(srs, SRS_CLIENT_TYPE_BUILTIN,
286 name, appcls, cmds, ncmd, id, &ops, sch);
294 client_request_focus(c, SRS_VOICE_FOCUS_SHARED);
300 static void stop_search(srs_plugin_t *plugin)
302 search_t *sch = (search_t *)plugin->plugin_data;
304 mrp_debug("stop search plugin");
306 client_destroy(sch->c);
313 static void destroy_search(srs_plugin_t *plugin)
315 srs_context_t *srs = plugin->srs;
316 search_t *sch = (search_t *)plugin->plugin_data;
320 mrp_debug("destroy search plugin");
326 SRS_DECLARE_PLUGIN(SEARCH_NAME, SEARCH_DESCR, SEARCH_AUTHORS, SEARCH_VERSION,
327 create_search, config_search, start_search, stop_search,