Added autobuild tools

This commit is contained in:
James Booth
2012-07-01 14:47:09 +01:00
parent 9e686c0e01
commit 30ca6cac3d
38 changed files with 14 additions and 55 deletions

396
src/command.c Normal file
View File

@@ -0,0 +1,396 @@
/*
* command.c
*
* Copyright (C) 2012 James Booth <boothj5@gmail.com>
*
* This file is part of Profanity.
*
* Profanity is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Profanity is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <string.h>
#include <stdlib.h>
#include <glib.h>
#include "command.h"
#include "contact_list.h"
#include "history.h"
#include "jabber.h"
#include "ui.h"
#include "util.h"
#include "preferences.h"
#include "prof_autocomplete.h"
static gboolean _handle_command(const char * const command,
const char * const inp);
static gboolean _cmd_quit(const char * const inp);
static gboolean _cmd_help(const char * const inp);
static gboolean _cmd_who(const char * const inp);
static gboolean _cmd_ros(const char * const inp);
static gboolean _cmd_connect(const char * const inp);
static gboolean _cmd_msg(const char * const inp);
static gboolean _cmd_close(const char * const inp);
static gboolean _cmd_set_beep(const char * const inp);
static gboolean _cmd_set_notify(const char * const inp);
static gboolean _cmd_set_flash(const char * const inp);
static gboolean _cmd_set_showsplash(const char * const inp);
static gboolean _cmd_away(const char * const inp);
static gboolean _cmd_online(const char * const inp);
static gboolean _cmd_dnd(const char * const inp);
static gboolean _cmd_chat(const char * const inp);
static gboolean _cmd_xa(const char * const inp);
static gboolean _cmd_default(const char * const inp);
static void _update_presence(const jabber_presence_t presence,
const char * const show, const char * const inp);
struct cmd_t {
const gchar *cmd;
gboolean (*func)(const char * const inp);
};
static PAutocomplete commands_ac;
static struct cmd_t commands[] = {
{ "/away", _cmd_away },
{ "/beep", _cmd_set_beep },
{ "/notify", _cmd_set_notify },
{ "/chat", _cmd_chat },
{ "/close", _cmd_close },
{ "/connect", _cmd_connect },
{ "/dnd", _cmd_dnd },
{ "/flash", _cmd_set_flash },
{ "/help", _cmd_help },
{ "/msg", _cmd_msg },
{ "/online", _cmd_online },
{ "/quit", _cmd_quit },
{ "/ros", _cmd_ros },
{ "/showsplash", _cmd_set_showsplash },
{ "/who", _cmd_who },
{ "/xa", _cmd_xa },
};
static const int num_cmds = 15;
gboolean process_input(char *inp)
{
gboolean result = FALSE;
g_strstrip(inp);
if (strlen(inp) > 0)
history_append(inp);
if (strlen(inp) == 0) {
result = TRUE;
} else if (inp[0] == '/') {
char inp_cpy[strlen(inp) + 1];
strcpy(inp_cpy, inp);
char *command = strtok(inp_cpy, " ");
result = _handle_command(command, inp);
} else {
result = _cmd_default(inp);
}
inp_clear();
reset_search_attempts();
win_page_off();
return result;
}
void command_init(void)
{
commands_ac = p_autocomplete_new();
int i;
for (i = 0; i < num_cmds; i++) {
struct cmd_t *pcmd = commands+i;
p_autocomplete_add(commands_ac, (gchar *)pcmd->cmd);
}
history_init();
}
char * cmd_complete(char *inp)
{
return p_autocomplete_complete(commands_ac, inp);
}
void reset_command_completer(void)
{
p_autocomplete_reset(commands_ac);
}
static gboolean _handle_command(const char * const command, const char * const inp)
{
int i;
for (i = 0; i < num_cmds; i++) {
struct cmd_t *pcmd = commands+i;
if (strcmp(pcmd->cmd, command) == 0) {
return (pcmd->func(inp));
}
}
return _cmd_default(inp);
}
static gboolean _cmd_connect(const char * const inp)
{
gboolean result = FALSE;
jabber_conn_status_t conn_status = jabber_connection_status();
if ((conn_status != JABBER_DISCONNECTED) && (conn_status != JABBER_STARTED)) {
cons_show("You are either connected already, or a login is in process.");
result = TRUE;
} else if (strlen(inp) < 10) {
cons_show("Usage: /connect user@host");
result = TRUE;
} else {
char *user;
user = strndup(inp+9, strlen(inp)-9);
status_bar_get_password();
status_bar_refresh();
char passwd[21];
inp_block();
inp_get_password(passwd);
inp_non_block();
conn_status = jabber_connect(user, passwd);
if (conn_status == JABBER_CONNECTING)
cons_show("Connecting...");
if (conn_status == JABBER_DISCONNECTED)
cons_bad_show("Connection to server failed.");
result = TRUE;
}
return result;
}
static gboolean _cmd_quit(const char * const inp)
{
return FALSE;
}
static gboolean _cmd_help(const char * const inp)
{
cons_help();
return TRUE;
}
static gboolean _cmd_ros(const char * const inp)
{
jabber_conn_status_t conn_status = jabber_connection_status();
if (conn_status != JABBER_CONNECTED)
cons_show("You are not currently connected.");
else
jabber_roster_request();
return TRUE;
}
static gboolean _cmd_who(const char * const inp)
{
jabber_conn_status_t conn_status = jabber_connection_status();
if (conn_status != JABBER_CONNECTED) {
cons_show("You are not currently connected.");
} else {
GSList *list = get_contact_list();
cons_show_online_contacts(list);
}
return TRUE;
}
static gboolean _cmd_msg(const char * const inp)
{
char *usr = NULL;
char *msg = NULL;
jabber_conn_status_t conn_status = jabber_connection_status();
if (conn_status != JABBER_CONNECTED) {
cons_show("You are not currently connected.");
} else {
// copy input
char inp_cpy[strlen(inp) + 1];
strcpy(inp_cpy, inp);
// get user
strtok(inp_cpy, " ");
usr = strtok(NULL, " ");
if ((usr != NULL) && (strlen(inp) > (5 + strlen(usr) + 1))) {
// get message
msg = strndup(inp+5+strlen(usr)+1, strlen(inp)-(5+strlen(usr)+1));
if (msg != NULL) {
jabber_send(msg, usr);
win_show_outgoing_msg("me", usr, msg);
} else {
cons_show("Usage: /msg user@host message");
}
} else {
cons_show("Usage: /msg user@host message");
}
}
return TRUE;
}
static gboolean _cmd_close(const char * const inp)
{
if (!win_close_win())
cons_bad_command(inp);
return TRUE;
}
static gboolean _cmd_set_beep(const char * const inp)
{
if (strcmp(inp, "/beep on") == 0) {
cons_show("Sound enabled.");
prefs_set_beep(TRUE);
} else if (strcmp(inp, "/beep off") == 0) {
cons_show("Sound disabled.");
prefs_set_beep(FALSE);
} else {
cons_show("Usage: /beep <on/off>");
}
return TRUE;
}
static gboolean _cmd_set_notify(const char * const inp)
{
if (strcmp(inp, "/notify on") == 0) {
cons_show("Desktop notifications enabled.");
prefs_set_notify(TRUE);
} else if (strcmp(inp, "/notify off") == 0) {
cons_show("Desktop notifications disabled.");
prefs_set_notify(FALSE);
} else {
cons_show("Usage: /notify <on/off>");
}
return TRUE;
}
static gboolean _cmd_set_flash(const char * const inp)
{
if (strcmp(inp, "/flash on") == 0) {
cons_show("Screen flash enabled.");
prefs_set_flash(TRUE);
} else if (strcmp(inp, "/flash off") == 0) {
cons_show("Screen flash disabled.");
prefs_set_flash(FALSE);
} else {
cons_show("Usage: /flash <on/off>");
}
return TRUE;
}
static gboolean _cmd_set_showsplash(const char * const inp)
{
if (strcmp(inp, "/showsplash on") == 0) {
cons_show("Splash screen enabled.");
prefs_set_showsplash(TRUE);
} else if (strcmp(inp, "/showsplash off") == 0) {
cons_show("Splash screen disabled.");
prefs_set_showsplash(FALSE);
} else {
cons_show("Usage: /showsplash <on/off>");
}
return TRUE;
}
static gboolean _cmd_away(const char * const inp)
{
_update_presence(PRESENCE_AWAY, "away", inp);
return TRUE;
}
static gboolean _cmd_online(const char * const inp)
{
_update_presence(PRESENCE_ONLINE, "online", inp);
return TRUE;
}
static gboolean _cmd_dnd(const char * const inp)
{
_update_presence(PRESENCE_DND, "dnd", inp);
return TRUE;
}
static gboolean _cmd_chat(const char * const inp)
{
_update_presence(PRESENCE_CHAT, "chat", inp);
return TRUE;
}
static gboolean _cmd_xa(const char * const inp)
{
_update_presence(PRESENCE_XA, "xa", inp);
return TRUE;
}
static gboolean _cmd_default(const char * const inp)
{
if (win_in_chat()) {
char *recipient = win_get_recipient();
jabber_send(inp, recipient);
win_show_outgoing_msg("me", recipient, inp);
free(recipient);
} else {
cons_bad_command(inp);
}
return TRUE;
}
static void _update_presence(const jabber_presence_t presence,
const char * const show, const char * const inp)
{
char *msg;
if (strlen(inp) > strlen(show) + 2) {
msg = strndup(inp+(strlen(show) + 2), strlen(inp)-(strlen(show) + 2));
} else {
msg = NULL;
}
jabber_conn_status_t conn_status = jabber_connection_status();
if (conn_status != JABBER_CONNECTED) {
cons_show("You are not currently connected.");
} else {
jabber_update_presence(presence, msg);
title_bar_set_status(presence);
if (msg != NULL) {
char str[14 + strlen(show) + 3 + strlen(msg) + 2];
sprintf(str, "Status set to %s, \"%s\"", show, msg);
cons_show(str);
free(msg);
} else {
char str[14 + strlen(show) + 1];
sprintf(str, "Status set to %s", show);
cons_show(str);
}
}
}

31
src/command.h Normal file
View File

@@ -0,0 +1,31 @@
/*
* command.h
*
* Copyright (C) 2012 James Booth <boothj5@gmail.com>
*
* This file is part of Profanity.
*
* Profanity is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Profanity is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef COMMAND_H
#define COMMAND_H
void command_init(void);
gboolean process_input(char *inp);
char * cmd_complete(char *inp);
void reset_command_completer(void);
#endif

29
src/common.c Normal file
View File

@@ -0,0 +1,29 @@
/*
* common.c
*
* Copyright (C) 2012 James Booth <boothj5@gmail.com>
*
* This file is part of Profanity.
*
* Profanity is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Profanity is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <glib.h>
void p_slist_free_full(GSList *items, GDestroyNotify free_func)
{
g_slist_foreach (items, (GFunc) free_func, NULL);
g_slist_free (items);
}

54
src/common.h Normal file
View File

@@ -0,0 +1,54 @@
/*
* common.h
*
* Copyright (C) 2012 James Booth <boothj5@gmail.com>
*
* This file is part of Profanity.
*
* Profanity is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Profanity is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef COMMON_H
#define COMMON_H
#include <glib.h>
typedef enum {
JABBER_STARTED,
JABBER_CONNECTING,
JABBER_CONNECTED,
JABBER_DISCONNECTED
} jabber_conn_status_t;
typedef enum {
PRESENCE_OFFLINE,
PRESENCE_ONLINE,
PRESENCE_AWAY,
PRESENCE_DND,
PRESENCE_CHAT,
PRESENCE_XA
} jabber_presence_t;
#if !GLIB_CHECK_VERSION(2,28,0)
#define g_slist_free_full(items, free_func) p_slist_free_full(items, free_func)
#endif
#ifndef NOTIFY_CHECK_VERSION
#define notify_notification_new(summary, body, icon) notify_notification_new(summary, body, icon, NULL)
#endif
void p_slist_free_full(GSList *items, GDestroyNotify free_func);
#endif

108
src/contact.c Normal file
View File

@@ -0,0 +1,108 @@
/*
* contact.c
*
* Copyright (C) 2012 James Booth <boothj5@gmail.com>
*
* This file is part of Profanity.
*
* Profanity is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Profanity is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <stdlib.h>
#include <string.h>
#include <glib.h>
#include "contact.h"
struct p_contact_t {
char *name;
char *show;
char *status;
};
PContact p_contact_new(const char * const name, const char * const show,
const char * const status)
{
PContact contact = malloc(sizeof(struct p_contact_t));
contact->name = strdup(name);
if (show == NULL || (strcmp(show, "") == 0))
contact->show = strdup("online");
else
contact->show = strdup(show);
if (status != NULL)
contact->status = strdup(status);
else
contact->status = NULL;
return contact;
}
PContact p_contact_copy(PContact contact)
{
PContact copy = malloc(sizeof(struct p_contact_t));
copy->name = strdup(contact->name);
copy->show = strdup(contact->show);
if (contact->status != NULL)
copy->status = strdup(contact->status);
else
copy->status = NULL;
return copy;
}
void p_contact_free(PContact contact)
{
free(contact->name);
if (contact->show != NULL) {
free(contact->show);
contact->show = NULL;
}
if (contact->status != NULL) {
free(contact->status);
contact->status = NULL;
}
free(contact);
contact = NULL;
}
const char * p_contact_name(const PContact contact)
{
return contact->name;
}
const char * p_contact_show(const PContact contact)
{
return contact->show;
}
const char * p_contact_status(const PContact contact)
{
return contact->status;
}
int p_contacts_equal_deep(const PContact c1, const PContact c2)
{
int name_eq = (g_strcmp0(c1->name, c2->name) == 0);
int show_eq = (g_strcmp0(c1->show, c2->show) == 0);
int status_eq = (g_strcmp0(c1->status, c2->status) == 0);
return (name_eq && show_eq && status_eq);
}

37
src/contact.h Normal file
View File

@@ -0,0 +1,37 @@
/*
* contact.h
*
* Copyright (C) 2012 James Booth <boothj5@gmail.com>
*
* This file is part of Profanity.
*
* Profanity is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Profanity is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef CONTACT_H
#define CONTACT_H
typedef struct p_contact_t *PContact;
PContact p_contact_new(const char * const name, const char * const show,
const char * const status);
PContact p_contact_copy(PContact contact);
void p_contact_free(PContact contact);
const char * p_contact_name(PContact contact);
const char * p_contact_show(PContact contact);
const char * p_contact_status(PContact contact);
int p_contacts_equal_deep(const PContact c1, const PContact c2);
#endif

72
src/contact_list.c Normal file
View File

@@ -0,0 +1,72 @@
/*
* contact_list.c
*
* Copyright (C) 2012 James Booth <boothj5@gmail.com>
*
* This file is part of Profanity.
*
* Profanity is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Profanity is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <glib.h>
#include "contact.h"
#include "contact_list.h"
#include "prof_autocomplete.h"
static PAutocomplete ac;
void contact_list_init(void)
{
ac = p_obj_autocomplete_new((PStrFunc)p_contact_name,
(PCopyFunc)p_contact_copy,
(PEqualDeepFunc)p_contacts_equal_deep,
(GDestroyNotify)p_contact_free);
}
void contact_list_clear(void)
{
p_autocomplete_clear(ac);
}
void reset_search_attempts(void)
{
p_autocomplete_reset(ac);
}
gboolean contact_list_remove(const char * const name)
{
return p_autocomplete_remove(ac, name);
}
gboolean contact_list_add(const char * const name, const char * const show,
const char * const status)
{
return p_autocomplete_add(ac, p_contact_new(name, show, status));
}
GSList * get_contact_list(void)
{
return p_autocomplete_get_list(ac);
}
char * find_contact(char *search_str)
{
return p_autocomplete_complete(ac, search_str);
}

39
src/contact_list.h Normal file
View File

@@ -0,0 +1,39 @@
/*
* contact_list.h
*
* Copyright (C) 2012 James Booth <boothj5@gmail.com>
*
* This file is part of Profanity.
*
* Profanity is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Profanity is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef CONTACT_LIST_H
#define CONTACT_LIST_H
#include <glib.h>
#include "contact.h"
void contact_list_init(void);
void contact_list_clear(void);
void reset_search_attempts(void);
gboolean contact_list_add(const char * const name, const char * const show,
const char * const status);
gboolean contact_list_remove(const char * const name);
GSList * get_contact_list(void);
char * find_contact(char *search_str);
#endif

69
src/history.c Normal file
View File

@@ -0,0 +1,69 @@
/*
* history.c
*
* Copyright (C) 2012 James Booth <boothj5@gmail.com>
*
* This file is part of Profanity.
*
* Profanity is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Profanity is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <stdlib.h>
#include <string.h>
#include "prof_history.h"
#define MAX_HISTORY 100
static PHistory history;
void _stringify_input(char *inp, int size, char *string);
void history_init(void)
{
history = p_history_new(MAX_HISTORY);
}
void history_append(char *inp)
{
p_history_append(history, inp);
}
char * history_previous(char *inp, int *size)
{
char inp_str[*size + 1];
_stringify_input(inp, *size, inp_str);
return p_history_previous(history, inp_str);
}
char *history_next(char *inp, int *size)
{
char inp_str[*size + 1];
_stringify_input(inp, *size, inp_str);
return p_history_next(history, inp_str);
}
void _stringify_input(char *inp, int size, char *string)
{
int i;
for (i = 0; i < size; i++) {
string[i] = inp[i];
}
string[size] = '\0';
}

32
src/history.h Normal file
View File

@@ -0,0 +1,32 @@
/*
* history.h
*
* Copyright (C) 2012 James Booth <boothj5@gmail.com>
*
* This file is part of Profanity.
*
* Profanity is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Profanity is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef HISTORY_H
#define HISTORY_H
void history_init(void);
void history_append(char *inp);
char *history_previous(char *inp, int *size);
char *history_next(char *inp, int *size);
#endif

316
src/input_win.c Normal file
View File

@@ -0,0 +1,316 @@
/*
* input_win.c
*
* Copyright (C) 2012 James Booth <boothj5@gmail.com>
*
* This file is part of Profanity.
*
* Profanity is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Profanity is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <http://www.gnu.org/licenses/>.
*
*/
/*
* Non blocking input char handling
*
* *size - holds the current size of input
* *input - holds the current input string, NOT null terminated at this point
* *ch - getch will put a charater here if there was any input
*
* The example below shows the values of size, input, a call to wgetyx to
* find the current cursor location, and the index of the input string.
*
* size : " 7 "
* input : " example "
* inp_x : "012345678"
* index : " 0123456 " (inp_x - 1)
*/
#include <string.h>
#include <stdlib.h>
#include <ncurses.h>
#include "ui.h"
#include "history.h"
#include "preferences.h"
#include "util.h"
#include "command.h"
static WINDOW *inp_win;
static int _handle_edit(const int ch, char *input, int *size);
static int _printable(const int ch);
static void _replace_input(char *input, const char * const new_input, int *size);
void create_input_window(void)
{
int rows, cols;
getmaxyx(stdscr, rows, cols);
inp_win = newwin(1, cols, rows-1, 0);
wbkgd(inp_win, COLOR_PAIR(1));
keypad(inp_win, TRUE);
// wattrset(inp_win, A_BOLD);
wmove(inp_win, 0, 1);
wrefresh(inp_win);
}
void inp_win_resize(const char * const input, const int size)
{
int rows, cols;
getmaxyx(stdscr, rows, cols);
mvwin(inp_win, rows-1, 0);
wresize(inp_win, 1, cols);
wrefresh(inp_win);
}
void inp_clear(void)
{
wclear(inp_win);
wmove(inp_win, 0, 1);
wrefresh(inp_win);
}
void inp_non_block(void)
{
wtimeout(inp_win, 500);
}
void inp_block(void)
{
wtimeout(inp_win, -1);
}
void inp_get_char(int *ch, char *input, int *size)
{
int inp_y = 0;
int inp_x = 0;
int i;
// echo off, and get some more input
noecho();
*ch = wgetch(inp_win);
// if it wasn't an arrow key etc
if (!_handle_edit(*ch, input, size)) {
if (_printable(*ch)) {
getyx(inp_win, inp_y, inp_x);
// handle insert if not at end of input
if (inp_x <= *size) {
winsch(inp_win, *ch);
wmove(inp_win, inp_y, inp_x+1);
for (i = *size; i > inp_x -1; i--)
input[i] = input[i-1];
input[inp_x -1] = *ch;
(*size)++;
// otherwise just append
} else {
waddch(inp_win, *ch);
input[(*size)++] = *ch;
}
reset_search_attempts();
reset_login_search();
reset_command_completer();
}
}
echo();
}
void inp_get_password(char *passwd)
{
wclear(inp_win);
noecho();
mvwgetnstr(inp_win, 0, 1, passwd, 20);
wmove(inp_win, 0, 1);
echo();
status_bar_clear();
}
void inp_put_back(void)
{
wrefresh(inp_win);
}
/*
* Deal with command editing, return 1 if ch was an edit
* key press: up, down, left, right or backspace
* return 0 if it wasnt
*/
static int _handle_edit(const int ch, char *input, int *size)
{
int i;
char *prev = NULL;
char *next = NULL;
char *found = NULL;
char *auto_msg = NULL;
int inp_y = 0;
int inp_x = 0;
char inp_cpy[*size];
getyx(inp_win, inp_y, inp_x);
switch(ch) {
case 127:
case KEY_BACKSPACE:
reset_search_attempts();
if (*size > 0) {
// if at end, delete last char
if (inp_x > *size) {
wmove(inp_win, inp_y, inp_x-1);
wdelch(inp_win);
(*size)--;
// if in middle, delete and shift chars left
} else if (inp_x > 1 && inp_x <= *size) {
for (i = inp_x-1; i < *size; i++)
input[i-1] = input[i];
(*size)--;
inp_clear();
for (i = 0; i < *size; i++)
waddch(inp_win, input[i]);
wmove(inp_win, 0, inp_x -1);
}
}
return 1;
case KEY_DC: // DEL
if (inp_x <= *size) {
wdelch(inp_win);
// if not last char, shift chars left
if (inp_x < *size)
for (i = inp_x-1; i < *size; i++)
input[i] = input[i+1];
(*size)--;
}
return 1;
case KEY_LEFT:
if (inp_x > 1)
wmove(inp_win, inp_y, inp_x-1);
return 1;
case KEY_RIGHT:
if (inp_x <= *size )
wmove(inp_win, inp_y, inp_x+1);
return 1;
case KEY_UP:
prev = history_previous(input, size);
if (prev)
_replace_input(input, prev, size);
return 1;
case KEY_DOWN:
next = history_next(input, size);
if (next)
_replace_input(input, next, size);
return 1;
case KEY_HOME:
wmove(inp_win, inp_y, 1);
return 1;
case KEY_END:
wmove(inp_win, inp_y, (*size) + 1);
return 1;
case 9: // tab
// autocomplete commands
if ((strncmp(input, "/", 1) == 0) && (!str_contains(input, *size, ' '))) {
for(i = 0; i < *size; i++) {
inp_cpy[i] = input[i];
}
inp_cpy[i] = '\0';
found = cmd_complete(inp_cpy);
if (found != NULL) {
auto_msg = (char *) malloc((strlen(found) + 1) * sizeof(char));
strcpy(auto_msg, found);
_replace_input(input, auto_msg, size);
free(auto_msg);
free(found);
}
// autcomplete /msg recipient
} else if ((strncmp(input, "/msg ", 5) == 0) && (*size > 5)) {
for(i = 5; i < *size; i++) {
inp_cpy[i-5] = input[i];
}
inp_cpy[(*size) - 5] = '\0';
found = find_contact(inp_cpy);
if (found != NULL) {
auto_msg = (char *) malloc((5 + (strlen(found) + 1)) * sizeof(char));
strcpy(auto_msg, "/msg ");
strcat(auto_msg, found);
_replace_input(input, auto_msg, size);
free(auto_msg);
free(found);
}
// autocomplete /connect username
} else if ((strncmp(input, "/connect ", 9) == 0) && (*size > 9)) {
for(i = 9; i < *size; i++) {
inp_cpy[i-9] = input[i];
}
inp_cpy[(*size) - 9] = '\0';
found = find_login(inp_cpy);
if (found != NULL) {
auto_msg = (char *) malloc((9 + (strlen(found) + 1)) * sizeof(char));
strcpy(auto_msg, "/connect ");
strcat(auto_msg, found);
_replace_input(input, auto_msg, size);
free(auto_msg);
free(found);
}
}
return 1;
default:
return 0;
}
}
static int _printable(const int ch)
{
return (ch != ERR && ch != '\n' &&
ch != KEY_PPAGE && ch != KEY_NPAGE &&
ch != KEY_F(1) && ch != KEY_F(2) && ch != KEY_F(3) &&
ch != KEY_F(4) && ch != KEY_F(5) && ch != KEY_F(6) &&
ch != KEY_F(7) && ch != KEY_F(8) && ch != KEY_F(9) &&
ch != KEY_F(10) && ch!= KEY_F(11) && ch != KEY_F(12) &&
ch != KEY_IC && ch != KEY_EIC && ch != KEY_RESIZE);
}
static void _replace_input(char *input, const char * const new_input, int *size)
{
int i;
strcpy(input, new_input);
*size = strlen(input);
inp_clear();
for (i = 0; i < *size; i++)
waddch(inp_win, input[i]);
}

