70
70
static char *custom_user_dir = NULL;
71
static char *home_dir = NULL;
71
static char *user_dir = NULL;
74
75
purple_menu_action_new(const char *label, PurpleCallback callback, gpointer data,
96
purple_util_init(void)
98
/* This does nothing right now. It exists for symmetry with
99
* purple_util_uninit() and forwards compatibility. */
103
purple_util_uninit(void)
105
/* Free these so we don't have leaks at shutdown. */
107
g_free(custom_user_dir);
108
custom_user_dir = NULL;
94
114
/**************************************************************************
95
115
* Base16 Functions
96
116
**************************************************************************/
515
535
* Date/Time Functions
516
536
**************************************************************************/
519
static long win32_get_tz_offset() {
520
TIME_ZONE_INFORMATION tzi;
524
if ((ret = GetTimeZoneInformation(&tzi)) != TIME_ZONE_ID_INVALID)
526
off = -(tzi.Bias * 60);
527
if (ret == TIME_ZONE_ID_DAYLIGHT)
528
off -= tzi.DaylightBias * 60;
535
538
const char *purple_get_tzoff_str(const struct tm *tm, gboolean iso)
537
540
static char buf[7];
750
753
struct tm *tm, long *tz_off, const char **rest)
752
755
time_t retval = 0;
754
757
const char *c = timestamp;
756
759
long tzoff = PURPLE_NO_TZ_OFF;
759
t = localtime(&retval);
762
localtime_r(&retval, &t);
761
764
/* 4 digit year */
762
765
if (sscanf(c, "%04d", &year) && year > 1900)
767
t->tm_year = year - 1900;
770
t.tm_year = year - 1900;
770
773
/* 2 digit month */
771
if (!sscanf(c, "%02d", &t->tm_mon))
774
if (!sscanf(c, "%02d", &t.tm_mon))
773
776
if (rest != NULL && *c != '\0')
778
781
if (*c == '-' || *c == '/')
782
785
/* 2 digit day */
783
if (!sscanf(c, "%02d", &t->tm_mday))
786
if (!sscanf(c, "%02d", &t.tm_mday))
785
788
if (rest != NULL && *c != '\0')
794
if (!sscanf(c, "%04d", &t->tm_year))
797
if (!sscanf(c, "%04d", &t.tm_year))
796
799
if (rest != NULL && *c != '\0')
802
805
else if (*c == 'T' || *c == '.')
805
808
/* we have more than a date, keep going */
807
810
/* 2 digit hour */
808
if ((sscanf(c, "%02d:%02d:%02d", &t->tm_hour, &t->tm_min, &t->tm_sec) == 3 && (c = c + 8)) ||
809
(sscanf(c, "%02d%02d%02d", &t->tm_hour, &t->tm_min, &t->tm_sec) == 3 && (c = c + 6)))
811
if ((sscanf(c, "%02d:%02d:%02d", &t.tm_hour, &t.tm_min, &t.tm_sec) == 3 && (c = c + 8)) ||
812
(sscanf(c, "%02d%02d%02d", &t.tm_hour, &t.tm_min, &t.tm_sec) == 3 && (c = c + 6)))
811
814
gboolean offset_positive = FALSE;
817
if (*c == '.' && *(c+1) >= '0' && *(c+1) <= '9') /* dealing with precision we don't care about */
823
} while (*c >= '0' && *c <= '9'); /* dealing with precision we don't care about */
820
826
offset_positive = TRUE;
821
827
if (((*c == '+' || *c == '-') && (c = c + 1)) &&
828
834
/* We don't want the C library doing DST calculations
829
835
* if we know the UTC offset already. */
840
static struct tm tmptm;
843
/* we care about whether it *was* dst, and the offset, here on this
844
* date, not whether we are currently observing dst locally *now*.
845
* This isn't perfect, because we would need to know in advance the
846
* offset we are trying to work out in advance to be sure this
847
* works for times around dst transitions but it'll have to do. */
848
localtime_r(&tmp, &tmptm);
849
t.tm_isdst = tmptm.tm_isdst;
850
#ifdef HAVE_TM_GMTOFF
851
t.tm_gmtoff = tmptm.tm_gmtoff;
837
855
if (rest != NULL && *c != '\0')
1369
1387
g_string_append_printf(xhtml, "</%s>", pt->dest_tag);
1370
1388
if(plain && !strcmp(pt->src_tag, "a")) {
1371
1389
/* if this is a link, we have to add the url to the plaintext, too */
1372
if (cdata && url && !g_string_equal(cdata, url))
1391
(!g_string_equal(cdata, url) && (g_ascii_strncasecmp(url->str, "mailto:", 7) != 0 ||
1392
g_utf8_collate(url->str + 7, cdata->str) != 0)))
1373
1393
g_string_append_printf(plain, " <%s>", g_strstrip(url->str));
1375
1395
g_string_free(cdata, TRUE);
1550
1570
if(*q == '\'' || *q == '\"')
1552
1572
while(*q && *q != '\"' && *q != '\'' && *q != ' ') {
1553
url = g_string_append_c(url, *q);
1574
if ((*q == '&') && (purple_markup_unescape_entity(q, &len) == NULL))
1575
url = g_string_append(url, "&");
1577
url = g_string_append_c(url, *q);
1729
1753
xhtml = g_string_append_len(xhtml, c, len);
1731
1755
plain = g_string_append(plain, pln);
1757
cdata = g_string_append_len(cdata, c, len);
1754
1780
*plain_out = g_string_free(plain, FALSE);
1756
1782
g_string_free(url, TRUE);
1784
g_string_free(cdata, TRUE);
1759
1787
/* The following are probably reasonable changes:
2466
2494
if (custom_user_dir != NULL)
2467
2495
return custom_user_dir;
2469
home_dir = g_build_filename(purple_home_dir(), ".purple", NULL);
2497
user_dir = g_build_filename(purple_home_dir(), ".purple", NULL);
2474
2502
void purple_util_set_user_dir(const char *dir)
2524
2552
if (g_mkdir(dir, mode) < 0) {
2525
purple_debug_warning("build_dir", "mkdir: %s\n", strerror(errno));
2553
purple_debug_warning("build_dir", "mkdir: %s\n", g_strerror(errno));
2526
2554
g_strfreev(components);
2558
2586
if (g_mkdir(user_dir, S_IRUSR | S_IWUSR | S_IXUSR) == -1)
2560
2588
purple_debug_error("util", "Error creating directory %s: %s\n",
2561
user_dir, strerror(errno));
2589
user_dir, g_strerror(errno));
2594
2625
purple_debug_error("util", "Error removing old file "
2596
filename_temp, strerror(errno));
2627
filename_temp, g_strerror(errno));
2604
2635
purple_debug_error("util", "Error opening file %s for "
2605
2636
"writing: %s\n",
2606
filename_temp, strerror(errno));
2637
filename_temp, g_strerror(errno));
2607
2638
g_free(filename_temp);
2612
2643
real_size = (size == -1) ? strlen(data) : (size_t) size;
2613
2644
byteswritten = fwrite(data, 1, real_size, file);
2647
/* Apparently XFS (and possibly other filesystems) do not
2648
* guarantee that file data is flushed before file metadata,
2649
* so this procedure is insufficient without some flushage. */
2650
if (fflush(file) < 0) {
2651
purple_debug_error("util", "Error flushing %s: %s\n",
2652
filename_temp, g_strerror(errno));
2653
g_free(filename_temp);
2657
if (fsync(fileno(file)) < 0) {
2658
purple_debug_error("util", "Error syncing file contents for %s: %s\n",
2659
filename_temp, g_strerror(errno));
2660
g_free(filename_temp);
2615
2666
/* Close file */
2616
2667
if (fclose(file) != 0)
2618
2669
purple_debug_error("util", "Error closing file %s: %s\n",
2619
filename_temp, strerror(errno));
2620
g_free(filename_temp);
2670
filename_temp, g_strerror(errno));
2671
g_free(filename_temp);
2676
/* This is the same effect (we hope) as the HAVE_FILENO block
2677
* above, but for systems without fileno(). */
2678
if ((fd = open(filename_temp, O_RDWR)) < 0) {
2679
purple_debug_error("util", "Error opening file %s for flush: %s\n",
2680
filename_temp, g_strerror(errno));
2681
g_free(filename_temp);
2684
if (fsync(fd) < 0) {
2685
purple_debug_error("util", "Error syncing %s: %s\n",
2686
filename_temp, g_strerror(errno));
2687
g_free(filename_temp);
2691
if (close(fd) < 0) {
2692
purple_debug_error("util", "Error closing %s after sync: %s\n",
2693
filename_temp, g_strerror(errno));
2694
g_free(filename_temp);
2624
2699
/* Ensure the file is the correct size */
2625
2700
if (byteswritten != real_size)
2648
2723
if (chmod(filename_temp, S_IRUSR | S_IWUSR) == -1)
2650
2725
purple_debug_error("util", "Error setting permissions of file %s: %s\n",
2651
filename_temp, strerror(errno));
2726
filename_temp, g_strerror(errno));
3217
3291
purple_str_size_to_units(size_t size)
3219
static const char *size_str[4] = { "bytes", "KiB", "MiB", "GiB" };
3293
static const char * const size_str[] = { "bytes", "KiB", "MiB", "GiB" };
3220
3294
float size_mag;
3221
3295
int size_index = 0;
3409
3483
char host[256], path[256], user[256], passwd[256];
3411
3485
/* hyphen at end includes it in control set */
3412
static char addr_ctrl[] = "A-Za-z0-9.-";
3413
static char port_ctrl[] = "0-9";
3414
static char page_ctrl[] = "A-Za-z0-9.~_/:*!@&%%?=+^-";
3415
static char user_ctrl[] = "A-Za-z0-9.~_/*!&%%?=+^-";
3416
static char passwd_ctrl[] = "A-Za-z0-9.~_/*!&%%?=+^-";
3486
static const char addr_ctrl[] = "A-Za-z0-9.-";
3487
static const char port_ctrl[] = "0-9";
3488
static const char page_ctrl[] = "A-Za-z0-9.~_/:*!@&%%?=+^-";
3489
static const char user_ctrl[] = "A-Za-z0-9.~_/*!&%%?=+^-";
3490
static const char passwd_ctrl[] = "A-Za-z0-9.~_/*!&%%?=+^-";
3418
3492
g_return_val_if_fail(url != NULL, FALSE);
3708
3782
if(new_data == NULL) {
3709
3783
purple_debug_error("util",
3710
3784
"Failed to allocate %u bytes: %s\n",
3711
content_len, strerror(errno));
3785
content_len, g_strerror(errno));
3712
3786
purple_util_fetch_url_error(gfud,
3713
3787
_("Unable to allocate enough memory to hold "
3714
3788
"the contents from %s. The web server may "
3748
3822
purple_util_fetch_url_error(gfud, _("Error reading from %s: %s"),
3749
gfud->website.address, strerror(errno));
3823
gfud->website.address, g_strerror(errno));
3778
3852
else if (len < 0) {
3779
3853
purple_util_fetch_url_error(gfud, _("Error writing to %s: %s"),
3780
gfud->website.address, strerror(errno));
3854
gfud->website.address, g_strerror(errno));
3783
3857
gfud->request_written += len;