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 "src/daemon/plugin.h"
35 #include "src/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 "chromium-browser \"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;
61 case SRS_VOICE_FOCUS_NONE: state = "none"; break;
62 case SRS_VOICE_FOCUS_SHARED: state = "shared"; break;
63 case SRS_VOICE_FOCUS_EXCLUSIVE: state = "exclusive"; break;
64 default: state = "unknown";
67 mrp_debug("search plugin focus is now: %s", state);
73 static int url_encode(char *buf, size_t size, int ntoken, char **tokens)
75 unsigned char *p, *s, L, H;
78 p = (unsigned char *)buf;
81 for (i = 0; i < ntoken; i++) {
93 s = (unsigned char *)tokens[i];
111 H = (*s & 0xf0) >> 4;
114 if (0 <= H && H <= 9) H += '0';
116 if (0 <= L && L <= 9) L += '0';
140 static int command_cb(srs_client_t *c, int idx, int ntoken, char **tokens,
141 uint32_t *start, uint32_t *end, srs_audiobuf_t *audio)
143 search_t *sch = (search_t *)c->user_data;
144 char qry[1024], cmd[8192];
154 mrp_debug("got search plugin command...");
159 if (url_encode(qry, sizeof(qry), ntoken, tokens) > 0) {
160 mrp_log_info("*** search query: '%s'", qry);
162 l = snprintf(cmd, sizeof(cmd), sch->cmd, qry);
164 if (l < sizeof(cmd)) {
165 mrp_log_info("*** executing '%s'", cmd);
170 mrp_log_error("*** URL encoding failed");
175 static int create_search(srs_plugin_t *plugin)
179 mrp_debug("creating search plugin");
181 sch = mrp_allocz(sizeof(*sch));
184 plugin->plugin_data = sch;
192 static int config_search(srs_plugin_t *plugin, srs_cfg_t *settings)
194 static char cmdbuf[1024];
195 search_t *sch = (search_t *)plugin->plugin_data;
196 srs_context_t *srs = plugin->srs;
197 srs_cfg_t *cfg = srs->settings;
198 const char *dict, *cmd;
202 mrp_debug("configure search plugin");
204 dict = srs_get_string_config(cfg, "search.dictionary", DICTIONARY);
205 cmd = srs_get_string_config(cfg, "search.command" , COMMAND);
207 q = (char *)cmd + strlen(cmd);
208 while (q > cmd && (*q == ' ' || *q == '\t'))
215 if ((q = strstr(cmd, "__url__")) == NULL) {
216 mrp_log_error("Invalid search command '%s', has no __url__ tag.", cmd);
224 n = snprintf(p, l, "%*.*s", n, n, cmd);
230 mrp_log_error("Invalid search command '%s', too long.", cmd);
234 n = snprintf(p, l, "%%s");
241 q += strlen("__url__");
242 n = snprintf(p, l, "%s%s", q, nobg ? "&" : "");
252 mrp_log_info("search plugin dictionary: '%s'", sch->dict);
253 mrp_log_info("search plugin command: '%s'", sch->cmd);
259 static int start_search(srs_plugin_t *plugin)
261 static srs_client_ops_t ops = {
262 .notify_focus = focus_cb,
263 .notify_command = command_cb
266 char cmd1[1024], cmd2[1024];
267 search_t *sch = plugin->plugin_data;
268 char *cmds[2]= { &cmd1[0], &cmd2[0] };
269 int ncmd = (int)MRP_ARRAY_SIZE(cmds);
270 srs_context_t *srs = plugin->srs;
273 const char *name, *appcls, *id;
275 mrp_debug("starting search plugin");
281 snprintf(cmd1, sizeof(cmd1), "search for __push_dict__(%s) *", sch->dict);
282 snprintf(cmd2, sizeof(cmd2), "google for __push_dict__(%s) *", sch->dict);
284 c = client_create(srs, SRS_CLIENT_TYPE_BUILTIN,
285 name, appcls, cmds, ncmd, id, &ops, sch);
293 client_request_focus(c, SRS_VOICE_FOCUS_SHARED);
299 static void stop_search(srs_plugin_t *plugin)
301 search_t *sch = (search_t *)plugin->plugin_data;
303 mrp_debug("stop search plugin");
305 client_destroy(sch->c);
312 static void destroy_search(srs_plugin_t *plugin)
314 srs_context_t *srs = plugin->srs;
315 search_t *sch = (search_t *)plugin->plugin_data;
317 mrp_debug("destroy search plugin");
323 SRS_DECLARE_PLUGIN(SEARCH_NAME, SEARCH_DESCR, SEARCH_AUTHORS, SEARCH_VERSION,
324 create_search, config_search, start_search, stop_search,