410
src/jabber.c Normal file
View File

@@ -0,0 +1,410 @@
/*
* jabber.c
*
* Copyright (C) 2012 James Booth <boothj5@gmail.com>
*
* This file is part of Profanity.
*
* Profanity is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Profanity is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <string.h>
#include <strophe.h>
#include "jabber.h"
#include "common.h"
#include "log.h"
#include "contact_list.h"
#include "ui.h"
#include "util.h"
#include "preferences.h"
#define PING_INTERVAL 120000 // 2 minutes
// log reference
extern FILE *logp;
static struct _jabber_conn_t {
xmpp_log_t *log;
xmpp_ctx_t *ctx;
xmpp_conn_t *conn;
jabber_conn_status_t conn_status;
jabber_presence_t presence;
int tls_disabled;
} jabber_conn;
void xmpp_file_logger(void * const userdata, const xmpp_log_level_t level,
const char * const area, const char * const msg);
static const xmpp_log_t file_log = { &xmpp_file_logger, XMPP_LEVEL_DEBUG };
xmpp_log_t *xmpp_get_file_logger()
{
return (xmpp_log_t*) &file_log;
}
void xmpp_file_logger(void * const userdata, const xmpp_log_level_t level,
const char * const area, const char * const msg)
{
log_msg(area, msg);
}
// private XMPP handlers
static void _jabber_conn_handler(xmpp_conn_t * const conn,
const xmpp_conn_event_t status, const int error,
xmpp_stream_error_t * const stream_error, void * const userdata);
static int _jabber_message_handler(xmpp_conn_t * const conn,
xmpp_stanza_t * const stanza, void * const userdata);
static int _roster_handler(xmpp_conn_t * const conn,
xmpp_stanza_t * const stanza, void * const userdata);
static int _jabber_presence_handler(xmpp_conn_t * const conn,
xmpp_stanza_t * const stanza, void * const userdata);
static int _ping_timed_handler(xmpp_conn_t * const conn, void * const userdata);
void jabber_init(const int disable_tls)
{
jabber_conn.conn_status = JABBER_STARTED;
jabber_conn.presence = PRESENCE_OFFLINE;
jabber_conn.tls_disabled = disable_tls;
}
jabber_conn_status_t jabber_connection_status(void)
{
return (jabber_conn.conn_status);
}
jabber_conn_status_t jabber_connect(const char * const user,
const char * const passwd)
{
xmpp_initialize();
jabber_conn.log = xmpp_get_file_logger();
jabber_conn.ctx = xmpp_ctx_new(NULL, jabber_conn.log);
jabber_conn.conn = xmpp_conn_new(jabber_conn.ctx);
xmpp_conn_set_jid(jabber_conn.conn, user);
xmpp_conn_set_pass(jabber_conn.conn, passwd);
if (jabber_conn.tls_disabled)
xmpp_conn_disable_tls(jabber_conn.conn);
int connect_status = xmpp_connect_client(jabber_conn.conn, NULL, 0,
_jabber_conn_handler, jabber_conn.ctx);
if (connect_status == 0)
jabber_conn.conn_status = JABBER_CONNECTING;
else
jabber_conn.conn_status = JABBER_DISCONNECTED;
return jabber_conn.conn_status;
}
const char * jabber_get_jid(void)
{
return xmpp_conn_get_jid(jabber_conn.conn);
}
void jabber_disconnect(void)
{
if (jabber_conn.conn_status == JABBER_CONNECTED) {
xmpp_conn_release(jabber_conn.conn);
xmpp_ctx_free(jabber_conn.ctx);
xmpp_shutdown();
jabber_conn.conn_status = JABBER_DISCONNECTED;
jabber_conn.presence = PRESENCE_OFFLINE;
}
}
void jabber_process_events(void)
{
if (jabber_conn.conn_status == JABBER_CONNECTED
|| jabber_conn.conn_status == JABBER_CONNECTING)
xmpp_run_once(jabber_conn.ctx, 10);
}
void jabber_send(const char * const msg, const char * const recipient)
{
char *coded_msg = str_replace(msg, "&", "&amp;");
xmpp_stanza_t *reply, *body, *text;
reply = xmpp_stanza_new(jabber_conn.ctx);
xmpp_stanza_set_name(reply, "message");
xmpp_stanza_set_type(reply, "chat");
xmpp_stanza_set_attribute(reply, "to", recipient);
body = xmpp_stanza_new(jabber_conn.ctx);
xmpp_stanza_set_name(body, "body");
text = xmpp_stanza_new(jabber_conn.ctx);
xmpp_stanza_set_text(text, coded_msg);
xmpp_stanza_add_child(body, text);
xmpp_stanza_add_child(reply, body);
xmpp_send(jabber_conn.conn, reply);
xmpp_stanza_release(reply);
}
void jabber_roster_request(void)
{
xmpp_stanza_t *iq, *query;
iq = xmpp_stanza_new(jabber_conn.ctx);
xmpp_stanza_set_name(iq, "iq");
xmpp_stanza_set_type(iq, "get");
xmpp_stanza_set_id(iq, "roster");
query = xmpp_stanza_new(jabber_conn.ctx);
xmpp_stanza_set_name(query, "query");
xmpp_stanza_set_ns(query, XMPP_NS_ROSTER);
xmpp_stanza_add_child(iq, query);
xmpp_stanza_release(query);
xmpp_send(jabber_conn.conn, iq);
xmpp_stanza_release(iq);
}
void jabber_update_presence(jabber_presence_t status, const char * const msg)
{
jabber_conn.presence = status;
xmpp_stanza_t *pres, *show;
pres = xmpp_stanza_new(jabber_conn.ctx);
xmpp_stanza_set_name(pres, "presence");
if (status != PRESENCE_ONLINE) {
show = xmpp_stanza_new(jabber_conn.ctx);
xmpp_stanza_set_name(show, "show");
xmpp_stanza_t *text = xmpp_stanza_new(jabber_conn.ctx);
if (status == PRESENCE_AWAY)
xmpp_stanza_set_text(text, "away");
else if (status == PRESENCE_DND)
xmpp_stanza_set_text(text, "dnd");
else if (status == PRESENCE_CHAT)
xmpp_stanza_set_text(text, "chat");
else if (status == PRESENCE_XA)
xmpp_stanza_set_text(text, "xa");
else
xmpp_stanza_set_text(text, "online");
xmpp_stanza_add_child(show, text);
xmpp_stanza_add_child(pres, show);
xmpp_stanza_release(text);
xmpp_stanza_release(show);
}
if (msg != NULL) {
xmpp_stanza_t *status = xmpp_stanza_new(jabber_conn.ctx);
xmpp_stanza_set_name(status, "status");
xmpp_stanza_t *text = xmpp_stanza_new(jabber_conn.ctx);
xmpp_stanza_set_text(text, msg);
xmpp_stanza_add_child(status, text);
xmpp_stanza_add_child(pres, status);
xmpp_stanza_release(text);
xmpp_stanza_release(status);
}
xmpp_send(jabber_conn.conn, pres);
xmpp_stanza_release(pres);
}
static int _jabber_message_handler(xmpp_conn_t * const conn,
xmpp_stanza_t * const stanza, void * const userdata)
{
xmpp_stanza_t *body = xmpp_stanza_get_child_by_name(stanza, "body");
if(body == NULL)
return 1;
char *type = xmpp_stanza_get_attribute(stanza, "type");
if(strcmp(type, "error") == 0)
return 1;
char *message = xmpp_stanza_get_text(body);
char *from = xmpp_stanza_get_attribute(stanza, "from");
win_show_incomming_msg(from, message);
win_page_off();
return 1;
}
static void _jabber_conn_handler(xmpp_conn_t * const conn,
const xmpp_conn_event_t status, const int error,
xmpp_stream_error_t * const stream_error, void * const userdata)
{
xmpp_ctx_t *ctx = (xmpp_ctx_t *)userdata;
if (status == XMPP_CONN_CONNECT) {
const char *jid = xmpp_conn_get_jid(conn);
const char *msg = " logged in successfully.";
char line[strlen(jid) + 1 + strlen(msg) + 1];
sprintf(line, "%s %s", jid, msg);
title_bar_set_status(PRESENCE_ONLINE);
cons_show(line);
win_page_off();
status_bar_print_message(jid);
status_bar_refresh();
xmpp_stanza_t* pres;
xmpp_handler_add(conn, _jabber_message_handler, NULL, "message", NULL, ctx);
xmpp_handler_add(conn, _jabber_presence_handler, NULL, "presence", NULL, ctx);
xmpp_id_handler_add(conn, _roster_handler, "roster", ctx);
xmpp_timed_handler_add(conn, _ping_timed_handler, PING_INTERVAL, ctx);
pres = xmpp_stanza_new(ctx);
xmpp_stanza_set_name(pres, "presence");
xmpp_send(conn, pres);
xmpp_stanza_release(pres);
prefs_add_login(jid);
jabber_conn.conn_status = JABBER_CONNECTED;
jabber_conn.presence = PRESENCE_ONLINE;
}
else {
if (jabber_conn.conn_status == JABBER_CONNECTED) {
cons_bad_show("Lost connection.");
win_disconnected();
} else {
cons_bad_show("Login failed.");
}
win_page_off();
log_msg(CONN, "disconnected");
xmpp_stop(ctx);
jabber_conn.conn_status = JABBER_DISCONNECTED;
jabber_conn.presence = PRESENCE_OFFLINE;
}
}
static int _roster_handler(xmpp_conn_t * const conn,
xmpp_stanza_t * const stanza, void * const userdata)
{
xmpp_stanza_t *query, *item;
char *type, *name, *jid;
type = xmpp_stanza_get_type(stanza);
if (strcmp(type, "error") == 0)
log_msg(CONN, "ERROR: query failed");
else {
query = xmpp_stanza_get_child_by_name(stanza, "query");
cons_show("Roster:");
item = xmpp_stanza_get_children(query);
while (item != NULL) {
name = xmpp_stanza_get_attribute(item, "name");
jid = xmpp_stanza_get_attribute(item, "jid");
if (name != NULL) {
char line[strlen(name) + 2 + strlen(jid) + 1 + 1];
sprintf(line, "%s (%s)", name, jid);
cons_show(line);
} else {
char line[strlen(jid) + 1];
sprintf(line, "%s", jid);
cons_show(line);
}
item = xmpp_stanza_get_next(item);
win_page_off();
}
}
return 1;
}
static int _ping_timed_handler(xmpp_conn_t * const conn, void * const userdata)
{
if (jabber_conn.conn_status == JABBER_CONNECTED) {
xmpp_ctx_t *ctx = (xmpp_ctx_t *)userdata;
xmpp_stanza_t *iq, *ping;
iq = xmpp_stanza_new(ctx);
xmpp_stanza_set_name(iq, "iq");
xmpp_stanza_set_type(iq, "get");
xmpp_stanza_set_id(iq, "c2s1");
ping = xmpp_stanza_new(ctx);
xmpp_stanza_set_name(ping, "ping");
// FIXME add ping namespace to libstrophe
xmpp_stanza_set_ns(ping, "urn:xmpp:ping");
xmpp_stanza_add_child(iq, ping);
xmpp_stanza_release(ping);
xmpp_send(conn, iq);
xmpp_stanza_release(iq);
}
return 1;
}
static int _jabber_presence_handler(xmpp_conn_t * const conn,
xmpp_stanza_t * const stanza, void * const userdata)
{
const char *jid = xmpp_conn_get_jid(jabber_conn.conn);
char jid_cpy[strlen(jid) + 1];
strcpy(jid_cpy, jid);
char *short_jid = strtok(jid_cpy, "/");
char *from = xmpp_stanza_get_attribute(stanza, "from");
char *short_from = strtok(from, "/");
char *type = xmpp_stanza_get_attribute(stanza, "type");
char *show_str, *status_str;
xmpp_stanza_t *show = xmpp_stanza_get_child_by_name(stanza, "show");
if (show != NULL)
show_str = xmpp_stanza_get_text(show);
else
show_str = NULL;
xmpp_stanza_t *status = xmpp_stanza_get_child_by_name(stanza, "status");
if (status != NULL)
status_str = xmpp_stanza_get_text(status);
else
status_str = NULL;
if (strcmp(short_jid, short_from) !=0) {
if (type == NULL) {// online
gboolean result = contact_list_add(short_from, show_str, status_str);
if (result) {
win_contact_online(short_from, show_str, status_str);
}
} else {// offline
gboolean result = contact_list_remove(short_from);
if (result) {
win_contact_offline(short_from, show_str, status_str);
}
}
win_page_off();
}
return 1;
}

40
src/jabber.h Normal file
View File

@@ -0,0 +1,40 @@
/*
* jabber.h
*
* Copyright (C) 2012 James Booth <boothj5@gmail.com>
*
* This file is part of Profanity.
*
* Profanity is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Profanity is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef JABBER_H
#define JABBER_H
#include "common.h"
void jabber_init(const int disable_tls);
jabber_conn_status_t jabber_connection_status(void);
jabber_presence_t jabber_presence_status(void);
jabber_conn_status_t jabber_connect(const char * const user,
const char * const passwd);
void jabber_disconnect(void);
void jabber_roster_request(void);
void jabber_process_events(void);
void jabber_send(const char * const msg, const char * const recipient);
const char * jabber_get_jid(void);
void jabber_update_presence(jabber_presence_t status, const char * const msg);
#endif

43
src/log.c Normal file
View File

@@ -0,0 +1,43 @@
/*
* log.c
*
* Copyright (C) 2012 James Booth <boothj5@gmail.com>
*
* This file is part of Profanity.
*
* Profanity is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Profanity is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <stdio.h>
#include "log.h"
extern FILE *logp;
void log_msg(const char * const area, const char * const msg)
{
fprintf(logp, "%s DEBUG: %s\n", area, msg);
}
void log_init(void)
{
logp = fopen("profanity.log", "a");
log_msg(PROF, "Starting Profanity...");
}
void log_close(void)
{
fclose(logp);
}

39
src/log.h Normal file
View File

@@ -0,0 +1,39 @@
/*
* log.h
*
* Copyright (C) 2012 James Booth <boothj5@gmail.com>
*
* This file is part of Profanity.
*
* Profanity is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Profanity is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef LOG_H
#define LOG_H
#include <stdio.h>
// log areas
#define PROF "prof"
#define CONN "conn"
// file log
FILE *logp;
void log_init(void);
void log_msg(const char * const area, const char * const msg);
void log_close(void);
#endif

52
src/main.c Normal file
View File

@@ -0,0 +1,52 @@
/*
* main.c
*
* Copyright (C) 2012 James Booth <boothj5@gmail.com>
*
* This file is part of Profanity.
*
* Profanity is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Profanity is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <stdio.h>
#include <string.h>
#include "profanity.h"
int main(int argc, char **argv)
{
int disable_tls = 0;
// more than one argument
if (argc > 2) {
printf("Usage: profanity [-notls]\n");
return 1;
// argument is not -notls
} else if (argc == 2) {
char *arg1 = argv[1];
if (strcmp(arg1, "-notls") != 0) {
printf("Usage: profanity [-notls]\n");
return 1;
} else {
disable_tls = 1;
}
}
profanity_init(disable_tls);
profanity_run();
return 0;
}

300
src/preferences.c Normal file
View File

@@ -0,0 +1,300 @@
/*
* preferences.c
*
* Copyright (C) 2012 James Booth <boothj5@gmail.com>
*
* This file is part of Profanity.
*
* Profanity is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Profanity is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <stdlib.h>
#include <string.h>
#include <ncurses.h>
#include <glib.h>
#include "log.h"
#include "preferences.h"
#include "prof_autocomplete.h"
static GString *prefs_loc;
static GKeyFile *prefs;
// search logins list
static PAutocomplete ac;
struct colour_string_t {
char *str;
NCURSES_COLOR_T colour;
};
static int num_colours = 9;
static struct colour_string_t colours[] = {
{ "default", -1 },
{ "white", COLOR_WHITE },
{ "green", COLOR_GREEN },
{ "red", COLOR_RED },
{ "yellow", COLOR_YELLOW },
{ "blue", COLOR_BLUE },
{ "cyan", COLOR_CYAN },
{ "black", COLOR_BLACK },
{ "magenta", COLOR_MAGENTA },
};
// colour preferences
static struct colours_t {
NCURSES_COLOR_T bkgnd;
NCURSES_COLOR_T text;
NCURSES_COLOR_T online;
NCURSES_COLOR_T offline;
NCURSES_COLOR_T err;
NCURSES_COLOR_T inc;
NCURSES_COLOR_T bar;
NCURSES_COLOR_T bar_draw;
NCURSES_COLOR_T bar_text;
} colour_prefs;
static NCURSES_COLOR_T _lookup_colour(const char * const colour);
static void _set_colour(gchar *val, NCURSES_COLOR_T *pref,
NCURSES_COLOR_T def);
static void _load_colours(void);
static void _save_prefs(void);
void prefs_load(void)
{
ac = p_autocomplete_new();
prefs_loc = g_string_new(getenv("HOME"));
g_string_append(prefs_loc, "/.profanity");
prefs = g_key_file_new();
g_key_file_load_from_file(prefs, prefs_loc->str, G_KEY_FILE_NONE, NULL);
// create the logins searchable list for autocompletion
gsize njids;
gchar **jids =
g_key_file_get_string_list(prefs, "connections", "logins", &njids, NULL);
gsize i;
for (i = 0; i < njids; i++) {
p_autocomplete_add(ac, jids[i]);
}
_load_colours();
}
static NCURSES_COLOR_T _lookup_colour(const char * const colour)
{
int i;
for (i = 0; i < num_colours; i++) {
if (strcmp(colours[i].str, colour) == 0) {
return colours[i].colour;
}
}
return -99;
}
static void _set_colour(gchar *val, NCURSES_COLOR_T *pref,
NCURSES_COLOR_T def)
{
if(!val) {
*pref = def;
} else {
NCURSES_COLOR_T col = _lookup_colour(val);
if (col == -99) {
*pref = def;
} else {
*pref = col;
}
}
}
static void _load_colours(void)
{
gchar *bkgnd_val = g_key_file_get_string(prefs, "colours", "bkgnd", NULL);
_set_colour(bkgnd_val, &colour_prefs.bkgnd, -1);
gchar *text_val = g_key_file_get_string(prefs, "colours", "text", NULL);
_set_colour(text_val, &colour_prefs.text, COLOR_WHITE);
gchar *online_val = g_key_file_get_string(prefs, "colours", "online", NULL);
_set_colour(online_val, &colour_prefs.online, COLOR_GREEN);
gchar *offline_val = g_key_file_get_string(prefs, "colours", "offline", NULL);
_set_colour(offline_val, &colour_prefs.offline, COLOR_CYAN);
gchar *err_val = g_key_file_get_string(prefs, "colours", "err", NULL);
_set_colour(err_val, &colour_prefs.err, COLOR_RED);
gchar *inc_val = g_key_file_get_string(prefs, "colours", "inc", NULL);
_set_colour(inc_val, &colour_prefs.inc, COLOR_YELLOW);
gchar *bar_val = g_key_file_get_string(prefs, "colours", "bar", NULL);
_set_colour(bar_val, &colour_prefs.bar, COLOR_BLUE);
gchar *bar_draw_val = g_key_file_get_string(prefs, "colours", "bar_draw", NULL);
_set_colour(bar_draw_val, &colour_prefs.bar_draw, COLOR_CYAN);
gchar *bar_text_val = g_key_file_get_string(prefs, "colours", "bar_text", NULL);
_set_colour(bar_text_val, &colour_prefs.bar_text, COLOR_WHITE);
}
char * find_login(char *prefix)
{
return p_autocomplete_complete(ac, prefix);
}
void reset_login_search(void)
{
p_autocomplete_reset(ac);
}
gboolean prefs_get_beep(void)
{
return g_key_file_get_boolean(prefs, "ui", "beep", NULL);
}
void prefs_set_beep(gboolean value)
{
g_key_file_set_boolean(prefs, "ui", "beep", value);
_save_prefs();
}
gboolean prefs_get_notify(void)
{
return g_key_file_get_boolean(prefs, "ui", "notify", NULL);
}
void prefs_set_notify(gboolean value)
{
g_key_file_set_boolean(prefs, "ui", "notify", value);
_save_prefs();
}
gboolean prefs_get_flash(void)
{
return g_key_file_get_boolean(prefs, "ui", "flash", NULL);
}
void prefs_set_flash(gboolean value)
{
g_key_file_set_boolean(prefs, "ui", "flash", value);
_save_prefs();
}
void prefs_add_login(const char *jid)
{
gsize njids;
gchar **jids =
g_key_file_get_string_list(prefs, "connections", "logins", &njids, NULL);
// no logins remembered yet
if (jids == NULL) {
njids = 1;
jids = (gchar**) g_malloc(sizeof(gchar *) * 2);
jids[0] = g_strdup(jid);
jids[1] = NULL;
g_key_file_set_string_list(prefs, "connections", "logins",
(const gchar * const *)jids, njids);
_save_prefs();
g_strfreev(jids);
return;
} else {
gsize i;
for (i = 0; i < njids; i++) {
if (strcmp(jid, jids[i]) == 0) {
g_strfreev(jids);
return;
}
}
// jid not found, add to the list
jids = (gchar **) g_realloc(jids, (sizeof(gchar *) * (njids+2)));
jids[njids] = g_strdup(jid);
njids++;
jids[njids] = NULL;
g_key_file_set_string_list(prefs, "connections", "logins",
(const gchar * const *)jids, njids);
_save_prefs();
g_strfreev(jids);
return;
}
}
gboolean prefs_get_showsplash(void)
{
return g_key_file_get_boolean(prefs, "ui", "showsplash", NULL);
}
void prefs_set_showsplash(gboolean value)
{
g_key_file_set_boolean(prefs, "ui", "showsplash", value);
_save_prefs();
}
static void _save_prefs(void)
{
gsize g_data_size;
char *g_prefs_data = g_key_file_to_data(prefs, &g_data_size, NULL);
g_file_set_contents(prefs_loc->str, g_prefs_data, g_data_size, NULL);
}
NCURSES_COLOR_T prefs_get_bkgnd()
{
return colour_prefs.bkgnd;
}
NCURSES_COLOR_T prefs_get_text()
{
return colour_prefs.text;
}
NCURSES_COLOR_T prefs_get_online()
{
return colour_prefs.online;
}
NCURSES_COLOR_T prefs_get_offline()
{
return colour_prefs.offline;
}
NCURSES_COLOR_T prefs_get_err()
{
return colour_prefs.err;
}
NCURSES_COLOR_T prefs_get_inc()
{
return colour_prefs.inc;
}
NCURSES_COLOR_T prefs_get_bar()
{
return colour_prefs.bar;
}
NCURSES_COLOR_T prefs_get_bar_draw()
{
return colour_prefs.bar_draw;
}
NCURSES_COLOR_T prefs_get_bar_text()
{
return colour_prefs.bar_text;
}

53
src/preferences.h Normal file
View File

@@ -0,0 +1,53 @@
/*
* preferences.h
*
* Copyright (C) 2012 James Booth <boothj5@gmail.com>
*
* This file is part of Profanity.
*
* Profanity is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Profanity is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef PREFERENCES_H
#define PREFERENCES_H
#include <glib.h>
void prefs_load(void);
char * find_login(char *prefix);
void reset_login_search(void);
gboolean prefs_get_beep(void);
void prefs_set_beep(gboolean value);
gboolean prefs_get_notify(void);
void prefs_set_notify(gboolean value);
gboolean prefs_get_flash(void);
void prefs_set_flash(gboolean value);
void prefs_add_login(const char *jid);
gboolean prefs_get_showsplash(void);
void prefs_set_showsplash(gboolean value);
NCURSES_COLOR_T prefs_get_bkgnd();
NCURSES_COLOR_T prefs_get_text();
NCURSES_COLOR_T prefs_get_online();
NCURSES_COLOR_T prefs_get_offline();
NCURSES_COLOR_T prefs_get_err();
NCURSES_COLOR_T prefs_get_inc();
NCURSES_COLOR_T prefs_get_bar();
NCURSES_COLOR_T prefs_get_bar_draw();
NCURSES_COLOR_T prefs_get_bar_text();
#endif

251
src/prof_autocomplete.c Normal file
View File

@@ -0,0 +1,251 @@
/*
* prof_autocomplete.c
*
* Copyright (C) 2012 James Booth <boothj5@gmail.com>
*
* This file is part of Profanity.
*
* Profanity is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Profanity is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <stdlib.h>
#include <string.h>
#include <glib.h>
#include "common.h"
#include "prof_autocomplete.h"
struct p_autocomplete_t {
GSList *items;
GSList *last_found;
gchar *search_str;
PStrFunc str_func;
PCopyFunc copy_func;
PEqualDeepFunc equal_deep_func;
GDestroyNotify free_func;
};
static gchar * _search_from(PAutocomplete ac, GSList *curr);
static const char *_str_func_default(const char *orig);
static const char *_copy_func_default(const char *orig);
static int _deep_equals_func_default(const char *o1, const char *o2);
PAutocomplete p_autocomplete_new(void)
{
return p_obj_autocomplete_new(NULL, NULL, NULL, NULL);
}
PAutocomplete p_obj_autocomplete_new(PStrFunc str_func, PCopyFunc copy_func,
PEqualDeepFunc equal_deep_func, GDestroyNotify free_func)
{
PAutocomplete new = malloc(sizeof(struct p_autocomplete_t));
new->items = NULL;
new->last_found = NULL;
new->search_str = NULL;
if (str_func)
new->str_func = str_func;
else
new->str_func = (PStrFunc)_str_func_default;
if (copy_func)
new->copy_func = copy_func;
else
new->copy_func = (PCopyFunc)_copy_func_default;
if (free_func)
new->free_func = free_func;
else
new->free_func = (GDestroyNotify)free;
if (equal_deep_func)
new->equal_deep_func = equal_deep_func;
else
new->equal_deep_func = (PEqualDeepFunc)_deep_equals_func_default;
return new;
}
void p_autocomplete_clear(PAutocomplete ac)
{
g_slist_free_full(ac->items, ac->free_func);
ac->items = NULL;
p_autocomplete_reset(ac);
}
void p_autocomplete_reset(PAutocomplete ac)
{
ac->last_found = NULL;
if (ac->search_str != NULL) {
free(ac->search_str);
ac->search_str = NULL;
}
}
gboolean p_autocomplete_add(PAutocomplete ac, void *item)
{
if (ac->items == NULL) {
ac->items = g_slist_append(ac->items, item);
return TRUE;
} else {
GSList *curr = ac->items;
while(curr) {
// insert
if (g_strcmp0(ac->str_func(curr->data), ac->str_func(item)) > 0) {
ac->items = g_slist_insert_before(ac->items,
curr, item);
return TRUE;
// update
} else if (g_strcmp0(ac->str_func(curr->data), ac->str_func(item)) == 0) {
// only update if data different
if (!ac->equal_deep_func(curr->data, item)) {
ac->free_func(curr->data);
curr->data = item;
return TRUE;
} else {
return FALSE;
}
}
curr = g_slist_next(curr);
}
// hit end, append
ac->items = g_slist_append(ac->items, item);
return TRUE;
}
}
gboolean p_autocomplete_remove(PAutocomplete ac, const char * const item)
{
// reset last found if it points to the item to be removed
if (ac->last_found != NULL)
if (g_strcmp0(ac->str_func(ac->last_found->data), item) == 0)
ac->last_found = NULL;
if (!ac->items) {
return FALSE;
} else {
GSList *curr = ac->items;
while(curr) {
if (g_strcmp0(ac->str_func(curr->data), item) == 0) {
void *current_item = curr->data;
ac->items = g_slist_remove(ac->items, curr->data);
ac->free_func(current_item);
return TRUE;
}
curr = g_slist_next(curr);
}
return FALSE;
}
}
GSList * p_autocomplete_get_list(PAutocomplete ac)
{
GSList *copy = NULL;
GSList *curr = ac->items;
while(curr) {
copy = g_slist_append(copy, ac->copy_func(curr->data));
curr = g_slist_next(curr);
}
return copy;
}
gchar * p_autocomplete_complete(PAutocomplete ac, gchar *search_str)
{
gchar *found = NULL;
// no items to search
if (!ac->items)
return NULL;
// first search attempt
if (ac->last_found == NULL) {
ac->search_str =
(gchar *) malloc((strlen(search_str) + 1) * sizeof(gchar));
strcpy(ac->search_str, search_str);
found = _search_from(ac, ac->items);
return found;
// subsequent search attempt
} else {
// search from here+1 tp end
found = _search_from(ac, g_slist_next(ac->last_found));
if (found != NULL)
return found;
// search from beginning
found = _search_from(ac, ac->items);
if (found != NULL)
return found;
// we found nothing, reset search
p_autocomplete_reset(ac);
return NULL;
}
}
static gchar * _search_from(PAutocomplete ac, GSList *curr)
{
while(curr) {
// match found
if (strncmp(ac->str_func(curr->data),
ac->search_str,
strlen(ac->search_str)) == 0) {
gchar *result =
(gchar *) malloc((strlen(ac->str_func(curr->data)) + 1) * sizeof(gchar));
// set pointer to last found
ac->last_found = curr;
// return the string, must be free'd by caller
strcpy(result, ac->str_func(curr->data));
return result;
}
curr = g_slist_next(curr);
}
return NULL;
}
static const char *_str_func_default(const char *orig)
{
return orig;
}
static const char *_copy_func_default(const char *orig)
{
return strdup(orig);
}
static int _deep_equals_func_default(const char *o1, const char *o2)
{
return (strcmp(o1, o2) == 0);
}

44
src/prof_autocomplete.h Normal file
View File

@@ -0,0 +1,44 @@
/*
* prof_autocomplete.h
*
* Copyright (C) 2012 James Booth <boothj5@gmail.com>
*
* This file is part of Profanity.
*
* Profanity is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Profanity is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef PROF_AUTOCOMPLETE_H
#define PROF_AUTOCOMPLETE_H
#include <glib.h>
typedef struct p_autocomplete_t *PAutocomplete;
typedef const char * (*PStrFunc)(const void *obj);
typedef void * (*PCopyFunc)(const void *obj);
typedef int (*PEqualFunc)(const void *o1, const void *o2);
typedef int (*PEqualDeepFunc)(const void *o1, const void *o2);
PAutocomplete p_autocomplete_new(void);
PAutocomplete p_obj_autocomplete_new(PStrFunc str_func, PCopyFunc copy_func,
PEqualDeepFunc equal_deep_func, GDestroyNotify free_func);
void p_autocomplete_clear(PAutocomplete ac);
void p_autocomplete_reset(PAutocomplete ac);
gboolean p_autocomplete_add(PAutocomplete ac, void *item);
gboolean p_autocomplete_remove(PAutocomplete ac, const char * const item);
GSList * p_autocomplete_get_list(PAutocomplete ac);
gchar * p_autocomplete_complete(PAutocomplete ac, gchar *search_str);
#endif

251
src/prof_history.c Normal file
View File

@@ -0,0 +1,251 @@
/*
* prof_history.c
*
* Copyright (C) 2012 James Booth <boothj5@gmail.com>
*
* This file is part of Profanity.
*
* Profanity is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Profanity is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <stdlib.h>
#include <string.h>
#include <glib.h>
#include "prof_history.h"
struct p_history_session_t {
GList *items;
GList *sess_curr;
GList *sess_new;
GList *orig_curr;
};
struct p_history_t {
GList *items;
guint max_size;
struct p_history_session_t session;
};
static void _replace_history_with_session(PHistory history);
static gboolean _adding_new(PHistory history);
static void _reset_session(PHistory history);
static gboolean _has_session(PHistory history);
static void _remove_first(PHistory history);
static void _update_current_session_item(PHistory history, char *item);
static void _add_to_history(PHistory history, char *item);
static void _remove_last_session_item(PHistory history);
static void _replace_current_with_original(PHistory history);
static void _create_session(PHistory history);
static void _session_previous(PHistory history);
static void _session_next(PHistory history);
PHistory p_history_new(unsigned int size)
{
PHistory new_history = malloc(sizeof(struct p_history_t));
new_history->items = NULL;
new_history->max_size = size;
_reset_session(new_history);
return new_history;
}
void p_history_append(PHistory history, char *item)
{
char *copied = "";
if (item != NULL) {
copied = strdup(item);
}
if (history->items == NULL) {
_add_to_history(history, copied);
return;
}
if (!_has_session(history)) {
if (g_list_length(history->items) == history->max_size) {
_remove_first(history);
}
_add_to_history(history, copied);
} else {
_update_current_session_item(history, copied);
if (_adding_new(history)) {
if (strcmp(history->session.sess_curr->data, "") == 0) {
_remove_last_session_item(history);
}
_replace_history_with_session(history);
} else {
_remove_last_session_item(history);
char *new = strdup(history->session.sess_curr->data);
history->session.items = g_list_append(history->session.items, new);
_replace_current_with_original(history);
_replace_history_with_session(history);
}
}
}
char * p_history_previous(PHistory history, char *item)
{
// no history
if (history->items == NULL) {
return NULL;
}
char *copied = "";
if (item != NULL) {
copied = strdup(item);
}
if (!_has_session(history)) {
_create_session(history);
// add the new item
g_list_append(history->session.items, copied);
history->session.sess_new = g_list_last(history->session.items);
char *result = strdup(history->session.sess_curr->data);
return result;
} else {
_update_current_session_item(history, copied);
_session_previous(history);
}
char *result = strdup(history->session.sess_curr->data);
return result;
}
char * p_history_next(PHistory history, char *item)
{
// no history, or no session, return NULL
if ((history->items == NULL) || (history->session.items == NULL)) {
return NULL;
}
char *copied = "";
if (item != NULL) {
copied = strdup(item);
}
_update_current_session_item(history, copied);
_session_next(history);
char *result = strdup(history->session.sess_curr->data);
return result;
}
static void _replace_history_with_session(PHistory history)
{
g_list_free(history->items);
history->items = g_list_copy(history->session.items);
if (g_list_length(history->items) > history->max_size) {
_remove_first(history);
}
_reset_session(history);
}
static gboolean _adding_new(PHistory history)
{
return (history->session.sess_curr ==
g_list_last(history->session.items));
}
static void _reset_session(PHistory history)
{
history->session.items = NULL;
history->session.sess_curr = NULL;
history->session.sess_new = NULL;
history->session.orig_curr = NULL;
}
static gboolean _has_session(PHistory history)
{
return (history->session.items != NULL);
}
static void _remove_first(PHistory history)
{
GList *first = g_list_first(history->items);
char *first_item = first->data;
history->items = g_list_remove(history->items, first_item);
}
static void _update_current_session_item(PHistory history, char *item)
{
history->session.sess_curr->data = item;
}
static void _add_to_history(PHistory history, char *item)
{
history->items = g_list_append(history->items, item);
}
static void _remove_last_session_item(PHistory history)
{
history->session.items = g_list_reverse(history->session.items);
GList *first = g_list_first(history->session.items);
history->session.items =
g_list_remove(history->session.items, first->data);
history->session.items = g_list_reverse(history->session.items);
}
static void _replace_current_with_original(PHistory history)
{
history->session.sess_curr->data = strdup(history->session.orig_curr->data);
}
static void _create_session(PHistory history)
{
history->session.items = g_list_copy(history->items);
history->session.sess_curr = g_list_last(history->session.items);
history->session.orig_curr = g_list_last(history->items);
}
static void _session_previous(PHistory history)
{
history->session.sess_curr =
g_list_previous(history->session.sess_curr);
if (history->session.orig_curr == NULL)
history->session.orig_curr = g_list_last(history->items);
else
history->session.orig_curr =
g_list_previous(history->session.orig_curr);
if (history->session.sess_curr == NULL) {
history->session.sess_curr = g_list_first(history->session.items);
history->session.orig_curr = g_list_first(history->items);
}
}
static void _session_next(PHistory history)
{
history->session.sess_curr = g_list_next(history->session.sess_curr);
history->session.orig_curr = g_list_next(history->session.orig_curr);
if (history->session.sess_curr == NULL) {
history->session.sess_curr = g_list_last(history->session.items);
history->session.orig_curr = NULL;
}
}

33
src/prof_history.h Normal file
View File

@@ -0,0 +1,33 @@
/*
* prof_history.h
*
* Copyright (C) 2012 James Booth <boothj5@gmail.com>
*
* This file is part of Profanity.
*
* Profanity is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Profanity is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef PROF_HISTORY_H
#define PROF_HISTORY_H
typedef struct p_history_t *PHistory;
PHistory p_history_new(unsigned int size);
char * p_history_previous(PHistory history, char *item);
char * p_history_next(PHistory history, char *item);
void p_history_append(PHistory history, char *item);
#endif

82
src/profanity.c Normal file
View File

@@ -0,0 +1,82 @@
/*
* profanity.c
*
* Copyright (C) 2012 James Booth <boothj5@gmail.com>
*
* This file is part of Profanity.
*
* Profanity is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Profanity is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <string.h>
#include <stdlib.h>
#include <glib.h>
#include "profanity.h"
#include "log.h"
#include "ui.h"
#include "jabber.h"
#include "command.h"
#include "preferences.h"
#include "contact_list.h"
static void _profanity_shutdown(void);
void profanity_run(void)
{
gboolean cmd_result = TRUE;
inp_non_block();
while(cmd_result == TRUE) {
int ch = ERR;
char inp[200];
int size = 0;
while(ch != '\n') {
win_handle_special_keys(&ch);
if (ch == KEY_RESIZE) {
gui_resize(ch, inp, size);
}
gui_refresh();
jabber_process_events();
inp_get_char(&ch, inp, &size);
}
inp[size++] = '\0';
cmd_result = process_input(inp);
}
}
void profanity_init(const int disable_tls)
{
log_init();
prefs_load();
gui_init();
jabber_init(disable_tls);
command_init();
contact_list_init();
atexit(_profanity_shutdown);
}
void _profanity_shutdown(void)
{
jabber_disconnect();
gui_close();
log_close();
}

30
src/profanity.h Normal file
View File

@@ -0,0 +1,30 @@
/*
* profanity.h
*
* Copyright (C) 2012 James Booth <boothj5@gmail.com>
*
* This file is part of Profanity.
*
* Profanity is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Profanity is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef PROFANITY_H
#define PROFANITY_H
void profanity_init(const int disable_tls);
void profanity_run(void);
void profanity_shutdown(void);
#endif

224
src/status_bar.c Normal file
View File

@@ -0,0 +1,224 @@
/*
* status_bar.c
*
* Copyright (C) 2012 James Booth <boothj5@gmail.com>
*
* This file is part of Profanity.
*
* Profanity is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Profanity is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <string.h>
#include <stdlib.h>
#include <ncurses.h>
#include "ui.h"
#include "util.h"
static WINDOW *status_bar;
static char *message = NULL;
static char _active[29] = "[ ][ ][ ][ ][ ][ ][ ][ ][ ]";
static int is_active[9];
static int is_new[9];
static int dirty;
static char curr_time[80];
static void _status_bar_update_time(void);
void create_status_bar(void)
{
int rows, cols, i;
getmaxyx(stdscr, rows, cols);
for (i = 0; i < 9; i++) {
is_active[i] = FALSE;
is_new[i] = FALSE;
}
status_bar = newwin(1, cols, rows-2, 0);
wbkgd(status_bar, COLOR_PAIR(8));
wattron(status_bar, COLOR_PAIR(4));
mvwprintw(status_bar, 0, cols - 29, _active);
wattroff(status_bar, COLOR_PAIR(4));
get_time(curr_time);
dirty = TRUE;
}
void status_bar_refresh(void)
{
char new_time[80];
get_time(new_time);
if (strcmp(new_time, curr_time) != 0) {
dirty = TRUE;
strcpy(curr_time, new_time);
}
if (dirty) {
_status_bar_update_time();
wrefresh(status_bar);
inp_put_back();
dirty = FALSE;
}
}
void status_bar_resize(void)
{
int rows, cols, i;
getmaxyx(stdscr, rows, cols);
mvwin(status_bar, rows-2, 0);
wresize(status_bar, 1, cols);
wbkgd(status_bar, COLOR_PAIR(8));
wclear(status_bar);
wattron(status_bar, COLOR_PAIR(4));
mvwprintw(status_bar, 0, cols - 29, _active);
wattroff(status_bar, COLOR_PAIR(4));
for(i = 0; i < 9; i++) {
if (is_new[i])
status_bar_new(i+1);
else if (is_active[i])
status_bar_active(i+1);
}
if (message != NULL)
mvwprintw(status_bar, 0, 9, message);
get_time(curr_time);
dirty = TRUE;
}
void status_bar_inactive(const int win)
{
is_active[win-1] = FALSE;
is_new[win-1] = FALSE;
int active_pos = 1 + ((win -1) * 3);
int rows, cols;
getmaxyx(stdscr, rows, cols);
mvwaddch(status_bar, 0, cols - 29 + active_pos, ' ');
if (win == 9)
mvwaddch(status_bar, 0, cols - 29 + active_pos + 1, ' ');
dirty = TRUE;
}
void status_bar_active(const int win)
{
is_active[win-1] = TRUE;
is_new[win-1] = FALSE;
int active_pos = 1 + ((win -1) * 3);
int rows, cols;
getmaxyx(stdscr, rows, cols);
wattron(status_bar, COLOR_PAIR(4));
if (win < 9)
mvwprintw(status_bar, 0, cols - 29 + active_pos, "%d", win+1);
else
mvwprintw(status_bar, 0, cols - 29 + active_pos, "10");
wattroff(status_bar, COLOR_PAIR(4));
dirty = TRUE;
}
void status_bar_new(const int win)
{
is_active[win-1] = TRUE;
is_new[win-1] = TRUE;
int active_pos = 1 + ((win -1) * 3);
int rows, cols;
getmaxyx(stdscr, rows, cols);
wattron(status_bar, COLOR_PAIR(3));
wattron(status_bar, A_BLINK);
if (win < 9)
mvwprintw(status_bar, 0, cols - 29 + active_pos, "%d", win+1);
else
mvwprintw(status_bar, 0, cols - 29 + active_pos, "10");
wattroff(status_bar, COLOR_PAIR(3));
wattroff(status_bar, A_BLINK);
dirty = TRUE;
}
void status_bar_get_password(void)
{
status_bar_print_message("Enter password:");
dirty = TRUE;
}
void status_bar_print_message(const char * const msg)
{
if (message != NULL)
free(message);
message = (char *) malloc((strlen(msg) + 1) * sizeof(char));
strcpy(message, msg);
mvwprintw(status_bar, 0, 9, message);
dirty = TRUE;
}
void status_bar_clear(void)
{
if (message != NULL) {
free(message);
message = NULL;
}
int i;
for (i = 0; i < 9; i++) {
is_active[i] = FALSE;
is_new[i] = FALSE;
}
wclear(status_bar);
int rows, cols;
getmaxyx(stdscr, rows, cols);
wattron(status_bar, COLOR_PAIR(4));
mvwprintw(status_bar, 0, cols - 29, _active);
wattroff(status_bar, COLOR_PAIR(4));
dirty = TRUE;
}
static void _status_bar_update_time(void)
{
char bar_time[6];
char tstmp[80];
get_time(tstmp);
sprintf(bar_time, "%s", tstmp);
wattron(status_bar, COLOR_PAIR(4));
mvwaddch(status_bar, 0, 1, '[');
wattroff(status_bar, COLOR_PAIR(4));
mvwprintw(status_bar, 0, 2, bar_time);
wattron(status_bar, COLOR_PAIR(4));
mvwaddch(status_bar, 0, 7, ']');
wattroff(status_bar, COLOR_PAIR(4));
dirty = TRUE;
}

134
src/title_bar.c Normal file
View File

@@ -0,0 +1,134 @@
/*
* title_bar.c
*
* Copyright (C) 2012 James Booth <boothj5@gmail.com>
*
* This file is part of Profanity.
*
* Profanity is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Profanity is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <stdlib.h>
#include <string.h>
#include <ncurses.h>
#include "common.h"
#include "ui.h"
static WINDOW *title_bar;
static char *current_title = NULL;
static int dirty;
static jabber_presence_t current_status;
static void _title_bar_draw_title(void);
static void _title_bar_draw_status(void);
void create_title_bar(void)
{
int rows, cols;
getmaxyx(stdscr, rows, cols);
title_bar = newwin(1, cols, 0, 0);
wbkgd(title_bar, COLOR_PAIR(8));
title_bar_title();
title_bar_set_status(PRESENCE_OFFLINE);
dirty = TRUE;
}
void title_bar_title(void)
{
title_bar_show("Profanity. Type /help for help information.");
dirty = TRUE;
}
void title_bar_resize(void)
{
int rows, cols;
getmaxyx(stdscr, rows, cols);
wresize(title_bar, 1, cols);
wbkgd(title_bar, COLOR_PAIR(8));
wclear(title_bar);
_title_bar_draw_title();
_title_bar_draw_status();
dirty = TRUE;
}
void title_bar_refresh(void)
{
if (dirty) {
wrefresh(title_bar);
inp_put_back();
dirty = FALSE;
}
}
void title_bar_show(const char * const title)
{
if (current_title != NULL)
free(current_title);
current_title = (char *) malloc((strlen(title) + 1) * sizeof(char));
strcpy(current_title, title);
_title_bar_draw_title();
}
void title_bar_set_status(jabber_presence_t status)
{
current_status = status;
_title_bar_draw_status();
}
static void _title_bar_draw_status()
{
int rows, cols;
getmaxyx(stdscr, rows, cols);
wattron(title_bar, COLOR_PAIR(4));
mvwaddch(title_bar, 0, cols - 14, '[');
wattroff(title_bar, COLOR_PAIR(4));
if (current_status == PRESENCE_ONLINE) {
mvwprintw(title_bar, 0, cols - 13, " ...online ");
} else if (current_status == PRESENCE_AWAY) {
mvwprintw(title_bar, 0, cols - 13, " .....away ");
} else if (current_status == PRESENCE_DND) {
mvwprintw(title_bar, 0, cols - 13, " ......dnd ");
} else if (current_status == PRESENCE_CHAT) {
mvwprintw(title_bar, 0, cols - 13, " .....chat ");
} else if (current_status == PRESENCE_XA) {
mvwprintw(title_bar, 0, cols - 13, " .......xa ");
} else {
mvwprintw(title_bar, 0, cols - 13, " ..offline ");
}
wattron(title_bar, COLOR_PAIR(4));
mvwaddch(title_bar, 0, cols - 2, ']');
wattroff(title_bar, COLOR_PAIR(4));
dirty = TRUE;
}
static void _title_bar_draw_title(void)
{
wmove(title_bar, 0, 0);
int i;
for (i = 0; i < 45; i++)
waddch(title_bar, ' ');
mvwprintw(title_bar, 0, 0, " %s", current_title);
dirty = TRUE;
}

100
src/ui.h Normal file
View File

@@ -0,0 +1,100 @@
/*
* ui.h
*
* Copyright (C) 2012 James Booth <boothj5@gmail.com>
*
* This file is part of Profanity.
*
* Profanity is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Profanity is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef WINDOWS_H
#define WINDOWS_h
#include <ncurses.h>
#include "common.h"
#include "contact_list.h"
struct prof_win {
char from[100];
WINDOW *win;
int y_pos;
int paged;
};
// gui startup and shutdown, resize
void gui_init(void);
void gui_refresh(void);
void gui_close(void);
void gui_resize(const int ch, const char * const input,
const int size);
// create windows
void create_title_bar(void);
void create_status_bar(void);
void create_input_window(void);
// title bar actions
void title_bar_refresh(void);
void title_bar_resize(void);
void title_bar_show(const char * const title);
void title_bar_title(void);
void title_bar_set_status(jabber_presence_t status);
// main window actions
int win_close_win(void);
int win_in_chat(void);
char *win_get_recipient(void);
void win_show_incomming_msg(const char * const from, const char * const message);
void win_show_outgoing_msg(const char * const from, const char * const to,
const char * const message);
void win_handle_special_keys(const int * const ch);
void win_page_off(void);
void win_contact_online(const char * const from, const char * const show,
const char * const status);
void win_contact_offline(const char * const from, const char * const show,
const char * const status);
void win_disconnected(void);
// console window actions
void cons_help(void);
void cons_bad_command(const char * const cmd);
void cons_show(const char * const cmd);
void cons_bad_show(const char * const cmd);
void cons_highlight_show(const char * const cmd);
void cons_show_online_contacts(GSList * list);
// status bar actions
void status_bar_refresh(void);
void status_bar_resize(void);
void status_bar_clear(void);
void status_bar_get_password(void);
void status_bar_print_message(const char * const msg);
void status_bar_inactive(const int win);
void status_bar_active(const int win);
void status_bar_new(const int win);
void status_bar_update_time(void);
// input window actions
void inp_get_char(int *ch, char *input, int *size);
void inp_clear(void);
void inp_win_resize(const char * input, const int size);
void inp_put_back(void);
void inp_non_block(void);
void inp_block(void);
void inp_get_password(char *passwd);
#endif

91
src/util.c Normal file
View File

@@ -0,0 +1,91 @@
/*
* util.c
*
* Copyright (C) 2012 James Booth <boothj5@gmail.com>
*
* This file is part of Profanity.
*
* Profanity is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Profanity is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <time.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
void get_time(char *thetime)
{
time_t rawtime;
struct tm *timeinfo;
time(&rawtime);
timeinfo = localtime(&rawtime);
strftime(thetime, 80, "%H:%M", timeinfo);
}
char * str_replace (const char *string, const char *substr,
const char *replacement) {
char *tok = NULL;
char *newstr = NULL;
char *oldstr = NULL;
char *head = NULL;
if (string == NULL)
return NULL;
if ( substr == NULL ||
replacement == NULL ||
(strcmp(substr, "") == 0))
return strdup (string);
newstr = strdup (string);
head = newstr;
while ( (tok = strstr ( head, substr ))) {
oldstr = newstr;
newstr = malloc ( strlen ( oldstr ) - strlen ( substr ) +
strlen ( replacement ) + 1 );
if ( newstr == NULL ) {
free (oldstr);
return NULL;
}
memcpy ( newstr, oldstr, tok - oldstr );
memcpy ( newstr + (tok - oldstr), replacement, strlen ( replacement ) );
memcpy ( newstr + (tok - oldstr) + strlen( replacement ),
tok + strlen ( substr ),
strlen ( oldstr ) - strlen ( substr ) - ( tok - oldstr ) );
memset ( newstr + strlen ( oldstr ) - strlen ( substr ) +
strlen ( replacement ) , 0, 1 );
head = newstr + (tok - oldstr) + strlen( replacement );
free (oldstr);
}
return newstr;
}
int str_contains(char str[], int size, char ch)
{
int i;
for (i = 0; i < size; i++) {
if (str[i] == ch)
return 1;
}
return 0;
}

31
src/util.h Normal file
View File

@@ -0,0 +1,31 @@
/*
* util.h
*
* Copyright (C) 2012 James Booth <boothj5@gmail.com>
*
* This file is part of Profanity.
*
* Profanity is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Profanity is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef UTIL_H
#define UTIL_H
void get_time(char *thetime);
char * str_replace(const char *string, const char *substr,
const char *replacement);
int str_contains(char str[], int size, char ch);
#endif

665
src/windows.c Normal file
View File

@@ -0,0 +1,665 @@
/*
* windows.c
*
* Copyright (C) 2012 James Booth <boothj5@gmail.com>
*
* This file is part of Profanity.
*
* Profanity is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Profanity is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Profanity. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include <string.h>
#include <stdlib.h>
#include <ncurses.h>
#include <glib.h>
#include <libnotify/notify.h>
#include "ui.h"
#include "util.h"
#include "contact.h"
#include "preferences.h"
#define CONS_WIN_TITLE "_cons"
#define PAD_SIZE 200
#define NUM_WINS 10
// holds console at index 0 and chat wins 1 through to 9
static struct prof_win _wins[NUM_WINS];
// the window currently being displayed
static int _curr_prof_win = 0;
// shortcut pointer to console window
static WINDOW * _cons_win = NULL;
// current window state
static int dirty;
// max columns for main windows, never resize below
static int max_cols = 0;
static void _create_windows(void);
static void _print_splash_logo(WINDOW *win);
static int _find_prof_win_index(const char * const contact);
static int _new_prof_win(const char * const contact);
static void _current_window_refresh(void);
static void _win_switch_if_active(const int i);
static void _win_show_time(WINDOW *win);
static void _win_show_user(WINDOW *win, const char * const user, const int colour);
static void _win_show_message(WINDOW *win, const char * const message);
static void _show_status_string(WINDOW *win, const char * const from,
const char * const show, const char * const status, const char * const pre,
const char * const default_show);
static void _cons_show_incoming_message(const char * const short_from,
const int win_index);
static void _win_handle_switch(const int * const ch);
static void _win_handle_page(const int * const ch);
static void _win_resize_all(void);
static void _win_notify(char * short_from);
void gui_init(void)
{
initscr();
cbreak();
keypad(stdscr, TRUE);
if (has_colors()) {
use_default_colors();
start_color();
init_pair(1, prefs_get_text(), prefs_get_bkgnd());
init_pair(2, prefs_get_online(), prefs_get_bkgnd());
init_pair(3, prefs_get_text(), prefs_get_bar());
init_pair(4, prefs_get_bar_draw(), prefs_get_bar());
init_pair(5, prefs_get_offline(), prefs_get_bkgnd());
init_pair(6, prefs_get_err(), prefs_get_bkgnd());
init_pair(7, prefs_get_inc(), prefs_get_bkgnd());
init_pair(8, prefs_get_bar_text(), prefs_get_bar());
}
refresh();
create_title_bar();
create_status_bar();
create_input_window();
_create_windows();
dirty = TRUE;
}
void gui_refresh(void)
{
title_bar_refresh();
status_bar_refresh();
if (dirty) {
_current_window_refresh();
dirty = FALSE;
}
inp_put_back();
}
void gui_close(void)
{
endwin();
}
void gui_resize(const int ch, const char * const input, const int size)
{
title_bar_resize();
status_bar_resize();
_win_resize_all();
inp_win_resize(input, size);
dirty = TRUE;
}
int win_close_win(void)
{
if (win_in_chat()) {
// reset the chat win to unused
strcpy(_wins[_curr_prof_win].from, "");
wclear(_wins[_curr_prof_win].win);
// set it as inactive in the status bar
status_bar_inactive(_curr_prof_win);
// go back to console window
_curr_prof_win = 0;
title_bar_title();
dirty = TRUE;
// success
return 1;
} else {
// didn't close anything
return 0;
}
}
int win_in_chat(void)
{
return ((_curr_prof_win != 0) &&
(strcmp(_wins[_curr_prof_win].from, "") != 0));
}
char *win_get_recipient(void)
{
struct prof_win current = _wins[_curr_prof_win];
char *recipient = (char *) malloc(sizeof(char) * (strlen(current.from) + 1));
strcpy(recipient, current.from);
return recipient;
}
void win_show_incomming_msg(const char * const from, const char * const message)
{
char from_cpy[strlen(from) + 1];
strcpy(from_cpy, from);
char *short_from = strtok(from_cpy, "/");
int win_index = _find_prof_win_index(short_from);
if (win_index == NUM_WINS)
win_index = _new_prof_win(short_from);
WINDOW *win = _wins[win_index].win;
_win_show_time(win);
_win_show_user(win, short_from, 1);
_win_show_message(win, message);
if (win_index == _curr_prof_win) {
status_bar_active(win_index);
dirty = TRUE;
} else {
status_bar_new(win_index);
_cons_show_incoming_message(short_from, win_index);
if (prefs_get_flash())
flash();
}
if (prefs_get_beep())
beep();
if (prefs_get_notify())
_win_notify(short_from);
}
static void _win_notify(char * short_from)
{
notify_init("Profanity");
// create a new notification
NotifyNotification *incoming;
incoming = notify_notification_new("Profanity", short_from, NULL);
// set the timeout of the notification to 10 secs
notify_notification_set_timeout(incoming, 10000);
// set the category so as to tell what kind it is
char category[30] = "Incoming message";
notify_notification_set_category(incoming, category);
// set the urgency level of the notification
notify_notification_set_urgency(incoming, NOTIFY_URGENCY_NORMAL);
GError *error = NULL;
notify_notification_show(incoming, &error);
}
void win_show_outgoing_msg(const char * const from, const char * const to,
const char * const message)
{
int win_index = _find_prof_win_index(to);
if (win_index == NUM_WINS)
win_index = _new_prof_win(to);
WINDOW *win = _wins[win_index].win;
_win_show_time(win);
_win_show_user(win, from, 0);
_win_show_message(win, message);
status_bar_active(win_index);
if (win_index == _curr_prof_win) {
dirty = TRUE;
} else {
status_bar_new(win_index);
}
}
void win_contact_online(const char * const from, const char * const show,
const char * const status)
{
_show_status_string(_cons_win, from, show, status, "++", "online");
int win_index = _find_prof_win_index(from);
if (win_index != NUM_WINS) {
WINDOW *win = _wins[win_index].win;
_show_status_string(win, from, show, status, "++", "online");
}
if (win_index == _curr_prof_win)
dirty = TRUE;
}
void win_contact_offline(const char * const from, const char * const show,
const char * const status)
{
_show_status_string(_cons_win, from, show, status, "--", "offline");
int win_index = _find_prof_win_index(from);
if (win_index != NUM_WINS) {
WINDOW *win = _wins[win_index].win;
_show_status_string(win, from, show, status, "--", "offline");
}
if (win_index == _curr_prof_win)
dirty = TRUE;
}
void win_disconnected(void)
{
int i;
// show message in all active chats
for (i = 1; i < NUM_WINS; i++) {
if (strcmp(_wins[i].from, "") != 0) {
WINDOW *win = _wins[_curr_prof_win].win;
_win_show_time(win);
wattron(win, COLOR_PAIR(6));
wprintw(win, "%s\n", "Lost connection.");
wattroff(win, COLOR_PAIR(6));
// if current win, set dirty
if (i == _curr_prof_win) {
dirty = TRUE;
}
}
}
}
void cons_help(void)
{
cons_show("");
cons_show("Basic Commands:");
cons_show("");
cons_show("/help : This help.");
cons_show("/connect user@host : Login to jabber.");
cons_show("/msg user@host mesg : Send mesg to user.");
cons_show("/close : Close a chat window.");
cons_show("/who : Find out who is online.");
cons_show("/ros : List all contacts.");
cons_show("/quit : Quit Profanity.");
cons_show("");
cons_show("Settings:");
cons_show("");
cons_show("/beep <on/off> : Enable/disable sound notification");
cons_show("/notify <on/off> : Enable/disable desktop notifications");
cons_show("/flash <on/off> : Enable/disable screen flash notification");
cons_show("/showsplash <on/off> : Enable/disable splash logo on startup");
cons_show("");
cons_show("Status changes (msg is optional):");
cons_show("");
cons_show("/away <msg> : Set status to away.");
cons_show("/online <msg> : Set status to online.");
cons_show("/dnd <msg> : Set status to dnd (do not disturb).");
cons_show("/chat <msg> : Set status to chat (available for chat).");
cons_show("/xa <msg> : Set status to xa (extended away).");
cons_show("");
cons_show("Navigation:");
cons_show("");
cons_show("F1 : This console window.");
cons_show("F2-F10 : Chat windows.");
cons_show("UP, DOWN : Navigate input history.");
cons_show("LEFT, RIGHT : Edit current input.");
cons_show("TAB : Autocomplete command/recipient/login");
cons_show("PAGE UP, PAGE DOWN : Page the chat window.");
cons_show("");
if (_curr_prof_win == 0)
dirty = TRUE;
}
void cons_show_online_contacts(GSList *list)
{
_win_show_time(_cons_win);
wprintw(_cons_win, "Online contacts:\n");
GSList *curr = list;
while(curr) {
PContact contact = curr->data;
_win_show_time(_cons_win);
wattron(_cons_win, COLOR_PAIR(2));
wprintw(_cons_win, "%s", p_contact_name(contact));
if (p_contact_show(contact))
wprintw(_cons_win, " is %s", p_contact_show(contact));
if (p_contact_status(contact))
wprintw(_cons_win, ", \"%s\"", p_contact_status(contact));
wprintw(_cons_win, "\n");
wattroff(_cons_win, COLOR_PAIR(2));
curr = g_slist_next(curr);
}
}
void cons_bad_show(const char * const msg)
{
_win_show_time(_cons_win);
wattron(_cons_win, COLOR_PAIR(6));
wprintw(_cons_win, "%s\n", msg);
wattroff(_cons_win, COLOR_PAIR(6));
if (_curr_prof_win == 0)
dirty = TRUE;
}
void cons_show(const char * const msg)
{
_win_show_time(_cons_win);
wprintw(_cons_win, "%s\n", msg);
if (_curr_prof_win == 0)
dirty = TRUE;
}
void cons_bad_command(const char * const cmd)
{
_win_show_time(_cons_win);
wprintw(_cons_win, "Unknown command: %s\n", cmd);
if (_curr_prof_win == 0)
dirty = TRUE;
}
void win_handle_special_keys(const int * const ch)
{
_win_handle_switch(ch);
_win_handle_page(ch);
}
void win_page_off(void)
{
int rows, cols;
getmaxyx(stdscr, rows, cols);
_wins[_curr_prof_win].paged = 0;
int y, x;
getyx(_wins[_curr_prof_win].win, y, x);
int size = rows - 3;
_wins[_curr_prof_win].y_pos = y - (size - 1);
if (_wins[_curr_prof_win].y_pos < 0)
_wins[_curr_prof_win].y_pos = 0;
dirty = TRUE;
}
static void _create_windows(void)
{
int rows, cols;
getmaxyx(stdscr, rows, cols);
max_cols = cols;
// create the console window in 0
struct prof_win cons;
strcpy(cons.from, CONS_WIN_TITLE);
cons.win = newpad(PAD_SIZE, cols);
wbkgd(cons.win, COLOR_PAIR(1));
cons.y_pos = 0;
cons.paged = 0;
scrollok(cons.win, TRUE);
_wins[0] = cons;
_cons_win = _wins[0].win;
// wattrset(_cons_win, A_BOLD);
_win_show_time(_cons_win);
if (prefs_get_showsplash()) {
_print_splash_logo(_cons_win);
} else {
wprintw(_cons_win, "Welcome to Profanity.\n");
}
prefresh(_cons_win, 0, 0, 1, 0, rows-3, cols-1);
dirty = TRUE;
// create the chat windows
int i;
for (i = 1; i < NUM_WINS; i++) {
struct prof_win chat;
strcpy(chat.from, "");
chat.win = newpad(PAD_SIZE, cols);
wbkgd(chat.win, COLOR_PAIR(1));
chat.y_pos = 0;
chat.paged = 0;
// wattrset(chat.win, A_BOLD);
scrollok(chat.win, TRUE);
_wins[i] = chat;
}
}
static void _print_splash_logo(WINDOW *win)
{
wprintw(win, "Welcome to\n");
wattron(win, COLOR_PAIR(5));
wprintw(win, " ___ _ \n");
wprintw(win, " / __) (_)_ \n");
wprintw(win, " ____ ____ ___ | |__ ____ ____ _| |_ _ _ \n");
wprintw(win, "| _ \\ / ___) _ \\| __) _ | _ \\| | _) | | |\n");
wprintw(win, "| | | | | | |_| | | ( ( | | | | | | |_| |_| |\n");
wprintw(win, "| ||_/|_| \\___/|_| \\_||_|_| |_|_|\\___)__ |\n");
wprintw(win, "|_| (____/ \n");
wattroff(win, COLOR_PAIR(5));
}
static int _find_prof_win_index(const char * const contact)
{
// find the chat window for recipient
int i;
for (i = 1; i < NUM_WINS; i++)
if (strcmp(_wins[i].from, contact) == 0)
break;
return i;
}
static int _new_prof_win(const char * const contact)
{
int i;
// find the first unused one
for (i = 1; i < NUM_WINS; i++)
if (strcmp(_wins[i].from, "") == 0)
break;
// set it up
strcpy(_wins[i].from, contact);
wclear(_wins[i].win);
return i;
}
static void _win_switch_if_active(const int i)
{
win_page_off();
if (strcmp(_wins[i].from, "") != 0) {
_curr_prof_win = i;
win_page_off();
if (i == 0) {
title_bar_title();
} else {
title_bar_show(_wins[i].from);
status_bar_active(i);
}
}
dirty = TRUE;
}
static void _win_show_time(WINDOW *win)
{
char tstmp[80];
get_time(tstmp);
wprintw(win, "%s - ", tstmp);
}
static void _win_show_user(WINDOW *win, const char * const user, const int colour)
{
if (colour)
wattron(win, COLOR_PAIR(2));
wprintw(win, "%s: ", user);
if (colour)
wattroff(win, COLOR_PAIR(2));
}
static void _win_show_message(WINDOW *win, const char * const message)
{
// wattroff(win, A_BOLD);
wprintw(win, "%s\n", message);
// wattron(win, A_BOLD);
}
static void _current_window_refresh(void)
{
int rows, cols;
getmaxyx(stdscr, rows, cols);
WINDOW *current = _wins[_curr_prof_win].win;
prefresh(current, _wins[_curr_prof_win].y_pos, 0, 1, 0, rows-3, cols-1);
}
void _win_resize_all(void)
{
int rows, cols;
getmaxyx(stdscr, rows, cols);
// only make the pads bigger, to avoid data loss on cropping
if (cols > max_cols) {
max_cols = cols;
int i;
for (i = 0; i < NUM_WINS; i++) {
wresize(_wins[i].win, PAD_SIZE, cols);
}
}
WINDOW *current = _wins[_curr_prof_win].win;
prefresh(current, _wins[_curr_prof_win].y_pos, 0, 1, 0, rows-3, cols-1);
}
static void _show_status_string(WINDOW *win, const char * const from,
const char * const show, const char * const status, const char * const pre,
const char * const default_show)
{
_win_show_time(win);
if (strcmp(default_show, "online") == 0) {
wattron(win, COLOR_PAIR(2));
} else {
wattron(win, COLOR_PAIR(5));
// wattroff(win, A_BOLD);
}
wprintw(win, "%s %s", pre, from);
if (show != NULL)
wprintw(win, " is %s", show);
else
wprintw(win, " is %s", default_show);
if (status != NULL)
wprintw(win, ", \"%s\"", status);
wprintw(win, "\n");
if (strcmp(default_show, "online") == 0) {
wattroff(win, COLOR_PAIR(2));
} else {
wattroff(win, COLOR_PAIR(5));
// wattron(win, A_BOLD);
}
}
static void _cons_show_incoming_message(const char * const short_from, const int win_index)
{
_win_show_time(_cons_win);
wattron(_cons_win, COLOR_PAIR(7));
wprintw(_cons_win, "<< incoming from %s (%d)\n", short_from, win_index + 1);
wattroff(_cons_win, COLOR_PAIR(7));
}
static void _win_handle_switch(const int * const ch)
{
if (*ch == KEY_F(1)) {
_win_switch_if_active(0);
} else if (*ch == KEY_F(2)) {
_win_switch_if_active(1);
} else if (*ch == KEY_F(3)) {
_win_switch_if_active(2);
} else if (*ch == KEY_F(4)) {
_win_switch_if_active(3);
} else if (*ch == KEY_F(5)) {
_win_switch_if_active(4);
} else if (*ch == KEY_F(6)) {
_win_switch_if_active(5);
} else if (*ch == KEY_F(7)) {
_win_switch_if_active(6);
} else if (*ch == KEY_F(8)) {
_win_switch_if_active(7);
} else if (*ch == KEY_F(9)) {
_win_switch_if_active(8);
} else if (*ch == KEY_F(10)) {
_win_switch_if_active(9);
}
}
static void _win_handle_page(const int * const ch)
{
int rows, cols, y, x;
getmaxyx(stdscr, rows, cols);
getyx(_wins[_curr_prof_win].win, y, x);
int page_space = rows - 4;
int *page_start = &_wins[_curr_prof_win].y_pos;
// page up
if (*ch == KEY_PPAGE) {
*page_start -= page_space;
// went past beginning, show first page
if (*page_start < 0)
*page_start = 0;
_wins[_curr_prof_win].paged = 1;
dirty = TRUE;
// page down
} else if (*ch == KEY_NPAGE) {
*page_start += page_space;
// only got half a screen, show full screen
if ((y - (*page_start)) < page_space)
*page_start = y - page_space;
// went past end, show full screen
else if (*page_start >= y)
*page_start = y - page_space;
_wins[_curr_prof_win].paged = 1;
dirty = TRUE;
}
}