943 lines
21 KiB
C
943 lines
21 KiB
C
/*
|
|
* JoeyDev
|
|
* Copyright (C) 2018-2023 Scott Duensing <scott@kangaroopunch.com>
|
|
*
|
|
* This software is provided 'as-is', without any express or implied
|
|
* warranty. In no event will the authors be held liable for any damages
|
|
* arising from the use of this software.
|
|
*
|
|
* Permission is granted to anyone to use this software for any purpose,
|
|
* including commercial applications, and to alter it and redistribute it
|
|
* freely, subject to the following restrictions:
|
|
*
|
|
* 1. The origin of this software must not be misrepresented; you must not
|
|
* claim that you wrote the original software. If you use this software
|
|
* in a product, an acknowledgment in the product documentation would be
|
|
* appreciated but is not required.
|
|
* 2. Altered source versions must be plainly marked as such, and must not be
|
|
* misrepresented as being the original software.
|
|
* 3. This notice may not be removed or altered from any source distribution.
|
|
*/
|
|
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include "common.h"
|
|
#include "utils.h"
|
|
#include "cwalk.h"
|
|
#include "messages.h"
|
|
|
|
|
|
#ifdef _WIN32
|
|
#define ourMkdir(p,m) mkdir(p)
|
|
#else
|
|
#define ourMkdir mkdir
|
|
#endif
|
|
|
|
|
|
typedef struct WindowListS {
|
|
GtkWidget *key;
|
|
WindowDataT *value;
|
|
} WindowListT;
|
|
|
|
|
|
static ArchiveT **_activeArchives = NULL;
|
|
static WindowListT *_windowList = NULL;
|
|
|
|
char __utilFilenameBuffer[FILENAME_MAX];
|
|
|
|
|
|
gboolean utilDecompressUpdate(gpointer userData); // Not static
|
|
|
|
|
|
void utilAddTextToListBox(GtkListBox *list, char *text) {
|
|
GtkWidget *row;
|
|
GtkWidget *box;
|
|
GtkWidget *label;
|
|
|
|
row = gtk_list_box_row_new();
|
|
box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6);
|
|
gtk_widget_set_hexpand(box, TRUE);
|
|
label = gtk_label_new(text);
|
|
gtk_label_set_use_markup(GTK_LABEL(label), TRUE);
|
|
|
|
// Add new row to the message box.
|
|
gtk_box_pack_start(GTK_BOX(box), label, FALSE, FALSE, 0);
|
|
gtk_container_add(GTK_CONTAINER(row), box);
|
|
gtk_list_box_insert(GTK_LIST_BOX(list), row, -1);
|
|
gtk_widget_show_all(list);
|
|
}
|
|
|
|
|
|
void utilClearContainer(GtkContainer *container) {
|
|
GList *children;
|
|
GList *iter;
|
|
|
|
children = gtk_container_get_children(GTK_CONTAINER(container));
|
|
for (iter = children; iter != NULL; iter = g_list_next(iter)) {
|
|
gtk_widget_destroy(GTK_WIDGET(iter->data));
|
|
}
|
|
g_list_free(children);
|
|
}
|
|
|
|
|
|
char *utilCreateString(char *format, ...) {
|
|
va_list args;
|
|
char *string;
|
|
|
|
va_start(args, format);
|
|
string = utilCreateStringVArgs(format, args);
|
|
va_end(args);
|
|
|
|
return string;
|
|
}
|
|
|
|
|
|
__attribute__((__format__(__printf__, 1, 0)))
|
|
char *utilCreateStringVArgs(char *format, va_list args) {
|
|
va_list argsCopy;
|
|
int32_t size;
|
|
char *buffer = NULL;
|
|
|
|
va_copy(argsCopy, args);
|
|
size = vsnprintf(NULL, 0, format, argsCopy) + 1;
|
|
va_end(argsCopy);
|
|
buffer = calloc(1, (size_t)size);
|
|
if (buffer) {
|
|
vsnprintf(buffer, (size_t)size, format, args);
|
|
}
|
|
|
|
//debug("%s = %s\n", format, buffer);
|
|
|
|
return buffer;
|
|
}
|
|
|
|
|
|
ArchiveT *utilDecompress(char *archive, char *outPath, archiveCallback callback, void *userData) {
|
|
ArchiveT *a = NULL;
|
|
int i;
|
|
|
|
// Do not allow two of the same archive to be started.
|
|
for (i=0; i<arrlen(_activeArchives); i++) {
|
|
if (strcmp(_activeArchives[i]->archive, archive) == 0) {
|
|
// Return existing transfer handle.
|
|
return _activeArchives[i];
|
|
}
|
|
}
|
|
|
|
a = NEW(ArchiveT);
|
|
|
|
a->in = archive_read_new();
|
|
archive_read_support_filter_bzip2(a->in);
|
|
archive_read_support_format_gnutar(a->in);
|
|
|
|
a->out = archive_write_disk_new();
|
|
archive_write_disk_set_options(a->out, 0);
|
|
archive_write_disk_set_standard_lookup(a->out);
|
|
|
|
a->entry = NULL;
|
|
a->result = 0;
|
|
a->compression = 0;
|
|
a->fileCount = 0;
|
|
a->compressed = 0;
|
|
a->uncompressed = 0;
|
|
a->archive = utilFileBasename(archive);
|
|
a->outPath = strdup(outPath);
|
|
a->currentFile = NULL;
|
|
a->copying = FALSE;
|
|
a->finished = FALSE;
|
|
a->success = FALSE;
|
|
a->callback = callback;
|
|
a->userData = userData;
|
|
a->size = utilFileSize(archive);
|
|
|
|
a->result = archive_read_open_filename(a->in, archive, 16384);
|
|
if (a->result == ARCHIVE_OK) {
|
|
arrput(_activeArchives, a);
|
|
return a;
|
|
}
|
|
|
|
debug("%s\n", archive_error_string(a->in));
|
|
|
|
DEL(a->archive);
|
|
DEL(a->outPath);
|
|
DEL(a);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
gboolean utilDecompressUpdate(gpointer userData) {
|
|
ArchiveT *a;
|
|
const void *buff;
|
|
size_t size;
|
|
la_int64_t offset;
|
|
int i;
|
|
int toClose = -1;
|
|
char *fullOutputPath;
|
|
|
|
(void)userData;
|
|
|
|
// Anything to process?
|
|
for (i=0; i<arrlen(_activeArchives); i++) {
|
|
a = _activeArchives[i];
|
|
// Did they cancel?
|
|
if (a->finished) {
|
|
a->success = FALSE;
|
|
toClose = i;
|
|
break;
|
|
}
|
|
// Update stats.
|
|
if (a->in != NULL) {
|
|
a->compressed = archive_filter_bytes(a->in, -1);
|
|
a->uncompressed = archive_filter_bytes(a->in, 0);
|
|
if (a->compressed > a->uncompressed) {
|
|
a->compression = 0;
|
|
} else {
|
|
a->compression = (int)((a->uncompressed - a->compressed) * 100 / a->uncompressed);
|
|
}
|
|
a->fileCount = archive_file_count(a->in);
|
|
}
|
|
|
|
if (a->entry != NULL) {
|
|
DEL(a->currentFile);
|
|
a->currentFile = strdup(archive_entry_pathname(a->entry));
|
|
}
|
|
// Are we unpacking, or do we need the next file?
|
|
if (a->copying) {
|
|
a->result = archive_read_data_block(a->in, &buff, &size, &offset);
|
|
if (a->result == ARCHIVE_EOF) {
|
|
a->copying = FALSE;
|
|
a->result = archive_write_finish_entry(a->out);
|
|
if (a->result < ARCHIVE_WARN) {
|
|
a->finished = TRUE;
|
|
a->success = FALSE;
|
|
toClose = i;
|
|
}
|
|
break;
|
|
}
|
|
if (a->result < ARCHIVE_OK) {
|
|
a->finished = TRUE;
|
|
a->success = FALSE;
|
|
toClose = i;
|
|
break;
|
|
}
|
|
a->result = archive_write_data_block(a->out, buff, size, offset);
|
|
if (a->result < ARCHIVE_OK) {
|
|
a->finished = TRUE;
|
|
a->success = FALSE;
|
|
toClose = i;
|
|
break;
|
|
}
|
|
} else {
|
|
// Get next file to unpack.
|
|
a->result = archive_read_next_header(a->in, &a->entry);
|
|
if (a->result == ARCHIVE_EOF) {
|
|
a->finished = TRUE;
|
|
a->success = TRUE;
|
|
toClose = i;
|
|
break;
|
|
}
|
|
if (a->result < ARCHIVE_WARN) {
|
|
a->finished = TRUE;
|
|
a->success = FALSE;
|
|
toClose = i;
|
|
break;
|
|
}
|
|
// Add path to output filename.
|
|
fullOutputPath = utilCreateString("%s%s", a->outPath, archive_entry_pathname(a->entry));
|
|
archive_entry_set_pathname(a->entry, fullOutputPath);
|
|
DEL(fullOutputPath);
|
|
// Create output file.
|
|
a->result = archive_write_header(a->out, a->entry);
|
|
if (a->result != ARCHIVE_OK) {
|
|
a->finished = TRUE;
|
|
a->success = FALSE;
|
|
toClose = i;
|
|
break;
|
|
}
|
|
// Is there data to decompress?
|
|
if (archive_entry_size(a->entry) > 0) {
|
|
// Start copying decompressed data.
|
|
a->copying = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (toClose >= 0) {
|
|
a = _activeArchives[toClose];
|
|
arrdel(_activeArchives, toClose);
|
|
if (a->callback) {
|
|
a->callback(a);
|
|
}
|
|
archive_read_close(a->in);
|
|
archive_read_free(a->in);
|
|
archive_write_close(a->out);
|
|
archive_write_free(a->out);
|
|
DEL(a->archive);
|
|
DEL(a->outPath);
|
|
DEL(a->currentFile);
|
|
DEL(a);
|
|
}
|
|
|
|
return G_SOURCE_CONTINUE;
|
|
}
|
|
|
|
|
|
int utilDeleteTree(const char *path) {
|
|
DIR *directory = opendir(path);
|
|
char *filename = NULL;
|
|
struct dirent *entry;
|
|
int (*removeFunc)(const char *);
|
|
|
|
if (directory) {
|
|
while ((entry = readdir(directory))) {
|
|
if (!strcmp(".", entry->d_name) || !strcmp("..", entry->d_name)) {
|
|
continue;
|
|
}
|
|
filename = utilCreateString("%s/%s", path, entry->d_name);
|
|
removeFunc = entry->d_type == DT_DIR ? utilDeleteTree : remove;
|
|
if (removeFunc(filename)) {
|
|
DEL(filename);
|
|
closedir(directory);
|
|
return -1;
|
|
}
|
|
DEL(filename);
|
|
}
|
|
if (closedir(directory)) {
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
return remove(path);
|
|
}
|
|
|
|
|
|
char *utilDeobfuscateASCII(char *obfuscated) {
|
|
char *deobfuscated = NULL;
|
|
char *hostname;
|
|
int i;
|
|
int j;
|
|
int c;
|
|
|
|
// Valid ASCII 32 - 126 (94 chars)
|
|
|
|
hostname = strdup(g_get_host_name());
|
|
|
|
// Decrypt.
|
|
j = 0;
|
|
deobfuscated = (char *)malloc((strlen(obfuscated) + 1) * sizeof(char));
|
|
for (i=0; i<strlen(obfuscated); i++) {
|
|
c = obfuscated[i] - hostname[j] - 32;
|
|
while (c < 0) c += 94;
|
|
deobfuscated[i] = (char)(c + 32);
|
|
j++;
|
|
if (j >= strlen(hostname)) j = 0;
|
|
}
|
|
deobfuscated[i] = 0;
|
|
|
|
DEL(hostname);
|
|
|
|
return deobfuscated;
|
|
}
|
|
|
|
|
|
void utilDequote(char *string) {
|
|
int x;
|
|
|
|
if (string[0] == '"' || string[strlen(string) - 1] == '"') {
|
|
string[strlen(string) - 1] = 0;
|
|
for (x=1; x<strlen(string) + 1; x++) {
|
|
string[x - 1] = string[x];
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void utilEnsureBufferSize(unsigned char **buffer, int *length, int wanted) {
|
|
unsigned char *temp = NULL;
|
|
|
|
if (*length < wanted) {
|
|
while (*length < wanted) *length = *length + 1024;
|
|
temp = realloc(*buffer, *length);
|
|
if (temp == NULL) {
|
|
message(MSG_SEVERE, "Unable to reallocate buffer from %d to %d bytes!", *length, wanted);
|
|
} else {
|
|
*buffer = temp;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void utilExtractResource(char *path) {
|
|
GInputStream *in;
|
|
gssize read;
|
|
gssize bytes = 0;
|
|
FILE *out = NULL;
|
|
unsigned char *buffer = NULL;
|
|
int name = (int)strlen(path) - 1;
|
|
char *target = NULL;
|
|
|
|
while (name >= 0 && path[name] != '/') name--;
|
|
target = utilCreateString("%s%s", __resourcePath, &path[name + 1]);
|
|
|
|
if (!utilFileExists(target)) {
|
|
utilEnsureBufferSize(&buffer, (int *)&bytes, 8192);
|
|
|
|
in = g_resources_open_stream(path, G_RESOURCE_LOOKUP_FLAGS_NONE, NULL);
|
|
if (in) {
|
|
out = fopen(target, "wb");
|
|
if (out) {
|
|
do {
|
|
read = g_input_stream_read(in, buffer, bytes, NULL, NULL);
|
|
fwrite(buffer, read, 1, out);
|
|
} while (read > 0);
|
|
fclose(out);
|
|
} else {
|
|
debug("Unable to write resource %s!\n", target);
|
|
}
|
|
g_input_stream_close(in, NULL, NULL);
|
|
g_object_unref(in);
|
|
} else {
|
|
debug("Resource %s not found!\n", path);
|
|
}
|
|
|
|
DEL(buffer);
|
|
}
|
|
|
|
DEL(target);
|
|
}
|
|
|
|
|
|
char *utilFileBasename(char *path) {
|
|
const char *basename;
|
|
size_t length;
|
|
char *newString = NULL;
|
|
|
|
// Returns filename without path.
|
|
|
|
cwk_path_get_basename(path, &basename, &length);
|
|
if (basename != NULL) newString = strdup(basename);
|
|
|
|
return newString;
|
|
}
|
|
|
|
|
|
gboolean utilFileCopy(char *from, char *to) {
|
|
FILE *in = NULL;
|
|
FILE *out = NULL;
|
|
gboolean result = FALSE;
|
|
size_t bytes;
|
|
|
|
in = fopen(from, "rb");
|
|
if (in) {
|
|
out = fopen(to, "wb");
|
|
if (out) {
|
|
while (!feof(in)) {
|
|
bytes = fread(__utilFilenameBuffer, 1, FILENAME_MAX, in);
|
|
if (bytes) {
|
|
fwrite(__utilFilenameBuffer, 1, bytes, out);
|
|
}
|
|
}
|
|
result = TRUE;
|
|
fclose(out);
|
|
}
|
|
fclose(in);
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
gboolean utilFileExists(char *filename) {
|
|
FILE *f = fopen(filename, "rb");
|
|
|
|
if (f) {
|
|
fclose(f);
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
gboolean utilFileOpen(WindowDataT *self, char *extension, char *what) {
|
|
GtkWidget *dialog;
|
|
GtkFileFilter *filter;
|
|
char *title = utilCreateString("Open %s", what);
|
|
char *warning = utilCreateString("You have unsaved changes. Open different %s?", what);
|
|
char *files = utilCreateString("%s Files", what);
|
|
gboolean result = TRUE;
|
|
|
|
if (self->isDirty) {
|
|
if (!utilQuestionDialog(self->window, title, warning)) {
|
|
result = FALSE;
|
|
}
|
|
}
|
|
|
|
if (result == TRUE) {
|
|
dialog = gtk_file_chooser_dialog_new(title,
|
|
GTK_WINDOW(self->window),
|
|
GTK_FILE_CHOOSER_ACTION_OPEN,
|
|
"_Cancel", GTK_RESPONSE_CANCEL,
|
|
"_Open", GTK_RESPONSE_ACCEPT,
|
|
NULL
|
|
);
|
|
|
|
filter = gtk_file_filter_new();
|
|
gtk_file_filter_set_name(filter, files);
|
|
gtk_file_filter_add_pattern(filter, extension);
|
|
gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
|
|
|
|
if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
|
|
utilSetDirty((WindowDataT *)self, FALSE);
|
|
DEL(self->filename);
|
|
DEL(self->path);
|
|
self->filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
|
|
utilUpdatePath(self);
|
|
} else {
|
|
result = FALSE;
|
|
}
|
|
|
|
gtk_widget_destroy(dialog);
|
|
}
|
|
|
|
DEL(files);
|
|
DEL(warning);
|
|
DEL(title);
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
char *utilFilePath(char *filename) {
|
|
size_t i;
|
|
char *temp = NULL;
|
|
|
|
if (filename) {
|
|
// Derive the path from the filename.
|
|
temp = strdup(filename);
|
|
cwk_path_get_dirname(temp, &i);
|
|
if (i > 0) temp[i] = 0;
|
|
}
|
|
|
|
return temp;
|
|
}
|
|
|
|
|
|
char *utilFileRemoveExtension(char *filename) {
|
|
int x = (int)strlen(filename) - 1;
|
|
char c;
|
|
char *newString = NULL;
|
|
|
|
while (x >= 0) {
|
|
if (filename[x] == '.') break;
|
|
x--;
|
|
}
|
|
|
|
if (x >= 0) {
|
|
c = filename[x];
|
|
filename[x] = 0;
|
|
newString = strdup(filename);
|
|
filename[x] = c;
|
|
} else {
|
|
newString = strdup(filename);
|
|
}
|
|
|
|
return newString;
|
|
}
|
|
|
|
|
|
gboolean utilFileSaveAs(WindowDataT *self, char *extension, char *what) {
|
|
gboolean result;
|
|
|
|
result = utilFileSaveOtherAs(self, extension, what, &self->filename);
|
|
utilUpdatePath(self);
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
gboolean utilFileSaveOtherAs(WindowDataT *self, char *extension, char *what, char **filename) {
|
|
GtkWidget *dialog;
|
|
GtkFileFilter *filter;
|
|
gboolean result = FALSE;
|
|
char *files = utilCreateString("%s Files", what);
|
|
size_t x;
|
|
|
|
dialog = gtk_file_chooser_dialog_new("Save As",
|
|
GTK_WINDOW(self->window),
|
|
GTK_FILE_CHOOSER_ACTION_SAVE,
|
|
"_Cancel", GTK_RESPONSE_CANCEL,
|
|
"_Save", GTK_RESPONSE_ACCEPT,
|
|
NULL);
|
|
|
|
if (*filename != NULL) {
|
|
memcpy(__utilFilenameBuffer, *filename, strlen(*filename) + 1);
|
|
cwk_path_get_dirname(__utilFilenameBuffer, &x);
|
|
if (x > 0) __utilFilenameBuffer[x] = 0;
|
|
gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog),__utilFilenameBuffer);
|
|
}
|
|
|
|
gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog), TRUE);
|
|
|
|
filter = gtk_file_filter_new();
|
|
gtk_file_filter_set_name(filter, files);
|
|
gtk_file_filter_add_pattern(filter, extension);
|
|
gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
|
|
|
|
if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
|
|
DEL(*filename);
|
|
*filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
|
|
result = TRUE;
|
|
}
|
|
|
|
DEL(files);
|
|
|
|
gtk_widget_destroy(dialog);
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
size_t utilFileSize(char *filename) {
|
|
size_t bytes = 0;
|
|
|
|
FILE *f = fopen(filename, "rb");
|
|
|
|
if (f) {
|
|
fseek(f, 0, SEEK_END);
|
|
bytes = ftell(f);
|
|
fclose(f);
|
|
}
|
|
|
|
return bytes;
|
|
}
|
|
|
|
|
|
GtkWidget *utilFindChildWidget(GtkWidget *parent, const gchar *name) {
|
|
GList *children = NULL;
|
|
GtkWidget *widget = NULL;
|
|
|
|
// This works on widgets with names. If a widget is referenced by
|
|
// utilGetWidgetsFromMemory, the name will be set to the ID of the
|
|
// widget. If not, you need to assign a name yourself.
|
|
|
|
if (g_strcmp0(gtk_widget_get_name(parent), name) == 0) {
|
|
return parent;
|
|
}
|
|
|
|
if (GTK_IS_CONTAINER(parent)) {
|
|
children = gtk_container_get_children(GTK_CONTAINER(parent));
|
|
}
|
|
|
|
while (children != NULL) {
|
|
widget = utilFindChildWidget(children->data, name);
|
|
|
|
if (widget != NULL) {
|
|
return widget;
|
|
}
|
|
|
|
children = children->next;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
void utilForceUpdate(void) {
|
|
//***TODO*** This is supposed to force any pending paint operations.
|
|
// It doesn't work.
|
|
|
|
//while (g_main_context_pending(NULL)) {
|
|
g_main_context_iteration(NULL,FALSE);
|
|
//}
|
|
}
|
|
|
|
|
|
char *utilGetToken(char *input, char *delimit, char *openblock, char *closeblock) {
|
|
static char *token = NULL;
|
|
char *lead = NULL;
|
|
char *block = NULL;
|
|
int iBlock = 0;
|
|
int iBlockIndex = 0;
|
|
|
|
// https://stackoverflow.com/questions/26187037/in-c-split-char-on-spaces-with-strtok-function-except-if-between-quotes
|
|
|
|
if (input != NULL) {
|
|
token = input;
|
|
lead = input;
|
|
} else {
|
|
lead = token;
|
|
if (*token == 0) lead = NULL;
|
|
}
|
|
|
|
while (*token != 0) {
|
|
|
|
if (iBlock) {
|
|
if (closeblock[iBlockIndex] == *token) {
|
|
iBlock = 0;
|
|
}
|
|
token++;
|
|
continue;
|
|
}
|
|
|
|
if ((block = strchr(openblock, *token)) != NULL) {
|
|
iBlock = 1;
|
|
iBlockIndex = (int)(block - openblock);
|
|
token++;
|
|
continue;
|
|
}
|
|
|
|
if (strchr(delimit, *token) != NULL) {
|
|
*token = 0;
|
|
token++;
|
|
break;
|
|
}
|
|
|
|
token++;
|
|
}
|
|
|
|
return lead;
|
|
}
|
|
|
|
|
|
WindowDataT *utilGetWindowData(GtkWidget *window) {
|
|
return hmget(_windowList, window);
|
|
}
|
|
|
|
|
|
gboolean utilGetWidgetsFromMemory(char *resource, char *name[], GtkWidget **widgets[], gpointer userData) {
|
|
GtkBuilder *gtkBuilder;
|
|
int x;
|
|
|
|
gtkBuilder = gtk_builder_new();
|
|
if (gtk_builder_add_from_resource(gtkBuilder, resource, NULL) == 0) {
|
|
printf("Failed to build UI '%s'!\n", name[0]);
|
|
exit(1);
|
|
}
|
|
|
|
x = 0;
|
|
while (name[x] != NULL) {
|
|
*widgets[x] = GTK_WIDGET(gtk_builder_get_object(gtkBuilder, name[x]));
|
|
// Set the widget name property to the ID we used to find it.
|
|
gtk_widget_set_name(*widgets[x], name[x]);
|
|
x++;
|
|
}
|
|
|
|
gtk_builder_connect_signals(gtkBuilder, userData);
|
|
g_object_unref(G_OBJECT(gtkBuilder));
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
void utilMessageDialog(GtkWidget *parent, char *title, char *message) {
|
|
GtkWidget *dialog;
|
|
|
|
dialog = gtk_message_dialog_new(
|
|
GTK_WINDOW(parent),
|
|
GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL,
|
|
GTK_MESSAGE_INFO,
|
|
GTK_BUTTONS_OK,
|
|
"%s", message);
|
|
gtk_window_set_title(GTK_WINDOW(dialog), title);
|
|
gtk_dialog_run(GTK_DIALOG(dialog));
|
|
gtk_widget_destroy(dialog);
|
|
}
|
|
|
|
|
|
gboolean utilMkDirP(const char *dir, const mode_t mode) {
|
|
char *p = NULL;
|
|
struct stat sb;
|
|
size_t len;
|
|
|
|
// Make copy of dir.
|
|
len = strnlen(dir, FILENAME_MAX);
|
|
if (len == 0 || len == FILENAME_MAX) {
|
|
return -1;
|
|
}
|
|
memcpy(__utilFilenameBuffer, dir, len);
|
|
__utilFilenameBuffer[len] = '\0';
|
|
|
|
// Remove trailing slash.
|
|
if (__utilFilenameBuffer[len - 1] == UTIL_PATH_CHAR) {
|
|
__utilFilenameBuffer[len - 1] = '\0';
|
|
}
|
|
|
|
// Does it already exist?
|
|
if (stat(__utilFilenameBuffer, &sb) == 0) {
|
|
if (S_ISDIR(sb.st_mode)) {
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
// Recursive mkdir.
|
|
for (p = __utilFilenameBuffer + 1; *p; p++) {
|
|
if (*p == UTIL_PATH_CHAR) {
|
|
*p = 0;
|
|
if (stat(__utilFilenameBuffer, &sb) != 0) {
|
|
// Does not exist - create it.
|
|
if (ourMkdir(__utilFilenameBuffer, mode) < 0) {
|
|
return FALSE;
|
|
}
|
|
} else {
|
|
if (!S_ISDIR(sb.st_mode)) {
|
|
// Not a directory
|
|
return FALSE;
|
|
}
|
|
}
|
|
*p = UTIL_PATH_CHAR;
|
|
}
|
|
}
|
|
// Check path
|
|
if (stat(__utilFilenameBuffer, &sb) != 0) {
|
|
// Does not exist - create it.
|
|
if (ourMkdir(__utilFilenameBuffer, mode) < 0) {
|
|
return FALSE;
|
|
}
|
|
} else {
|
|
if (!S_ISDIR(sb.st_mode)) {
|
|
// Not a directory
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
char *utilObfuscateASCII(char *clearText) {
|
|
char *obfuscated = NULL;
|
|
char *hostname;
|
|
int i;
|
|
int j;
|
|
int c;
|
|
|
|
// Valid ASCII 32 - 126 (94 chars)
|
|
|
|
hostname = strdup(g_get_host_name());
|
|
|
|
// Obfuscate.
|
|
j = 0;
|
|
obfuscated = (char *)malloc((strlen(clearText) + 1) * sizeof(char));
|
|
for (i=0; i<strlen(clearText); i++) {
|
|
c = clearText[i] + hostname[j] - 32;
|
|
while (c > 94) c -= 94;
|
|
obfuscated[i] = (char)(c + 32);
|
|
j++;
|
|
if (j >= strlen(hostname)) j = 0;
|
|
}
|
|
obfuscated[i] = 0;
|
|
|
|
DEL(hostname);
|
|
|
|
return obfuscated;
|
|
}
|
|
|
|
|
|
gboolean utilQuestionDialog(GtkWidget *parent, char *title, char *question) {
|
|
GtkWidget *dialog;
|
|
int response;
|
|
|
|
dialog = gtk_message_dialog_new(
|
|
GTK_WINDOW(parent),
|
|
GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL,
|
|
GTK_MESSAGE_QUESTION,
|
|
GTK_BUTTONS_OK_CANCEL,
|
|
"%s", question);
|
|
gtk_window_set_title(GTK_WINDOW(dialog), title);
|
|
response = gtk_dialog_run(GTK_DIALOG(dialog));
|
|
gtk_widget_destroy(dialog);
|
|
|
|
return (response == GTK_RESPONSE_OK) ? TRUE : FALSE;
|
|
}
|
|
|
|
|
|
void utilSetDirty(WindowDataT *self, gboolean dirty) {
|
|
char *title;
|
|
|
|
self->isDirty = dirty;
|
|
if (dirty) {
|
|
if (self->filename) {
|
|
title = utilCreateString("%s - * %s", self->title, self->filename);
|
|
} else {
|
|
title = utilCreateString("%s - * (no name)", self->title);
|
|
}
|
|
} else {
|
|
if (self->filename) {
|
|
title = utilCreateString("%s - %s", self->title, self->filename);
|
|
} else {
|
|
title = utilCreateString("%s", self->title);
|
|
}
|
|
}
|
|
gtk_window_set_title(GTK_WINDOW(self->window), title);
|
|
DEL(title);
|
|
}
|
|
|
|
|
|
void utilShutdown(void) {
|
|
g_idle_remove_by_data(utilDecompressUpdate);
|
|
}
|
|
|
|
|
|
void utilStartup(void) {
|
|
g_idle_add(utilDecompressUpdate, utilDecompressUpdate);
|
|
}
|
|
|
|
|
|
void utilUpdatePath(WindowDataT *self) {
|
|
DEL(self->path);
|
|
self->path = utilFilePath(self->filename);
|
|
}
|
|
|
|
|
|
void utilWindowRegister(gpointer windowData) {
|
|
WindowDataT *w = (WindowDataT *)windowData;
|
|
|
|
// Grab title.
|
|
w->title = strdup(gtk_window_get_title(GTK_WINDOW(w->window)));
|
|
|
|
gtk_widget_show_all(w->window);
|
|
utilForceUpdate();
|
|
|
|
hmput(_windowList, w->window, windowData);
|
|
debug("Window Registered: %ld\n", hmlen(_windowList));
|
|
}
|
|
|
|
|
|
int utilWindowsCloseAll(void) {
|
|
WindowDataT *w;
|
|
|
|
debug("Windows Left Open: %ld\n", hmlen(_windowList));
|
|
while (hmlen(_windowList) > 0) {
|
|
w = (WindowDataT *)_windowList[0].value;
|
|
if (w->closeWindow(w->window, w) == TRUE) {
|
|
// User canceled closing.
|
|
break;
|
|
}
|
|
}
|
|
|
|
return utilWindowsOpen();
|
|
}
|
|
|
|
|
|
int utilWindowsOpen(void) {
|
|
return hmlen(_windowList);
|
|
}
|
|
|
|
|
|
gboolean utilWindowUnRegister(gpointer windowData) {
|
|
int result;
|
|
WindowDataT *w = (WindowDataT *)windowData;
|
|
|
|
result = hmdel(_windowList, w->window);
|
|
debug("Window Unregistered: %ld\n", hmlen(_windowList));
|
|
|
|
DEL(w->filename);
|
|
DEL(w->path);
|
|
DEL(w->title);
|
|
|
|
return (result == 1) ? TRUE : FALSE;
|
|
}
|