647 lines
14 KiB
C
647 lines
14 KiB
C
#ifdef HAVE_CONFIG_H
|
|
#include "../config.h"
|
|
#endif
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <unistd.h>
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include <locale.h>
|
|
|
|
#include <gtk/gtk.h>
|
|
#include <regex.h>
|
|
#include <libgnome/gnome-url.h>
|
|
#include <libgnomevfs/gnome-vfs.h>
|
|
#include <errno.h>
|
|
|
|
#include "gm-support.h"
|
|
#include "gm-debug.h"
|
|
#include "gm-pixbuf.h"
|
|
//#include "if_main.h"
|
|
|
|
#define URL_REGEXP "(((mailto|news|telnet|nttp|file|http|sftp|ftp|https|dav|callto)://)|(www|ftp)[-A-Za-z0-9]*\\.)[-A-Za-z0-9\\.@:]+[^]''\\.}>\\) ,\\/\\\"\\!]+(:[0-9]*)?(/|/[-A-Za-z0-9_\\$\\.\\+\\!\\*\\(\\),;:@&=\\?/~\\#\\%]*[^]'\\.}>\\) ,\\\"\\!])?"
|
|
static regex_t url_regexp;
|
|
|
|
gchar *
|
|
gm_fix_decimal_point(gchar *line, int len) {
|
|
int i;
|
|
struct lconv *l = localeconv();
|
|
|
|
if (l->decimal_point[0] == '.') {
|
|
return line;
|
|
}
|
|
|
|
for (i = 0; i < len; i++) {
|
|
if (line[i] == '.') {
|
|
line[i] = l->decimal_point[0];
|
|
}
|
|
}
|
|
|
|
return line;
|
|
}
|
|
|
|
gchar *
|
|
gm_fix_decimal_point_rev(gchar *line, int len) {
|
|
int i;
|
|
struct lconv *l = localeconv();
|
|
|
|
for (i = 0; i < len; i++) {
|
|
if (line[i] == l->decimal_point[0]) {
|
|
line[i] = '.';
|
|
}
|
|
}
|
|
|
|
return line;
|
|
}
|
|
|
|
gchar *
|
|
gm_ansi_strip(gchar * s) {
|
|
int i, j = 0;
|
|
|
|
for (i = 0; s[i] != '\0'; i++) {
|
|
// Escape sequence, advance to character after 'm'
|
|
if (s[i] == '\x1B') {
|
|
while (s[i] != '\0' && s[i] != 'm') {
|
|
i++;
|
|
}
|
|
} else if (s[i] != '\x07') {
|
|
s[j] = s[i];
|
|
j++;
|
|
}
|
|
}
|
|
|
|
s[j] = '\0';
|
|
return s;
|
|
}
|
|
|
|
int
|
|
garray_length(gchar **s) {
|
|
int i = 0;
|
|
|
|
while (s[i] != NULL) {
|
|
i++;
|
|
}
|
|
|
|
return i;
|
|
}
|
|
|
|
void g_list_free_simple(GList *s) {
|
|
GList *tmp;
|
|
|
|
for (tmp = s; tmp; tmp = tmp->next) {
|
|
g_free(tmp->data);
|
|
}
|
|
|
|
g_list_free(s);
|
|
}
|
|
|
|
gchar *
|
|
g_list_find_simple(GList *s, gchar *f) {
|
|
GList *tmp;
|
|
|
|
for (tmp = s; tmp; tmp = tmp->next) {
|
|
if (strcmp(tmp->data, f) == 0) {
|
|
return tmp->data;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
void
|
|
gm_dialog(gchar * message, GtkMessageType messagebox_type,
|
|
GtkWindow * parent) {
|
|
GtkWidget *dlg;
|
|
|
|
if (parent == NULL) {
|
|
//parent = GTK_WINDOW(if_main_get_widget("wndMain"));
|
|
}
|
|
|
|
dlg =
|
|
gtk_message_dialog_new(parent,
|
|
GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
|
|
messagebox_type, GTK_BUTTONS_OK, message, NULL);
|
|
gtk_dialog_run(GTK_DIALOG(dlg));
|
|
gtk_widget_destroy(dlg);
|
|
}
|
|
|
|
void
|
|
gm_error_dialog(gchar * message, GtkWindow * parent) {
|
|
gm_dialog(message, GTK_MESSAGE_ERROR, parent);
|
|
}
|
|
|
|
void
|
|
gm_warning_dialog(gchar * message, GtkWindow * parent) {
|
|
gm_dialog(message, GTK_MESSAGE_WARNING, parent);
|
|
}
|
|
|
|
void
|
|
gm_info_dialog(gchar * message, GtkWindow * parent) {
|
|
gm_dialog(message, GTK_MESSAGE_INFO, parent);
|
|
}
|
|
|
|
void
|
|
gm_question_dialog(gchar * message, GtkWindow * parent) {
|
|
gm_dialog(message, GTK_MESSAGE_QUESTION, parent);
|
|
}
|
|
|
|
void
|
|
gm_do_events() {
|
|
while (gtk_events_pending()) {
|
|
gtk_main_iteration();
|
|
}
|
|
}
|
|
|
|
gchar *
|
|
gm_str_escape(gchar * line) {
|
|
gchar *newLine;
|
|
int i, j = 0;
|
|
|
|
if (strlen(line) == 0) {
|
|
return g_strdup("");
|
|
}
|
|
|
|
if (strstr(line, "\"") || strstr(line, "\\")) {
|
|
newLine = g_new(gchar, (strlen(line) * 2) + 1);
|
|
|
|
for (i = 0; i < (int)strlen(line); i++) {
|
|
if (line[i] == '"' || line[i] == '\\') {
|
|
newLine[j] = '\\';
|
|
j++;
|
|
}
|
|
newLine[j] = line[i];
|
|
j++;
|
|
}
|
|
|
|
newLine[j] = '\0';
|
|
return newLine;
|
|
} else {
|
|
return g_strdup(line);
|
|
}
|
|
}
|
|
|
|
void
|
|
gm_directory_remove_all(const gchar * path, gboolean remove_self) {
|
|
GDir *cDir;
|
|
gchar *name;
|
|
gchar *newPath;
|
|
|
|
if (g_file_test(path, G_FILE_TEST_IS_DIR)) {
|
|
// Iterate through the files and do the right thingie
|
|
if ((cDir = g_dir_open(path, 0, NULL))) {
|
|
while ((name = (gchar *) (g_dir_read_name(cDir))) != NULL) {
|
|
newPath = g_strconcat(path, "/", name, NULL);
|
|
gm_directory_remove_all(newPath, TRUE);
|
|
g_free(newPath);
|
|
}
|
|
g_dir_close(cDir);
|
|
}
|
|
}
|
|
|
|
if (remove_self) {
|
|
// Its a file, or just empty! MUST...BE...REMOVEEEED!
|
|
remove(path);
|
|
}
|
|
}
|
|
|
|
gint
|
|
gm_url_regex_match(const gchar *msg, int len, GArray *start, GArray *end) {
|
|
static gboolean inited = FALSE;
|
|
regmatch_t matches[1];
|
|
gint ret = 0, num_matches = 0, offset = 0;
|
|
gchar *tmp;
|
|
gint s;
|
|
|
|
if (!inited) {
|
|
memset(&url_regexp, 0, sizeof (regex_t));
|
|
regcomp(&url_regexp, URL_REGEXP, REG_EXTENDED);
|
|
inited = TRUE;
|
|
}
|
|
|
|
tmp = g_strndup(msg, len);
|
|
|
|
while (!ret) {
|
|
ret = regexec(&url_regexp, (char *)(tmp + offset), 1, matches, 0);
|
|
|
|
if (ret == 0) {
|
|
if (matches[0].rm_so > matches[0].rm_eo) {
|
|
break;
|
|
}
|
|
|
|
num_matches++;
|
|
|
|
s = matches[0].rm_so + offset;
|
|
offset = matches[0].rm_eo + offset;
|
|
|
|
g_array_append_val(start, s);
|
|
g_array_append_val(end, offset);
|
|
}
|
|
}
|
|
|
|
g_free(tmp);
|
|
|
|
return num_matches;
|
|
}
|
|
|
|
void
|
|
gm_open_url (const gchar *url) {
|
|
if (!url || strlen (url) == 0) {
|
|
return;
|
|
}
|
|
|
|
/* gnome_url_show doesn't work when there's no protocol, so we might
|
|
* need to add one.
|
|
*/
|
|
if (strstr (url, "://") == NULL) {
|
|
gchar *tmp;
|
|
|
|
tmp = g_strconcat ("http://", url, NULL);
|
|
gnome_url_show(tmp, NULL);
|
|
g_free (tmp);
|
|
return;
|
|
}
|
|
|
|
gnome_url_show (url, NULL);
|
|
}
|
|
|
|
void
|
|
gm_fetch_handle_free(GmFetchHandle *g) {
|
|
GList *tmp;
|
|
|
|
g_free(g->cur_file_name);
|
|
|
|
for (tmp = g->source_uri; tmp; tmp = tmp->next) {
|
|
gnome_vfs_uri_unref((GnomeVFSURI*)(tmp->data));
|
|
}
|
|
g_list_free(g->source_uri);
|
|
|
|
|
|
for (tmp = g->dest_uri; tmp; tmp = tmp->next) {
|
|
gnome_vfs_uri_unref((GnomeVFSURI*)(tmp->data));
|
|
}
|
|
g_list_free(g->dest_uri);
|
|
|
|
g_free(g);
|
|
}
|
|
|
|
GmFetchHandle *
|
|
gm_fetch_handle_create(GFunc cb, gpointer user_data) {
|
|
GmFetchHandle *g = g_new0(GmFetchHandle, 1);
|
|
|
|
g->cb = cb;
|
|
g->user_data = user_data;
|
|
g->prev_status = GNOME_VFS_XFER_PROGRESS_STATUS_OK;
|
|
g->cur_phase = -1;
|
|
g->prev_phase = -1;
|
|
g->cur_file = -1;
|
|
g->prev_file = -1;
|
|
g->source_uri = NULL;
|
|
g->dest_uri = NULL;
|
|
g->cur_file_name = NULL;
|
|
g->files_total = 0;
|
|
g->done = FALSE;
|
|
g->aborted = FALSE;
|
|
|
|
return g;
|
|
}
|
|
|
|
gint
|
|
gm_fetch_progress(GnomeVFSAsyncHandle *handle,
|
|
GnomeVFSXferProgressInfo *info,
|
|
GmFetchHandle *g) {
|
|
gchar *name;
|
|
const gchar *err;
|
|
|
|
g->cur_phase = info->phase;
|
|
g->cur_file = info->file_index;
|
|
g->files_total = info->files_total;
|
|
g->bytes_total = info->bytes_total;
|
|
g->file_size = info->file_size;
|
|
g->bytes_copied = info->bytes_copied;
|
|
g->total_bytes_copied = info->total_bytes_copied;
|
|
g->status = info->status;
|
|
|
|
if (g->aborted) {
|
|
g->cb(g, g->user_data);
|
|
gm_fetch_handle_free(g);
|
|
return FALSE;
|
|
}
|
|
|
|
if (info->target_name != NULL) {
|
|
if (g->cur_file_name && strcmp(g->cur_file_name, info->target_name) != 0) {
|
|
g->cur_phase = GNOME_VFS_XFER_PHASE_FILECOMPLETED;
|
|
g->cb(g, g->user_data);
|
|
g->cur_phase = info->phase;
|
|
|
|
g_free(g->cur_file_name);
|
|
g->cur_file_name = NULL;
|
|
}
|
|
|
|
if (!g->cur_file_name) {
|
|
g->cur_file_name = g_strdup(info->target_name);
|
|
}
|
|
}
|
|
|
|
if (info->status == GNOME_VFS_XFER_PROGRESS_STATUS_OVERWRITE) {
|
|
name = gnome_vfs_get_local_path_from_uri(info->target_name);
|
|
gm_debug_msg(DEBUG_DEFAULT, "gnoemoe_fetch_progress: asking for overwriting %s: yes", name);
|
|
|
|
g->prev_status = GNOME_VFS_XFER_PROGRESS_STATUS_OVERWRITE;
|
|
return GNOME_VFS_XFER_OVERWRITE_ACTION_REPLACE;
|
|
} else if (info->status == GNOME_VFS_XFER_PROGRESS_STATUS_VFSERROR) {
|
|
name = gnome_vfs_get_local_path_from_uri(info->target_name);
|
|
err = gnome_vfs_result_to_string(info->vfs_status);
|
|
|
|
gdk_threads_enter();
|
|
gm_debug_msg(DEBUG_DEFAULT, "gnoemoe_fetch_progress: error for %s: %s", name, err);
|
|
g->cb(g, g->user_data);
|
|
gdk_threads_leave();
|
|
|
|
g_free(g->cur_file_name);
|
|
g->cur_file_name = NULL;
|
|
|
|
g->prev_status = GNOME_VFS_XFER_PROGRESS_STATUS_VFSERROR;
|
|
g_free(name);
|
|
|
|
return GNOME_VFS_XFER_ERROR_ACTION_SKIP;
|
|
}
|
|
|
|
if (info->phase == GNOME_VFS_XFER_PHASE_COMPLETED) {
|
|
if (g->cur_file_name != NULL) {
|
|
g->cur_phase = GNOME_VFS_XFER_PHASE_FILECOMPLETED;
|
|
g->cb(g, g->user_data);
|
|
g->cur_phase = info->phase;
|
|
}
|
|
|
|
g->done = TRUE;
|
|
g->cb(g, g->user_data);
|
|
gm_fetch_handle_free(g);
|
|
return TRUE;
|
|
}
|
|
|
|
g->prev_status = info->status;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
gint
|
|
gm_fetch_interact(GnomeVFSXferProgressInfo *info, gpointer user_data) {
|
|
return 1;
|
|
}
|
|
|
|
GmFetchHandle *
|
|
gm_fetch(const GList *source, const GList *dest,
|
|
GFunc cb, gpointer user_data) {
|
|
GmFetchHandle *g = gm_fetch_handle_create(cb, user_data);
|
|
gchar *uri;
|
|
|
|
for (; source; source = source->next) {
|
|
uri = (gchar *)(source->data);
|
|
g->source_uri = g_list_append(g->source_uri, gnome_vfs_uri_new(uri));
|
|
}
|
|
|
|
for (; dest; dest = dest->next) {
|
|
uri = (gchar *)(dest->data);
|
|
g->dest_uri = g_list_append(g->dest_uri, gnome_vfs_uri_new(uri));
|
|
}
|
|
|
|
gnome_vfs_async_xfer(&(g->handle), g->source_uri, g->dest_uri,
|
|
GNOME_VFS_XFER_DEFAULT|GNOME_VFS_XFER_RECURSIVE,
|
|
GNOME_VFS_XFER_ERROR_MODE_QUERY,
|
|
GNOME_VFS_XFER_OVERWRITE_MODE_REPLACE,
|
|
GNOME_VFS_PRIORITY_DEFAULT,
|
|
(GnomeVFSAsyncXferProgressCallback)gm_fetch_progress,
|
|
g, gm_fetch_interact, g);
|
|
return g;
|
|
}
|
|
|
|
gboolean
|
|
gm_is_end_scrolled(GtkScrolledWindow *wnd, guint charHeight) {
|
|
GtkAdjustment *ad = gtk_scrolled_window_get_vadjustment(wnd);
|
|
|
|
return ((ad->page_size + ad->value) >= ad->upper - (double)charHeight);
|
|
}
|
|
|
|
void
|
|
gm_scroll_end(GtkTextView *view, gboolean needs) {
|
|
GtkTextBuffer *buf;
|
|
GtkTextMark *mark;
|
|
GtkTextIter iter;
|
|
|
|
if (!needs) {
|
|
return;
|
|
}
|
|
|
|
buf = gtk_text_view_get_buffer(view);
|
|
mark = gtk_text_buffer_get_mark(buf, "end-of-buffer");
|
|
|
|
if (mark == NULL) {
|
|
gtk_text_buffer_get_end_iter(buf, &iter);
|
|
mark = gtk_text_buffer_create_mark(buf, "end-of-buffer", &iter, FALSE);
|
|
}
|
|
|
|
gtk_text_view_scroll_to_mark(view, mark, 0.0, TRUE, 1.0, 1.0);
|
|
}
|
|
|
|
#define MAX_BUF 1024
|
|
|
|
GString *
|
|
gm_read_file(const gchar *fname, gboolean readall, OpenLogProgress func, gpointer user_data) {
|
|
FILE *f;
|
|
gchar line[MAX_BUF], *tmp;
|
|
GString *str = NULL;
|
|
long bytes_read = 0, bytes_total = 0;
|
|
|
|
if (!fname) {
|
|
return NULL;
|
|
}
|
|
|
|
f = fopen(fname, "r");
|
|
|
|
if (f) {
|
|
fseek(f, 0, SEEK_END);
|
|
bytes_total = ftell(f);
|
|
rewind(f);
|
|
|
|
str = g_string_new("");
|
|
|
|
while (fgets((char *) &line, MAX_BUF, f) != NULL) {
|
|
bytes_read += strlen((char *)&line);
|
|
tmp = NULL;
|
|
if (g_utf8_validate(line, -1, NULL)) {
|
|
if (readall) {
|
|
str = g_string_append(str, line);
|
|
}
|
|
tmp = g_strdup(line);
|
|
} else {
|
|
tmp = g_locale_to_utf8(line, -1, NULL, NULL, NULL);
|
|
|
|
if (!tmp) {
|
|
tmp = g_convert(line, -1, "UTF-8", "ISO-8859-15", NULL, NULL, NULL);
|
|
}
|
|
if (!tmp) {
|
|
tmp = g_convert(line, -1, "UTF-8", "ISO-8859-15", NULL, NULL, NULL);
|
|
}
|
|
|
|
if (readall) {
|
|
str = g_string_append(str, tmp);
|
|
}
|
|
}
|
|
|
|
if (func != NULL) {
|
|
func(bytes_read, bytes_total, tmp, user_data);
|
|
} else {
|
|
g_free(tmp);
|
|
}
|
|
}
|
|
|
|
fclose(f);
|
|
|
|
return str;
|
|
} else {
|
|
gm_debug_msg(DEBUG_DEFAULT, "support_read_file: file (%s) could not be read: %s",
|
|
fname, strerror(errno));
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
GtkWidget *
|
|
gm_create_tab_label(const gchar *icon, const gchar *caption, gboolean has_exit,
|
|
GmLabelInfo *info) {
|
|
/* First create the gbox (size 3) which will contain an icon, a label and a
|
|
exit button if has_exit is true */
|
|
GtkWidget *hboxTabLabel;
|
|
gint h, w;
|
|
|
|
hboxTabLabel = gtk_hbox_new(FALSE, 3);
|
|
|
|
gtk_widget_show(hboxTabLabel);
|
|
|
|
info->image_icon = gtk_image_new_from_pixbuf(
|
|
gm_pixbuf_get_at_size(icon, 16, 16));
|
|
gtk_widget_set_size_request(info->image_icon, 16, 16);
|
|
gtk_widget_show(info->image_icon);
|
|
gtk_box_pack_start(GTK_BOX(hboxTabLabel), info->image_icon, TRUE, TRUE, 0);
|
|
|
|
info->label_name = gtk_label_new(caption);
|
|
gtk_widget_show(info->label_name);
|
|
gtk_box_pack_start(GTK_BOX(hboxTabLabel), info->label_name, FALSE, FALSE, 0);
|
|
|
|
if (has_exit) {
|
|
info->button_exit = gtk_button_new();
|
|
gtk_widget_show(info->button_exit);
|
|
|
|
gtk_box_pack_end(GTK_BOX(hboxTabLabel), info->button_exit , FALSE,
|
|
FALSE, 0);
|
|
|
|
gtk_icon_size_lookup(GTK_ICON_SIZE_MENU, &w, &h);
|
|
gtk_widget_set_size_request(info->button_exit , w + 2, h + 2);
|
|
gtk_button_set_relief(GTK_BUTTON(info->button_exit ), GTK_RELIEF_NONE);
|
|
gtk_button_set_focus_on_click(GTK_BUTTON(info->button_exit), FALSE);
|
|
|
|
info->image_exit = gtk_image_new_from_stock("gtk-close",
|
|
GTK_ICON_SIZE_MENU);
|
|
gtk_widget_show(info->image_exit);
|
|
gtk_container_add(GTK_CONTAINER(info->button_exit), info->image_exit);
|
|
}
|
|
|
|
return hboxTabLabel;
|
|
}
|
|
|
|
void
|
|
gm_widget_destroy_data(GtkWidget *caller, GtkWidget *destroyer) {
|
|
if (GTK_IS_WIDGET(destroyer)) {
|
|
gtk_widget_destroy(destroyer);
|
|
}
|
|
}
|
|
|
|
const gchar *
|
|
gm_default_charset() {
|
|
const gchar *loc = NULL;
|
|
g_get_charset(&loc);
|
|
|
|
if (loc == NULL || strlen(loc) == 0) {
|
|
loc = "ISO-8859-15";
|
|
}
|
|
|
|
return loc;
|
|
}
|
|
|
|
void
|
|
gm_notebook_focus_from_label(GtkNotebook *note, gchar *caption) {
|
|
int p = gtk_notebook_get_n_pages(note);
|
|
int i;
|
|
GtkWidget *child;
|
|
|
|
for (i = 0; i < p; i++) {
|
|
child = gtk_notebook_get_nth_page(note, i);
|
|
if (!g_strcasecmp(gtk_notebook_get_tab_label_text(note, child),
|
|
caption)) {
|
|
gtk_notebook_set_current_page(note, i);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
gm_string_skip_space(gchar **ptr) {
|
|
while (**ptr != '\0' && g_unichar_isspace(g_utf8_get_char(*ptr))) {
|
|
*ptr = g_utf8_next_char(*ptr);
|
|
}
|
|
}
|
|
|
|
void
|
|
gm_string_skip_nonspace(gchar **ptr) {
|
|
while (**ptr != '\0' && !g_unichar_isspace(g_utf8_get_char(*ptr))) {
|
|
*ptr = g_utf8_next_char(*ptr);
|
|
}
|
|
}
|
|
|
|
void
|
|
gm_string_skip_till(gchar **ptr, gchar const *find) {
|
|
gchar const *fptr;
|
|
gunichar check;
|
|
|
|
while (**ptr != '\0') {
|
|
check = g_utf8_get_char(*ptr);
|
|
|
|
for (fptr = find; *fptr; ++fptr) {
|
|
// CHECK: find should also be treated as utf8!
|
|
if (check == (gunichar)(*fptr)) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
*ptr = g_utf8_next_char(*ptr);
|
|
}
|
|
}
|
|
|
|
gchar *
|
|
gm_to_utf8_with_fallback(gchar const *text, gssize len, gchar const *from,
|
|
gchar const *fallback) {
|
|
gchar *res;
|
|
gsize read, written;
|
|
GString *str = g_string_new("");
|
|
|
|
// TODO: use g_iconv instead of g_convert
|
|
|
|
while ((res = g_convert(text, len, "UTF-8", from, &read, &written, NULL))
|
|
== NULL) {
|
|
res = g_convert(text, read, "UTF-8", from, NULL, NULL, NULL);
|
|
str = g_string_append(str, res);
|
|
|
|
str = g_string_append(str, fallback);
|
|
text = text + read + 1;
|
|
|
|
if (len != -1)
|
|
len = len - read - 1;
|
|
}
|
|
|
|
str = g_string_append(str, res);
|
|
g_free(res);
|
|
|
|
res = str->str;
|
|
g_string_free(str, FALSE);
|
|
return res;
|
|
}
|