2014-11-23 02:48:41 +00:00
|
|
|
#include "wmcliphist.h"
|
2014-11-23 02:48:37 +00:00
|
|
|
|
|
|
|
|
|
|
|
int autosave_period = 120;
|
|
|
|
int confirm_exec = 0;
|
|
|
|
int exec_immediately = 1;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* process new history item
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
process_item(char *content, gint locked, gboolean exec)
|
|
|
|
{
|
|
|
|
GList *list_node;
|
|
|
|
ACTION *action;
|
|
|
|
gboolean processed = FALSE;
|
|
|
|
HISTORY_ITEM *hist_item;
|
|
|
|
|
|
|
|
begin_func("process_item");
|
|
|
|
|
|
|
|
list_node = g_list_first(action_list);
|
|
|
|
while (list_node) {
|
|
|
|
|
|
|
|
action = (ACTION *)list_node->data;
|
|
|
|
|
|
|
|
/* check if some action is requested */
|
|
|
|
if (regexec(&action->expression, content, 0, NULL, 0) != 0) {
|
|
|
|
list_node = g_list_next(list_node);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* match - execute requested action */
|
|
|
|
|
|
|
|
if (action->action == ACT_IGNORE) {
|
|
|
|
processed = TRUE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (action->action == ACT_EXEC && exec_immediately == TRUE
|
|
|
|
&& exec == TRUE) {
|
|
|
|
exec_item(content, action);
|
2014-11-23 02:48:42 +00:00
|
|
|
}
|
2014-11-23 02:48:37 +00:00
|
|
|
if (action->action == ACT_SUBMENU) {
|
|
|
|
/* test if such item already exists in this menu */
|
|
|
|
processed = TRUE;
|
|
|
|
|
|
|
|
/* add item to menu and item list */
|
|
|
|
hist_item = menu_item_add(content, locked,
|
|
|
|
action->submenu);
|
|
|
|
|
|
|
|
/* when auto_take_up is true, set selection owner to myself */
|
|
|
|
if (auto_take_up == 1) {
|
|
|
|
selected = hist_item;
|
|
|
|
if (gtk_selection_owner_set(dock_app,
|
2014-11-23 02:48:52 +00:00
|
|
|
clipboard,
|
2014-11-23 02:48:37 +00:00
|
|
|
GDK_CURRENT_TIME) == 0) {
|
|
|
|
selected = NULL;
|
|
|
|
}
|
|
|
|
}
|
2014-11-23 02:48:42 +00:00
|
|
|
|
2014-11-23 02:48:37 +00:00
|
|
|
dump_history_list("added item");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
list_node = g_list_next(list_node);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (processed == FALSE) {
|
|
|
|
hist_item = menu_item_add(content, locked, menu_hist);
|
2014-11-23 02:48:42 +00:00
|
|
|
|
2014-11-23 02:48:37 +00:00
|
|
|
/* when auto_take_up is true, set selection owner to myself */
|
|
|
|
if (auto_take_up == 1) {
|
|
|
|
selected = hist_item;
|
|
|
|
if (gtk_selection_owner_set(dock_app,
|
2014-11-23 02:48:52 +00:00
|
|
|
clipboard,
|
2014-11-23 02:48:37 +00:00
|
|
|
GDK_CURRENT_TIME) == 0) {
|
|
|
|
selected = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return_void();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
move_item_to_begin(HISTORY_ITEM *item) {
|
|
|
|
GList *list_node;
|
|
|
|
|
|
|
|
begin_func("menu_item_activated");
|
|
|
|
|
|
|
|
if (!(list_node = g_list_find(history_items, item))) {
|
|
|
|
g_assert((list_node != NULL));
|
|
|
|
}
|
|
|
|
|
|
|
|
gtk_menu_popdown(GTK_MENU(menu_hist));
|
|
|
|
/* move previously stored item to beginning */
|
|
|
|
gtk_menu_reorder_child(GTK_MENU(item->menu),
|
|
|
|
item->menu_item, 1);
|
|
|
|
history_items = g_list_remove_link(history_items, list_node);
|
|
|
|
history_items = g_list_concat(list_node, history_items);
|
|
|
|
selected = item;
|
|
|
|
if (gtk_selection_owner_set(dock_app,
|
2014-11-23 02:48:52 +00:00
|
|
|
clipboard,
|
2014-11-23 02:48:37 +00:00
|
|
|
GDK_CURRENT_TIME) == 0)
|
|
|
|
selected = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Exec's an action on item.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
exec_item(char *content, ACTION *action)
|
|
|
|
{
|
|
|
|
int msg_result = 0, res;
|
|
|
|
gchar *msg_buf;
|
|
|
|
gchar *exec_buf;
|
|
|
|
gchar *converted;
|
|
|
|
|
|
|
|
converted = from_utf8(content);
|
2014-11-23 02:48:42 +00:00
|
|
|
|
2014-11-23 02:48:37 +00:00
|
|
|
/* If we're not given an action to perform, find the first matching
|
|
|
|
* exec action, and perform it */
|
|
|
|
if (!action) {
|
|
|
|
GList *list_node;
|
|
|
|
ACTION *a;
|
|
|
|
list_node = g_list_first(action_list);
|
|
|
|
while (list_node) {
|
|
|
|
a = (ACTION *)list_node->data;
|
|
|
|
/* check if some action is requested */
|
|
|
|
if ((regexec(&a->expression, converted, 0, NULL, 0)
|
|
|
|
== 0)
|
|
|
|
&& (a->action == ACT_EXEC)) {
|
|
|
|
action = a;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
list_node = g_list_next(list_node);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!action || action->action != ACT_EXEC) {
|
|
|
|
g_free(converted);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
exec_buf = g_new0(char, strlen(converted) +
|
|
|
|
strlen(action->command) + 1);
|
|
|
|
sprintf(exec_buf, action->command, converted);
|
|
|
|
if (confirm_exec) {
|
|
|
|
msg_buf = g_new0(char, strlen(exec_buf) + 256);
|
|
|
|
sprintf(msg_buf, "Do you want to perform the "
|
|
|
|
"following action?\n\n%s",
|
|
|
|
exec_buf);
|
|
|
|
msg_result = show_message(msg_buf,
|
|
|
|
"wmcliphist", "Yes", "No", NULL);
|
|
|
|
g_free(msg_buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* create child and exec command */
|
|
|
|
if (msg_result == 0 && fork() == 0) {
|
|
|
|
/* child */
|
|
|
|
res = system(exec_buf);
|
|
|
|
if (res == -1)
|
|
|
|
fprintf(stderr, "Cannot exec '%s'\n", exec_buf);
|
|
|
|
else if (res == 127)
|
|
|
|
fprintf(stderr, "/bin/sh not found\n");
|
|
|
|
g_free(exec_buf);
|
|
|
|
g_free(converted);
|
|
|
|
_exit(0);
|
|
|
|
} else {
|
|
|
|
/* parent */
|
|
|
|
g_free(exec_buf);
|
|
|
|
g_free(converted);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* loads history from file
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
history_load(gboolean dump_only)
|
|
|
|
{
|
|
|
|
gchar *buf;
|
|
|
|
gint len;
|
|
|
|
gint ver;
|
|
|
|
FILE *f;
|
|
|
|
gchar *fname;
|
|
|
|
gint locked;
|
|
|
|
int tmp_errno = 0;
|
|
|
|
|
|
|
|
begin_func("history_load");
|
|
|
|
|
|
|
|
fname = rcconfig_get_name(".data");
|
|
|
|
if (!(f = fopen(fname, "r"))) {
|
|
|
|
errno = E_OPEN;
|
|
|
|
return_val(-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fread(&ver, sizeof(gint), 1, f) != 1) {
|
|
|
|
fclose(f);
|
|
|
|
return_val(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* delete old history file */
|
|
|
|
if (ver == 0x0001) {
|
|
|
|
fclose(f);
|
|
|
|
if (remove(rcconfig_get_name(".data"))) {
|
|
|
|
errno = E_REMOVE;
|
|
|
|
return_val(-1);
|
|
|
|
}
|
|
|
|
return_val(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dump_only) {
|
|
|
|
printf("<history>\n");
|
|
|
|
}
|
|
|
|
while (!feof(f)) {
|
|
|
|
|
|
|
|
if (fread(&len, sizeof(gint), 1, f) != 1)
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (num_items == num_items_to_keep && !dump_only) {
|
|
|
|
tmp_errno = E_TOO_MUCH;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
buf = g_new0(gchar, len + 1);
|
|
|
|
if (fread(buf, len, 1, f) != 1) {
|
|
|
|
g_free(buf);
|
|
|
|
tmp_errno = E_INVALID;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
buf[len] = '\0';
|
|
|
|
|
|
|
|
if (fread(&locked, sizeof(gint), 1, f) != 1) {
|
|
|
|
g_free(buf);
|
|
|
|
tmp_errno = E_INVALID;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dump_only) {
|
|
|
|
printf("<item>%s</item>\n", buf);
|
|
|
|
} else {
|
|
|
|
process_item(buf, locked, FALSE);
|
|
|
|
}
|
|
|
|
g_free(buf);
|
|
|
|
|
|
|
|
}
|
|
|
|
fclose(f);
|
|
|
|
|
|
|
|
if (dump_only) {
|
|
|
|
printf("</history>\n");
|
|
|
|
} else {
|
|
|
|
dump_history_list("load_history()");
|
|
|
|
}
|
|
|
|
|
|
|
|
errno = tmp_errno;
|
2014-11-23 02:48:42 +00:00
|
|
|
|
2014-11-23 02:48:37 +00:00
|
|
|
if (errno == 0)
|
|
|
|
return_val(0);
|
|
|
|
else
|
|
|
|
return_val(-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* store history to file
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
history_save()
|
|
|
|
{
|
|
|
|
char *fname;
|
|
|
|
gint version = VERSION;
|
|
|
|
FILE *f;
|
|
|
|
HISTORY_ITEM *hist_item;
|
|
|
|
GList *list_node;
|
|
|
|
int tmp_errno = 0;
|
|
|
|
|
|
|
|
begin_func("history_save");
|
|
|
|
|
|
|
|
fname = g_strdup(rcconfig_get_name(".data.tmp"));
|
|
|
|
|
|
|
|
if (!(f = fopen(fname, "w"))) {
|
|
|
|
perror("fopen");
|
|
|
|
g_free(fname);
|
|
|
|
errno = E_OPEN;
|
|
|
|
return_val(-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((chmod(fname, S_IRUSR|S_IWUSR)) != 0) {
|
|
|
|
perror("chmod");
|
|
|
|
fclose(f);
|
|
|
|
unlink(fname);
|
|
|
|
g_free(fname);
|
|
|
|
errno = E_OPEN;
|
|
|
|
return_val(-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fwrite(&version, sizeof(gint), 1, f) != 1) {
|
|
|
|
perror("fwrite version");
|
|
|
|
fclose(f);
|
|
|
|
unlink(fname);
|
|
|
|
g_free(fname);
|
|
|
|
errno = E_WRITE;
|
|
|
|
return_val(-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
list_node = g_list_last(history_items);
|
|
|
|
while (list_node) {
|
|
|
|
int length;
|
|
|
|
hist_item = (HISTORY_ITEM *)list_node->data;
|
|
|
|
length = strlen(hist_item->content);
|
|
|
|
if (fwrite(&length, sizeof(gint), 1, f) != 1) {
|
|
|
|
tmp_errno = E_WRITE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (fwrite(hist_item->content, length, 1, f) != 1) {
|
|
|
|
tmp_errno = E_WRITE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (fwrite(&hist_item->locked, sizeof(gint), 1, f) != 1) {
|
|
|
|
tmp_errno = E_WRITE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
list_node = g_list_previous(list_node);
|
|
|
|
}
|
|
|
|
|
|
|
|
fclose(f);
|
|
|
|
|
|
|
|
if (!list_node) {
|
|
|
|
if (rename(fname, rcconfig_get_name(".data")) != 0) {
|
|
|
|
perror("rename");
|
|
|
|
unlink(fname);
|
|
|
|
g_free(fname);
|
|
|
|
errno = E_RENAME;
|
|
|
|
return_val(-1);
|
|
|
|
}
|
|
|
|
g_free(fname);
|
|
|
|
return_val(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
errno = tmp_errno;
|
|
|
|
unlink(fname);
|
|
|
|
g_free(fname);
|
|
|
|
|
|
|
|
return_val(-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* free history data
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
history_free()
|
|
|
|
{
|
|
|
|
HISTORY_ITEM *hist_item;
|
|
|
|
GList *list_node;
|
|
|
|
|
|
|
|
begin_func("history_free");
|
|
|
|
|
|
|
|
list_node = g_list_last(history_items);
|
|
|
|
while (list_node) {
|
|
|
|
hist_item = (HISTORY_ITEM *)list_node->data;
|
|
|
|
gtk_container_remove(GTK_CONTAINER(hist_item->menu),
|
|
|
|
hist_item->menu_item);
|
|
|
|
gtk_widget_destroy(hist_item->menu_item);
|
|
|
|
g_free(hist_item->content);
|
|
|
|
g_free(hist_item);
|
|
|
|
list_node = g_list_previous(list_node);
|
|
|
|
}
|
|
|
|
g_list_free(history_items);
|
|
|
|
|
|
|
|
return_void();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* autosave timer function
|
|
|
|
*/
|
|
|
|
gboolean
|
|
|
|
history_autosave()
|
|
|
|
{
|
|
|
|
begin_func("history_autosave");
|
|
|
|
|
|
|
|
history_save();
|
|
|
|
return_val(TRUE);
|
|
|
|
}
|
|
|
|
|