1 
2 /*
3  * Osmo - a handy personal organizer
4  *
5  * Copyright (C) 2007 Tomasz Maka <pasp@users.sourceforge.net>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20  */
21 
22 #include "utils.h"
23 #include "utils_gui.h"
24 #include "utils_time.h"
25 #include "utils_date.h"
26 #include "i18n.h"
27 #include "options_prefs.h"
28 
29 /*------------------------------------------------------------------------------*/
30 
31 gchar *
utl_text_with_tags_to_html(gchar * input_text)32 utl_text_with_tags_to_html (gchar *input_text)
33 {
34 const gchar *html_tags[] = {
35     "mark_color",   "<span style=\"background-color:#FFFF00;\">",
36     "bold",         "<span style=\"font-weight: bold;\">",
37     "italic",       "<span style=\"font-style: italic;\">",
38     "underline",    "<span style=\"text-decoration:underline;\">",
39     "strike",       "<span style=\"text-decoration:line-through;\">"
40 };
41 guint n_pairs = G_N_ELEMENTS (html_tags) / 2;
42 gchar *output = g_strdup ("");
43 gunichar TAG_CHAR = TAG;      /* Unicode chars in the Private Use Area. */
44 gchar tag_char_utf8[7] = {0};
45 gchar **tokens, *o_links_1_text, *o_links_2_text;
46 gint count, i;
47 
48     g_unichar_to_utf8 (TAG_CHAR, tag_char_utf8);
49 
50     tokens = g_strsplit (input_text, tag_char_utf8, 0);
51 
52     for (count = 0; tokens[count]; count++)
53     {
54         if (count % 2 == 0) {     /* normal text */
55             output = utl_strconcat (output, tokens[count], NULL);
56         } else {
57             if (tokens[count][0] != '/') {   /* opening tag */
58                 for (i=0; i < n_pairs; i++) {
59                     if (!strcmp(html_tags[i*2+0], tokens[count])) {
60                         output = utl_strconcat (output, html_tags[i*2+1], NULL);
61                         break;
62                     }
63                 }
64             } else {
65                 /* closing tag */
66                 output = utl_strconcat (output, "</span>", NULL);
67             }
68         }
69     }
70 
71     g_strfreev (tokens);
72 
73     o_links_1_text = utl_text_replace (output, REGEX_URL, "<a href=\"\\0\">\\0</a>");
74     g_free (output);
75 
76     o_links_2_text = utl_text_replace (o_links_1_text, REGEX_EMAIL, "<a href=\"mailto:\\0\">\\0</a>");
77     g_free (o_links_1_text);
78 
79     return o_links_2_text;
80 }
81 
82 /*------------------------------------------------------------------------------*/
83 
84 gchar *
utl_text_replace(const gchar * text,const gchar * regex,const gchar * replacement)85 utl_text_replace (const gchar *text, const gchar *regex, const gchar *replacement)
86 {
87     GRegex *reg = g_regex_new (regex, G_REGEX_OPTIMIZE, 0, NULL);
88     gchar *buffer = g_regex_replace (reg, text, -1, 0, replacement, 0, NULL);
89     g_regex_unref (reg);
90 
91     return buffer;
92 }
93 
94 gboolean
utl_text_match(const gchar * text,const gchar * regex)95 utl_text_match (const gchar *text, const gchar *regex) {
96     GRegex *reg = g_regex_new (regex, G_REGEX_OPTIMIZE, 0, NULL);
97     gboolean matched = g_regex_match (reg, text, 0, NULL);
98     g_regex_unref (reg);
99 
100     return matched;
101 }
102 
103 /*------------------------------------------------------------------------------*/
104 
105 #ifdef HAVE_LIBWEBKIT
106 
107 gboolean
utl_webkit_on_menu(WebKitWebView * web_view,WebKitContextMenu * context_menu,GdkEvent * event,WebKitHitTestResult * hit_test_result,gpointer user_data)108 utl_webkit_on_menu (WebKitWebView       *web_view,
109                WebKitContextMenu   *context_menu,
110                GdkEvent            *event,
111                WebKitHitTestResult *hit_test_result,
112                gpointer             user_data) {
113     /* don't show popup menus */
114     return TRUE;
115 }
116 
117 gboolean
utl_webkit_link_clicked(WebKitWebView * web_view,WebKitPolicyDecision * decision,WebKitPolicyDecisionType decision_type,gpointer user_data)118 utl_webkit_link_clicked(WebKitWebView *web_view,
119         WebKitPolicyDecision *decision,
120         WebKitPolicyDecisionType decision_type,
121         gpointer user_data) {
122     WebKitNavigationPolicyDecision *navigation_decision;
123     WebKitNavigationAction * navigation_action;
124     WebKitNavigationType navigation_type;
125     WebKitURIRequest *request;
126     const gchar *uri;
127 
128 
129     g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(web_view), FALSE);
130     if (decision_type != WEBKIT_POLICY_DECISION_TYPE_NAVIGATION_ACTION) {
131         return FALSE;
132     }
133 
134     navigation_decision = WEBKIT_NAVIGATION_POLICY_DECISION(decision);
135     navigation_action = webkit_navigation_policy_decision_get_navigation_action(navigation_decision);
136     navigation_type = webkit_navigation_action_get_navigation_type(navigation_action);
137     if (navigation_type != WEBKIT_NAVIGATION_TYPE_LINK_CLICKED) {
138         return FALSE;
139     }
140     request = webkit_navigation_action_get_request (navigation_action);
141     uri = webkit_uri_request_get_uri(request);
142     webkit_policy_decision_ignore(decision);
143 
144     utl_run_helper((gchar *) uri, utl_get_link_type((gchar *) uri));
145 
146     return FALSE;
147 }
148 
149 #endif  /* HAVE_LIBWEBKIT */
150 
151 /*------------------------------------------------------------------------------*/
152 
153 gchar *
utl_text_to_html_page(const gchar * text,const gchar * font_family,const gchar * background_color,const gchar * text_color,const gchar * header_html,const gchar * top_html,const gchar * bottom_html)154 utl_text_to_html_page (const gchar *text, const gchar *font_family,
155                        const gchar *background_color, const gchar *text_color,
156                        const gchar *header_html, const gchar *top_html, const gchar *bottom_html)
157 {
158 gunichar TAG_CHAR = TAG;      /* Unicode chars in the Private Use Area. */
159 gchar *output = g_strdup ("");
160 gchar tag_char_utf8[7] = {0};
161 gchar **tokens, *itext, *o_links_1_text, *o_links_2_text;
162 gint count, i;
163 const gchar *html_tags[] = {
164     "mark_color",   "<span style=\"background-color:#FFFF00;\">",
165     "bold",         "<span style=\"font-weight: bold;\">",
166     "italic",       "<span style=\"font-style: italic;\">",
167     "underline",    "<span style=\"text-decoration:underline;\">",
168     "strike",       "<span style=\"text-decoration:line-through;\">"
169 };
170 guint n_pairs = G_N_ELEMENTS (html_tags) / 2;
171 
172     g_unichar_to_utf8 (TAG_CHAR, tag_char_utf8);
173 
174     itext = utl_text_to_html (text, FALSE, TRUE);
175 
176     output = utl_strconcat (output, "<html><head>", NULL);
177     output = utl_strconcat (output, "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />", NULL);
178     output = utl_strconcat (output, "<style type=\"text/css\">", NULL);
179     output = utl_strconcat (output, "body {", NULL);
180 
181     if (background_color != NULL) {
182         output = utl_strconcat (output, "background-color: ", background_color, "; ", NULL);
183     }
184     if (text_color != NULL) {
185         output = utl_strconcat (output, "text-color: ", text_color, "; ", NULL);
186     }
187     if (font_family != NULL) {
188         output = utl_strconcat (output, "font-family: ", font_family, "; ", NULL);
189     }
190 
191     output = utl_strconcat (output, "line-height: 145\%; ", NULL);
192     output = utl_strconcat (output, "} </style>", NULL);
193 
194     if (header_html != NULL) {
195         output = utl_strconcat (output, header_html, NULL);
196     }
197     output = utl_strconcat (output, "</head><body>", NULL);
198 
199     if (top_html != NULL) {
200         output = utl_strconcat (output, top_html, NULL);
201     }
202 
203     output = utl_strconcat (output, "<span style=\"white-space: pre-wrap;\">", NULL);
204 
205     tokens = g_strsplit (itext, tag_char_utf8, 0);
206     g_free (itext);
207 
208     for (count = 0; tokens[count]; count++)
209     {
210         if (count % 2 == 0) {     /* normal text */
211             output = utl_strconcat (output, tokens[count], NULL);
212         } else {
213             if (tokens[count][0] != '/') {   /* opening tag */
214                 for (i=0; i < n_pairs; i++) {
215                     if (!strcmp(html_tags[i*2+0], tokens[count])) {
216                         output = utl_strconcat (output, html_tags[i*2+1], NULL);
217                         break;
218                     }
219                 }
220             } else {
221                 /* closing tag */
222                 output = utl_strconcat (output, "</span>", NULL);
223             }
224         }
225     }
226 
227     g_strfreev (tokens);
228 
229     output = utl_strconcat (output, "</span>", NULL);
230 
231     if (bottom_html != NULL) {
232         output = utl_strconcat (output, bottom_html, NULL);
233     }
234 
235     output = utl_strconcat (output, "</body></html>", NULL);
236 
237     o_links_1_text = utl_text_replace (output, REGEX_URL, "<a href=\"\\0\">\\0</a>");
238     g_free (output);
239 
240     o_links_2_text = utl_text_replace (o_links_1_text, REGEX_EMAIL, "<a href=\"mailto:\\0\">\\0</a>");
241     g_free (o_links_1_text);
242 
243     return o_links_2_text;
244 }
245 
246 /*------------------------------------------------------------------------------*/
247 
248 gchar *
utl_text_to_html(const gchar * text,gboolean ignoreBR,gboolean ignoreSP)249 utl_text_to_html (const gchar *text,
250 				  gboolean ignoreBR,     /* ignore line breaks */
251 				  gboolean ignoreSP      /* ignore spaces */)
252 {
253 
254 const gchar *pairs[] = {
255     "&",    "&amp;",
256     "\"",   "&quot;",
257     "<",    "&lt;",
258     ">",    "&gt;"
259 };
260 
261 GRegex *reg;
262 gint i = 0;
263 gchar *buffer = NULL, *temp = NULL;
264 guint n_pairs = G_N_ELEMENTS (pairs) / 2;
265 
266     temp = g_strdup(text);
267 
268     for (i=0; i < n_pairs; i++) {
269         reg = g_regex_new (pairs[i*2+0], 0, 0, NULL);
270         buffer = g_regex_replace_literal (reg, temp, -1, 0, pairs[i*2+1], 0, NULL);
271         g_free (temp);
272         temp = buffer;
273         g_regex_unref (reg);
274     }
275 
276 	if (ignoreBR == FALSE) {
277         reg = g_regex_new ("\\n", 0, 0, NULL);
278         buffer = g_regex_replace_literal (reg, temp, -1, 0, "<br />", 0, NULL);
279         g_free (temp);
280         temp = buffer;
281         g_regex_unref (reg);
282 	}
283 
284 	if (ignoreSP == FALSE) {
285         reg = g_regex_new (" ", 0, 0, NULL);
286         buffer = g_regex_replace_literal (reg, temp, -1, 0, "%20", 0, NULL);
287         g_free (temp);
288         temp = buffer;
289         g_regex_unref (reg);
290 	}
291 
292     return temp;
293 }
294 
295 /*------------------------------------------------------------------------------*/
296 
297 gchar *
utl_get_day_name(guint day,gboolean short_name)298 utl_get_day_name (guint day, gboolean short_name)
299 {
300     static gchar buffer[BUFFER_SIZE];
301     GDate *tmpdate = NULL;
302 
303     g_return_val_if_fail (day > 0 && day <= 31, buffer);
304 
305     tmpdate = g_date_new_dmy (day, 1, 2007);
306     g_return_val_if_fail (tmpdate != NULL, buffer);
307 
308     g_date_strftime (buffer, BUFFER_SIZE, short_name ? "%a" : "%A", tmpdate);
309     g_date_free (tmpdate);
310 
311     return buffer;
312 }
313 
314 /*------------------------------------------------------------------------------*/
315 
316 gchar *
utl_get_julian_day_name(guint32 julian)317 utl_get_julian_day_name (guint32 julian)
318 {
319     static gchar buffer[BUFFER_SIZE];
320     GDate *tmpdate = NULL;
321 
322     buffer[0] = '\0';
323     g_return_val_if_fail (g_date_valid_julian (julian) == TRUE, buffer);
324 
325     tmpdate = g_date_new_julian (julian);
326     g_return_val_if_fail (tmpdate != NULL, buffer);
327 
328     g_date_strftime (buffer, BUFFER_SIZE, "%A", tmpdate);
329     g_date_free (tmpdate);
330 
331     return buffer;
332 }
333 
334 /*------------------------------------------------------------------------------*/
335 
336 gchar *
utl_get_date_name(const GDate * date)337 utl_get_date_name (const GDate *date)
338 {
339     static gchar buffer[BUFFER_SIZE];
340 
341     g_date_strftime (buffer, BUFFER_SIZE, "%e %B %Y", date);     /* e.g. 1 August 1999 */
342     return buffer;
343 }
344 
345 /*------------------------------------------------------------------------------*/
346 
347 gchar *
utl_get_date_name_format(const GDate * date,gchar * fmt)348 utl_get_date_name_format (const GDate *date, gchar *fmt)
349 {
350     static gchar buffer[BUFFER_SIZE];
351 
352     g_date_strftime (buffer, BUFFER_SIZE, fmt, date);
353     return buffer;
354 }
355 
356 /*------------------------------------------------------------------------------*/
357 
358 guint
utl_get_weekend_days_in_month(const GDate * date)359 utl_get_weekend_days_in_month (const GDate *date)
360 {
361     GDate *tmpdate = NULL;
362     guint i, day, days, weekend_days;
363 
364     tmpdate = g_date_new_dmy (1, g_date_get_month (date), g_date_get_year (date));
365     g_return_val_if_fail (tmpdate != NULL, 0);
366 
367     days = utl_date_get_days_in_month (tmpdate);
368     weekend_days = 0;
369 
370     for (i = 1; i <= days; i++) {
371         g_date_set_day (tmpdate, i);
372         day = g_date_get_weekday (tmpdate);
373         if (day == G_DATE_SATURDAY || day == G_DATE_SUNDAY) {
374             weekend_days++;
375         }
376     }
377 
378     g_date_free (tmpdate);
379     return weekend_days;
380 }
381 
382 /*------------------------------------------------------------------------------*/
383 
384 guint
utl_get_weekend_days_in_month_my(guint month,guint year)385 utl_get_weekend_days_in_month_my (guint month, guint year)
386 {
387     GDate *tmpdate = NULL;
388     guint i, day, days, weekend_days;
389 
390     g_return_val_if_fail (g_date_valid_dmy (1, month, year) == TRUE, 0);
391 
392     tmpdate = g_date_new_dmy (1, month, year);
393     g_return_val_if_fail (tmpdate != NULL, 0);
394 
395     days = utl_date_get_days_in_month (tmpdate);
396     weekend_days = 0;
397 
398     for (i = 1; i <= days; i++) {
399         g_date_set_day (tmpdate, i);
400         day = g_date_get_weekday (tmpdate);
401         if (day == G_DATE_SATURDAY || day == G_DATE_SUNDAY) {
402             weekend_days++;
403         }
404     }
405 
406     g_date_free (tmpdate);
407     return weekend_days;
408 }
409 
410 /*------------------------------------------------------------------------------*/
411 
412 guint
utl_get_days_per_year(guint year)413 utl_get_days_per_year (guint year)
414 {
415     return (g_date_is_leap_year (year) ? 366 : 365);
416 }
417 
418 /*------------------------------------------------------------------------------*/
419 
420 void
utl_subtract_from_date(guint32 date,gint time,gint days,gint seconds,guint32 * new_date,gint * new_time)421 utl_subtract_from_date (guint32 date, gint time, gint days, gint seconds, guint32 *new_date, gint *new_time)
422 {
423     *new_date = date - days;
424 
425     if (time >= 0) {
426         *new_time = time - seconds;
427 
428         if (*new_time < 0) {
429             *new_time = (*new_time) + 24 * 3600;
430             *new_date = (*new_date) - 1;
431         }
432     } else {
433         *new_time = -1;
434     }
435 }
436 
437 /*------------------------------------------------------------------------------*/
438 /*  This routine has been taken from http://www.voidware.com/moon_phase.htm
439     calculates the moon phase (0-7), accurate to 1 segment: 0 = > new moon, 4 => full moon.
440 */
441 
442 gint
utl_calc_moon_phase(const GDate * date)443 utl_calc_moon_phase (const GDate *date)
444 {
445     gdouble jd;
446     gint day, month, year;
447     gint b, c, e;
448 
449     utl_date_get_dmy (date, &day, &month, &year);
450 
451     if (month < 3) {
452         year--;
453         month += 12;
454     }
455     month++;
456     c = 365.25 * year;
457     e = 30.6 * month;
458     jd = c + e + day - 694039.09;   /* jd is total days elapsed */
459     jd /= 29.53;                    /* divide by the moon cycle (29.53 days) */
460     b = jd;                         /* int(jd) -> b, take integer part of jd */
461     jd -= b;                        /* subtract integer part to leave fractional part of original jd */
462     b = jd * 8 + 0.5;               /* scale fraction from 0-8 and round by adding 0.5 */
463     b = b & 7;                      /* 0 and 8 are the same so turn 8 into 0 */
464 
465     return b;
466 }
467 
468 /*------------------------------------------------------------------------------*/
469 
470 gchar*
utl_get_moon_phase_name(gint phase)471 utl_get_moon_phase_name (gint phase)
472 {
473     const gchar *phase_names[] = {
474         N_("New Moon"), N_("Waxing Crescent Moon"), N_("Quarter Moon"), N_("Waxing Gibbous Moon"),
475         N_("Full Moon"), N_("Waning Gibbous Moon"), N_("Last Quarter Moon"), N_("Waning Crescent Moon")
476     };
477 
478     return (gchar *) gettext (phase_names[phase]);
479 }
480 
481 /*------------------------------------------------------------------------------*/
482 
483 void
utl_name_strcat(gchar * first,gchar * second,gchar * buffer)484 utl_name_strcat (gchar *first, gchar *second, gchar *buffer)
485 {
486     gchar tmpbuff[BUFFER_SIZE];
487     gboolean flag;
488 
489     buffer[0] = '\0';
490     g_return_if_fail (first != NULL || second != NULL);
491 
492     g_snprintf (tmpbuff, BUFFER_SIZE, "(%s)", _("None"));
493     flag = FALSE;
494 
495     if (first != NULL) {
496 
497         if (strcmp (first, tmpbuff) != 0) {
498             flag = TRUE;
499             g_strlcpy (buffer, first, BUFFER_SIZE);
500         }
501 
502         g_free (first);
503     }
504 
505     if (second != NULL) {
506 
507         if (strcmp (second, tmpbuff) != 0) {
508             if (flag == TRUE) {
509                 g_strlcat (buffer, " ", BUFFER_SIZE);
510                 g_strlcat (buffer, second, BUFFER_SIZE);
511             } else {
512                 g_strlcpy (buffer, second, BUFFER_SIZE);
513             }
514         }
515 
516         g_free (second);
517     }
518 
519     g_return_if_fail (strlen (buffer) > 0);
520 }
521 
522 /*------------------------------------------------------------------------------*/
523 
524 void
utl_xml_get_int(gchar * name,gint * iname,xmlNodePtr node)525 utl_xml_get_int (gchar *name, gint *iname, xmlNodePtr node)
526 {
527     xmlChar *key;
528 
529     if ((xmlStrcmp (node->name, (const xmlChar *) name)) == 0) {
530         key = xmlNodeGetContent (node->xmlChildrenNode);
531         if (key != NULL) {
532             *iname = atoi ((gchar *) key);
533             xmlFree (key);
534         }
535     }
536 }
537 
538 /*------------------------------------------------------------------------------*/
539 
540 void
utl_xml_get_uint(gchar * name,guint * uname,xmlNodePtr node)541 utl_xml_get_uint (gchar *name, guint *uname, xmlNodePtr node)
542 {
543     xmlChar *key;
544 
545     if ((xmlStrcmp (node->name, (const xmlChar *) name)) == 0) {
546         key = xmlNodeGetContent (node->xmlChildrenNode);
547         if (key != NULL) {
548             *uname = (guint) atoi ((gchar *) key);
549             xmlFree (key);
550         }
551     }
552 }
553 
554 /*------------------------------------------------------------------------------*/
555 
556 void
utl_xml_get_char(gchar * name,gchar * cname,xmlNodePtr node)557 utl_xml_get_char (gchar *name, gchar *cname, xmlNodePtr node)
558 {
559     xmlChar *key;
560 
561     if ((xmlStrcmp (node->name, (const xmlChar *) name)) == 0) {
562         key = xmlNodeGetContent (node->xmlChildrenNode);
563         if (key != NULL) {
564             *cname = key[0];
565             xmlFree (key);
566         }
567     }
568 }
569 
570 /*------------------------------------------------------------------------------*/
571 
572 void
utl_xml_get_str(gchar * name,gchar ** sname,xmlNodePtr node)573 utl_xml_get_str (gchar *name, gchar **sname, xmlNodePtr node)
574 {
575     xmlChar *key;
576 
577     if ((xmlStrcmp (node->name, (const xmlChar *) name)) == 0) {
578 
579         key = xmlNodeGetContent (node->xmlChildrenNode);
580 
581         if (key != NULL) {
582             *sname = g_strdup ((gchar *) key);
583             xmlFree (key);
584         }
585     }
586 }
587 
588 /*------------------------------------------------------------------------------*/
589 
590 void
utl_xml_get_strn(gchar * name,gchar * sname,gint buffer_size,xmlNodePtr node)591 utl_xml_get_strn (gchar *name, gchar *sname, gint buffer_size, xmlNodePtr node)
592 {
593     xmlChar *key;
594 
595     if ((xmlStrcmp (node->name, (const xmlChar *) name)) == 0) {
596 
597         key = xmlNodeGetContent (node->xmlChildrenNode);
598 
599         if (key != NULL) {
600             g_strlcpy (sname, (gchar *) key, buffer_size);
601             xmlFree (key);
602         }
603     }
604 }
605 
606 /*------------------------------------------------------------------------------*/
607 
608 void
utl_xml_put_int(gchar * name,gint value,xmlNodePtr node)609 utl_xml_put_int (gchar *name, gint value, xmlNodePtr node)
610 {
611 gchar buffer[32];
612 
613     g_snprintf (buffer, 32, "%d", value);
614     xmlNewChild (node, NULL, (const xmlChar *) name, (xmlChar *) buffer);
615 }
616 
617 /*------------------------------------------------------------------------------*/
618 
619 void
utl_xml_put_uint(gchar * name,guint value,xmlNodePtr node)620 utl_xml_put_uint (gchar *name, guint value, xmlNodePtr node)
621 {
622 gchar buffer[32];
623 
624     g_snprintf (buffer, 32, "%d", value);
625     xmlNewChild (node, NULL, (const xmlChar *) name, (xmlChar *) buffer);
626 }
627 
628 /*------------------------------------------------------------------------------*/
629 
630 void
utl_xml_put_char(gchar * name,gchar character,xmlNodePtr node)631 utl_xml_put_char (gchar *name, gchar character, xmlNodePtr node)
632 {
633     gchar buffer[32];
634 
635     g_snprintf (buffer, 32, "%c", character);
636     xmlNewTextChild (node, NULL, (const xmlChar *) name, (xmlChar *) buffer);
637 }
638 
639 /*------------------------------------------------------------------------------*/
640 
641 void
utl_xml_put_str(gchar * name,gchar * string,xmlNodePtr node)642 utl_xml_put_str (gchar *name, gchar *string, xmlNodePtr node)
643 {
644     xmlNewTextChild (node, NULL, (const xmlChar *) name, (xmlChar *) string);
645 }
646 
647 /*------------------------------------------------------------------------------*/
648 
649 void
utl_xml_put_strn(gchar * name,gchar * string,gint buffer_size,xmlNodePtr node)650 utl_xml_put_strn (gchar *name, gchar *string, gint buffer_size, xmlNodePtr node)
651 {
652     gchar buffer[BUFFER_SIZE];
653 
654     if (buffer_size > BUFFER_SIZE) buffer_size = BUFFER_SIZE;
655     g_snprintf (buffer, buffer_size, "%s", string);
656     xmlNewTextChild (node, NULL, (const xmlChar *) name, (xmlChar *) buffer);
657 }
658 /*------------------------------------------------------------------------------*/
659 void
utl_xml_write_doc(const char * filename,xmlDocPtr doc)660 utl_xml_write_doc(const char *filename, xmlDocPtr doc) {
661     gchar *tmp_filename = g_strconcat(filename, ".tmp", NULL);
662 
663     if (xmlSaveFormatFileEnc(tmp_filename, doc, "utf-8", 1) == -1) {
664         g_warning("Failed to write a file %s", filename);
665     } else if (g_rename(tmp_filename, filename) == -1) {
666         g_warning("Failed to replace the written file %s", filename);
667     }
668 
669     g_free(tmp_filename);
670 }
671 
672 /*------------------------------------------------------------------------------*/
673 
674 gboolean
utl_is_valid_command(gchar * command)675 utl_is_valid_command (gchar *command) {
676 
677 gchar *found_path;
678 
679     found_path = g_find_program_in_path (command);
680 
681     if (found_path != NULL) {
682         g_free (found_path);
683         return TRUE;
684     }
685 
686     return FALSE;
687 }
688 
689 /*------------------------------------------------------------------------------*/
690 
691 void
utl_run_command(gchar * command,gboolean sync)692 utl_run_command (gchar *command, gboolean sync) {
693 GError *err = NULL;
694 gchar *cmdline[4];
695 
696     cmdline[0] = "sh";
697     cmdline[1] = "-c";
698     cmdline[2] = command;
699     cmdline[3] = 0;
700 
701     if (sync == FALSE) {
702         g_spawn_async (NULL, (gchar **)cmdline, NULL, G_SPAWN_SEARCH_PATH | G_SPAWN_STDOUT_TO_DEV_NULL,
703                        NULL, NULL, NULL, &err);
704     } else {
705         g_spawn_sync (NULL, (gchar **)cmdline, NULL, G_SPAWN_SEARCH_PATH | G_SPAWN_STDOUT_TO_DEV_NULL,
706                       NULL, NULL, NULL, NULL, NULL, &err);
707     }
708     if(err) {
709         fprintf(stderr, "Failed to execute command %s: %s", command, err->message);
710         g_error_free (err);
711     }
712 }
713 
714 /*------------------------------------------------------------------------------*/
715 
716 gboolean
utl_run_helper(gchar * parameter,gint helper)717 utl_run_helper (gchar *parameter, gint helper) {
718 
719 gchar command[PATH_MAX], quoted[PATH_MAX];
720 gboolean sync = FALSE;
721 
722     g_snprintf(quoted, PATH_MAX, "\"%s\"", parameter);
723 
724     if (helper == EMAIL) {
725         g_snprintf(command, PATH_MAX, config.email_client, quoted);
726     } else if (helper == WWW) {
727         g_snprintf(command, PATH_MAX, config.web_browser, quoted);
728     } else if (helper == SOUND) {
729         g_snprintf(command, PATH_MAX, config.sound_player, quoted);
730         sync = TRUE;
731     } else {
732         return FALSE;
733     }
734 
735     utl_run_command (command, sync);
736 
737     return TRUE;
738 }
739 
740 /*------------------------------------------------------------------------------*/
741 
742 gint
utl_get_link_type(gchar * link)743 utl_get_link_type (gchar *link)
744 {
745     gint i, n, d;
746 
747     g_return_val_if_fail (link != NULL, UNKNOWN);
748 
749     for (i = n = d = 0; i < strlen (link); i++) {
750         if (link[i] == '@') n++;
751         if (link[i] == '.') d++;
752     }
753 
754     if (!strncasecmp (link, "https://", 8) || !strncasecmp (link, "http://", 7) || !strncasecmp(link, "www", 3)) {
755         return WWW;
756     } else if (n == 1) {
757         return EMAIL;
758     } else if (n == 0 && d >= 1) {
759         return WWW;
760     } else {
761         return UNKNOWN;
762     }
763 }
764 
765 /*------------------------------------------------------------------------------*/
766 
767 void
utl_cairo_draw(cairo_t * cr,gint stroke)768 utl_cairo_draw (cairo_t *cr, gint stroke)
769 {
770     if (stroke) {
771         cairo_set_line_width (cr, stroke);
772         cairo_stroke (cr);
773     } else {
774         cairo_fill (cr);
775     }
776 }
777 
778 /*------------------------------------------------------------------------------*/
779 
780 void
utl_draw_rounded_rectangle(cairo_t * cr,gint x,gint y,gint w,gint h,gint a,gint s)781 utl_draw_rounded_rectangle (cairo_t *cr, gint x, gint y, gint w, gint h, gint a, gint s)
782 {
783     cairo_move_to (cr, x + a + s, y + s);
784     cairo_line_to (cr, x + w - a - s, y + s);
785     cairo_arc (cr, x + w - a - s, y + a + s, a, 1.5 * M_PI, 2.0 * M_PI);
786     cairo_line_to (cr, x + w - s, y + h - a - s);
787     cairo_arc (cr, x + w - a - s, y + h - a - s, a, 0.0 * M_PI, 0.5 * M_PI);
788     cairo_line_to (cr, x + a + s, y + h - s);
789     cairo_arc (cr, x + a + s, y + h - a - s, a, 0.5 * M_PI, 1.0 * M_PI);
790     cairo_line_to (cr, x + s, y + a + s);
791     cairo_arc (cr, x + a + s, y + a + s, a, 1.0 * M_PI, 1.5 * M_PI);
792 }
793 
794 /*------------------------------------------------------------------------------*/
795 
796 void
utl_draw_left_arrow(cairo_t * cr,gdouble x,gdouble y,gdouble w,gdouble h,gdouble a)797 utl_draw_left_arrow (cairo_t *cr, gdouble x, gdouble y, gdouble w, gdouble h, gdouble a)
798 {
799     cairo_move_to (cr, x, y);
800     cairo_line_to (cr, x + w * a, y + h * 0.50);
801     cairo_line_to (cr, x + w * a, y + h * 0.25);
802     cairo_line_to (cr, x + w * 1, y + h * 0.25);
803     cairo_line_to (cr, x + w * 1, y - h * 0.25);
804     cairo_line_to (cr, x + w * a, y - h * 0.25);
805     cairo_line_to (cr, x + w * a, y - h * 0.50);
806     cairo_close_path (cr);
807 }
808 
809 /*------------------------------------------------------------------------------*/
810 
811 gpointer
utl_snd_play_thread(gpointer * data)812 utl_snd_play_thread (gpointer *data) {
813 
814 gchar sound_filename[PATH_MAX];
815 gint i;
816 
817     g_snprintf (sound_filename, PATH_MAX, "%s%c%s%c%s", SOUNDSDIR, G_DIR_SEPARATOR, "osmo",
818                 G_DIR_SEPARATOR, "alarm.wav");
819 
820     for (i=0; i < (size_t) data; i++) {
821         utl_run_helper (sound_filename, SOUND);
822     }
823 
824     return NULL;
825 }
826 
827 
828 void
utl_play_alarm_sound(guint repetitions)829 utl_play_alarm_sound (guint repetitions)
830 {
831     GThread *thread;
832 	if (repetitions == 0)
833 		return;
834 
835     thread = g_thread_try_new ("osmo", (GThreadFunc) utl_snd_play_thread, (gpointer) ((size_t) repetitions), NULL);
836     if(thread) {
837         g_thread_unref(thread);
838     }
839 }
840 
841 /*------------------------------------------------------------------------------*/
842 
843 gchar*
utl_add_timestamp_to_filename(gchar * filename,gchar * extension)844 utl_add_timestamp_to_filename (gchar *filename, gchar *extension) {
845 
846 static gchar filename_buffer[BUFFER_SIZE];
847 
848     g_snprintf (filename_buffer, BUFFER_SIZE, "%s-%4d%02d%02d%02d%02d.%s",
849                 filename,
850                 utl_date_get_current_year(), utl_date_get_current_month(), utl_date_get_current_day(),
851                 utl_time_get_current_hour(), utl_time_get_current_minute(),
852                 extension);
853 
854     return filename_buffer;
855 }
856 
857 /*------------------------------------------------------------------------------*/
858 
859 gchar *
utl_strconcat(gchar * string,...)860 utl_strconcat (gchar *string, ...) {
861 
862 gchar *tmp_holder, *tmp_str;
863 va_list arguments;
864 
865     va_start (arguments, string);
866 
867     while ((tmp_str = va_arg (arguments, gchar *)) != NULL) {
868         tmp_holder = string;
869         string = g_strconcat (tmp_holder, tmp_str, NULL);
870         g_free (tmp_holder);
871     }
872 
873     va_end (arguments);
874 
875     return string;
876 }
877 
878 /*------------------------------------------------------------------------------*/
879 
880 gint
utl_text_strcmp(const gchar * string1,const gchar * string2)881 utl_text_strcmp (const gchar *string1, const gchar *string2) {
882     if (string1 == NULL && string2 == NULL) {
883         return 0;
884     } if (string1 == NULL) {
885         return -1;
886     } else if (string2 == NULL) {
887         return 1;
888     } else {
889         return g_utf8_collate(string1, string2);
890     }
891 }
892 
893 /*------------------------------------------------------------------------------*/
894 
895 static gboolean
find_substring(const gchar * haystack,const gchar * needle,gboolean case_sensitive)896 find_substring(const gchar *haystack, const gchar *needle, gboolean case_sensitive) {
897     gint window_len, text_len, i, diff;
898     gchar *window_start, *window_end, *casefold1, *casefold2;
899 
900     window_len = g_utf8_strlen(needle, -1);
901     if (window_len == 0) {
902         return TRUE;
903     }
904     text_len = g_utf8_strlen(haystack, -1);
905     if (text_len == 0) {
906         return FALSE;
907     }
908     if(case_sensitive == TRUE) {
909         casefold1 = g_strdup(needle);
910     } else {
911         casefold1 = g_utf8_casefold(needle, -1);
912     }
913     for (i = 0; i <= text_len - window_len; i++) {
914         window_start = g_utf8_offset_to_pointer(haystack, i);
915         window_end = g_utf8_offset_to_pointer(haystack, i + window_len);
916         if(case_sensitive == TRUE) {
917             casefold2 = g_strndup(window_start, window_end - window_start);
918         } else {
919             casefold2 = g_utf8_casefold(window_start, window_end - window_start);
920         }
921         diff = g_utf8_collate(casefold1, casefold2);
922         g_free(casefold2);
923         if (!diff) {
924             g_free(casefold1);
925             return TRUE;
926         }
927     }
928     g_free(casefold1);
929     return FALSE;
930 }
931 
932 /*------------------------------------------------------------------------------*/
933 
934 gboolean
utl_text_strcasestr(const gchar * haystack,const gchar * needle)935 utl_text_strcasestr(const gchar *haystack, const gchar *needle) {
936     return find_substring(haystack, needle, FALSE);
937 }
938 
939 /*------------------------------------------------------------------------------*/
940 
941 gboolean
utl_text_strstr(const gchar * haystack,const gchar * needle)942 utl_text_strstr(const gchar *haystack, const gchar *needle) {
943     return find_substring(haystack, needle, TRUE);
944 }
945 
946 /*------------------------------------------------------------------------------*/
947 
948 void
utl_free_list(GList * list,GDestroyNotify free_func)949 utl_free_list (GList *list, GDestroyNotify free_func) {
950 #if GLIB_CHECK_VERSION(2, 28, 0)
951     g_list_free_full(list, free_func);
952 #else
953     GList *l;
954     for (l = list; l; l = l->next) {
955         free_func(l->data);
956     }
957     g_list_free(list);
958 #endif
959 }
960 
961 /*------------------------------------------------------------------------------*/
962 #ifdef HAVE_LIBWEBKIT
963 WebKitWebView *
utl_create_webkit_web_view(GUI * appGUI)964 utl_create_webkit_web_view(GUI *appGUI) {
965     WebKitSettings *settings;
966     WebKitWebView *view;
967     WebKitUserContentManager *manager;
968     WebKitUserStyleSheet *stylesheet;
969     settings = webkit_settings_new();
970 
971     manager = webkit_user_content_manager_new();
972     if (appGUI->stylesheet) {
973         stylesheet = webkit_user_style_sheet_new(appGUI->stylesheet, WEBKIT_USER_CONTENT_INJECT_ALL_FRAMES, WEBKIT_USER_STYLE_LEVEL_USER, NULL, NULL);
974         webkit_user_content_manager_add_style_sheet(manager, stylesheet);
975     }
976 
977     webkit_settings_set_enable_javascript(settings, FALSE);
978     webkit_settings_set_enable_plugins(settings, FALSE);
979     webkit_settings_set_enable_java(settings, FALSE);
980 
981     view = WEBKIT_WEB_VIEW(webkit_web_view_new_with_user_content_manager(manager));
982     webkit_web_view_set_settings(view, settings);
983     webkit_web_view_set_editable(view, FALSE);
984     return view;
985 }
986 #endif  /* HAVE_LIBWEBKIT */
987 
988 /*------------------------------------------------------------------------------*/
989 
990 gint
991 /*utl_open_count_url_links (gchar *text, gint *tsize, gboolean url_count) {*/
utl_open_count_url_links(gchar * text,gboolean url_count)992 utl_open_count_url_links (gchar *text, gboolean url_count) {
993 
994 GRegex *regex = NULL;
995 GMatchInfo *match_info = NULL;
996 gchar url_path[PATH_MAX], command[PATH_MAX];
997 gchar *URL = NULL, *qURL = NULL;
998 gint k = 0, tsize;
999 
1000 	regex = g_regex_new (REGEX_URL, 0, 0, NULL);
1001 	g_regex_match (regex, text, 0, &match_info);
1002 
1003     url_path[0] = '\0';
1004 	tsize = strlen(config.web_browser);
1005 
1006 	while (g_match_info_matches (match_info)) {
1007 
1008 	  	URL = g_match_info_fetch (match_info, 0);
1009 		qURL = g_shell_quote (URL);
1010 		if (url_count == FALSE) {
1011 			if (tsize + strlen(qURL) < PATH_MAX) {
1012 				tsize += strlen(qURL) + 1 /* space */;
1013 				strcat (url_path, qURL);
1014 				strcat (url_path, " ");
1015 				k++;
1016 			}
1017 		} else {
1018 			tsize += strlen(qURL) + 1 /* space */;
1019 			k++;
1020 		}
1021 		g_free (qURL);
1022 		g_free (URL);
1023 		g_match_info_next (match_info, NULL);
1024 	}
1025 
1026 	if (url_count == FALSE) {
1027         g_snprintf(command, PATH_MAX, config.web_browser, url_path);
1028         utl_run_command (command, FALSE);
1029     }
1030 
1031 	g_match_info_free (match_info);
1032 	g_regex_unref (regex);
1033 
1034 	return k;
1035 }
1036 
1037 /*------------------------------------------------------------------------------*/
1038 
1039