--- /dev/null
+# Citadel client makefile
+
+CC = gcc
+
+# For Gtk+ client
+
+# Gtk+ version of citadel/ux client
+CLIENTDIR = gtk
+CLIENT = gcit
+LIB = libcli_cit.so
+
+all: $(CLIENT) $(LIB)
+
+clean:
+ rm -f $(CLIENT) $(LIB) *.o *~
+ (cd libcli_cit; make clean ; cd ..)
+ (cd $(CLIENTDIR); make clean; cd ..)
+
+install: $(CLIENT) $(LIB)
+ (cd libcli_cit; make install; cd ..)
+ (cd $(CLIENTDIR); make install; cd ..)
+
+$(CLIENT)::
+ (cd $(CLIENTDIR) ; make all; cd ..)
+
+$(LIB)::
+ (cd libcli_cit ; make all; cd ..)
+
--- /dev/null
+# Citadel client makefile
+
+CC = gcc
+DATA_DIR=/usr/share/gcit
+Q_PIXMAP_DIR=\"$(DATA_DIR)\"
+DEFS= -DHAS_GDK_IMLIB -DDATA_DIR=\"$(DATA_DIR)\" -DQ_PIXMAP_DIR=$(Q_PIXMAP_DIR)
+GDK_IMLIB = -lgif -ljpeg -lpng -lz -ltiff -lgdk_imlib
+CFLAGS = -Wall -g `gtk-config --cflags` -I../libcli_cit/ $(DEFS)
+LDFLAGS = `gtk-config --libs` -lcli_cit -L..
+# For Gtk+ client
+
+# Gtk+ version of citadel/ux client
+TARGET = ../gcit
+OBJS = gcit.o gtk_misc.o gui.o
+
+all: $(TARGET)
+
+clean:
+ rm -f $(TARGET) *.o *~
+
+install: $(TARGET)
+ cp $(TARGET) /usr/bin/
+ if [ ! -d $(DATA_DIR) ]; then mkdir $(DATA_DIR) ; fi
+ cp gcit.gif $(DATA_DIR)/
+ cp gcitrc $(DATA_DIR)/
+
+$(TARGET): $(OBJS)
+ $(CC) $(LDFLAGS) -o $(TARGET) $(OBJS) $(GDK_IMLIB)
+
+gcit.o: gcit.c ../libcli_cit/client_api.h ../libcli_cit/citadel_util.h gtk_misc.h
+
+gtk_misc.o: gtk_misc.c gtk_misc.h
+
+gui.o: ../libcli_cit/client_api.h ../libcli_cit/citadel_util.h gtk_misc.h gui.h
--- /dev/null
+Things not done with the Gtk client:
+
+- New user login
+- Chat
--- /dev/null
+
+style "text"
+{
+ font = "-misc-fixed-medium-r-normal--10-100-*-*-*-*-*-*"
+}
+
+style "labels"
+{
+ font = "-misc-fixed-medium-r-normal--10-100-*-*-*-*-*-*"
+}
+
+style "clistitems"
+{
+ font = "-misc-fixed-medium-r-normal--10-100-*-*-*-*-*-*"
+}
+
+style "treeitems"
+{
+ font = "-misc-fixed-medium-r-normal--10-100-*-*-*-*-*-*"
+}
+
+style "default"
+{
+ font = "-misc-fixed-medium-r-normal--10-100-*-*-*-*-*-*"
+}
+
+widget_class "*GtkText" style "text"
+widget_class "*GtkLabel" style "labels"
+widget_class "*GtkCList" style "clistitems"
+widget_class "*GtkTree" style "treeitems"
+widget_class "*GtkTreeItem" style "treeitems"
+widget_class "*" style "default"
--- /dev/null
+/*
+
+gcit
+
+Protected by the red, the black and the green with a key!
+
+Brian Costello
+btx@calyx.net
+
+*/
+
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <gtk/gtk.h>
+#include <gdk/gdk.h>
+#include <gdk/gdkx.h>
+#include <sys/types.h>
+#include <sys/utsname.h>
+#ifdef HAS_GDK_IMLIB
+#include <gdk_imlib.h>
+#endif
+#include "client_api.h"
+#include "citadel_util.h"
+#include "gcit.h"
+#include "gui.h"
+#include "gtk_misc.h"
+
+client_context our_context;
+extern GtkWidget *page_user, *page_msg, *user_e, *pass_e, *host_e;
+extern GtkWidget *user_info_window;
+extern GtkWidget *maintext, *posttext, *chattext, *roomlist, *wholist, *pager;
+extern GtkWidget *mainwindow, *roomwindow, *whowindow;
+extern int changed_goto, next_goto_row;
+char lasthost[256]=DEFAULT_HOST;
+char lastusername[256]={0x00};
+char lastpassword[256]={0x00};
+
+void display_list(GtkWidget *text, citadel_list *list)
+{
+ citadel_list *t_list;
+
+ for (t_list = list; t_list; t_list = t_list->next)
+ print_gtk(text, "%s\n", t_list->listitem);
+
+ return;
+}
+
+void display_msg_header(GtkWidget *text, int msgnum, long post_time, char *from, char *rcpt, char *roomname, char *nodeshort)
+{
+ if (roomname[0])
+ print_gtk(text, "\nRoom: %s\n", roomname);
+ print_gtk(text, " Msg: %d\n", msgnum);
+ print_gtk(text, "From: %s", from);
+ if (nodeshort[0])
+ print_gtk(text, " (@%s)\n", nodeshort);
+ else
+ print_gtk(text, "\n");
+ if (rcpt[0])
+ print_gtk(text, "To: %30s\n", rcpt);
+ else
+ print_gtk(text, "\n");
+}
+
+void display_message(GtkWidget *text, citadel_list *list)
+{
+ citadel_list *t_list;
+ int textfound=0;
+ int msgn;
+ char path[256];
+ long post_time;
+ char from[256];
+ char rcpt[256];
+ char roomname[256];
+ char nodeshort[128];
+ char nodelong[256];
+
+ path[0] = '\0';
+ post_time = 0;
+ from[0] = '\0';
+ rcpt[0] = '\0';
+ roomname[0] = '\0';
+ nodeshort[0] = '\0';
+ nodelong[0] = '\0';
+
+ t_list = list;
+
+ print_gtk(text, "---------------------------------------------------------------------\n");
+ while ((!textfound) && (t_list))
+ {
+#ifdef DEBUG
+ printf("Looking at listitem - %s\n", t_list->listitem);
+#endif
+ if (!strncasecmp(t_list->listitem, "msgn=", 5))
+ msgn = atol(t_list->listitem);
+ if (!strncasecmp(t_list->listitem, "time=", 5))
+ post_time = atol(t_list->listitem);
+ if (!strncasecmp(t_list->listitem, "path=", 5))
+ {
+ strncpy(path, &t_list->listitem[5], sizeof(path)-1);
+ path[sizeof(path)-1] = '\0';
+ }
+ if (!strncasecmp(t_list->listitem, "from=", 5))
+ {
+ strncpy(from, &t_list->listitem[5], sizeof(from)-1);
+ from[sizeof(from)-1] = '\0';
+ }
+ if (!strncasecmp(t_list->listitem, "rcpt=", 5))
+ {
+ strncpy(rcpt, &t_list->listitem[5], sizeof(rcpt)-1);
+ rcpt[sizeof(rcpt)-1] = '\0';
+ }
+ if (!strncasecmp(t_list->listitem, "room=", 5))
+ {
+ strncpy(roomname, &t_list->listitem[5], sizeof(roomname)-1);
+ roomname[sizeof(roomname)-1] = '\0';
+ }
+ if (!strncasecmp(t_list->listitem, "node=", 5))
+ {
+ strncpy(nodeshort, &t_list->listitem[5], sizeof(nodeshort)-1);
+ nodeshort[sizeof(nodeshort)-1] = '\0';
+ }
+ if (!strncasecmp(t_list->listitem, "hnod=", 5))
+ {
+ strncpy(nodelong, &t_list->listitem[5], sizeof(nodelong)-1);
+ nodelong[sizeof(nodelong)-1] = '\0';
+ }
+
+ if (!strncasecmp(t_list->listitem, "text", 4))
+ {
+ textfound = 1;
+ }
+
+ t_list=t_list->next;
+ }
+
+ display_msg_header(text, msgn,post_time, from, rcpt, roomname, nodeshort);
+ display_list(text, t_list);
+ print_gtk(text, "---------------------------------------------------------------------\n");
+}
+
+void display_room_info(GtkWidget *text, client_context *our_context)
+{
+ print_gtk(text, "\nRoom: %s - (%d new of %d messages total)\n", our_context->roomname, our_context->unread_msg, our_context->num_msg);
+
+}
+
+
+/*
+
+get a list of the new messages in a room
+
+*/
+
+void get_room_new_msgs()
+{
+ if (our_context.room_msgs)
+ free_citadel_list(&our_context.room_msgs);
+ get_new_msg_list(&our_context, &our_context.room_msgs);
+ our_context.next_msg_ptr = our_context.room_msgs;
+}
+
+void do_nextmsg(GtkWidget *wid, GtkWidget *w)
+{
+ citadel_list *msgtext;
+
+ if (our_context.next_msg_ptr)
+ {
+ get_msg_num(&our_context, atoi(our_context.next_msg_ptr->listitem), &msgtext);
+ our_context.next_msg_ptr = our_context.next_msg_ptr->next;
+ display_message((GtkWidget *)maintext, msgtext);
+ free_citadel_list(&msgtext);
+ }
+ else
+ get_room_new_msgs();
+}
+
+/*
+
+Get the list of the last num messages, and display the first.
+
+*/
+
+void get_room_last_n(int num)
+{
+ citadel_list *msgtext;
+
+ if (our_context.room_msgs)
+ free_citadel_list(&our_context.room_msgs);
+ get_last_msg_list(&our_context, num, &our_context.room_msgs);
+ our_context.next_msg_ptr = our_context.room_msgs;
+
+ if (our_context.next_msg_ptr)
+ {
+ get_msg_num(&our_context, atoi(our_context.next_msg_ptr->listitem), &msgtext);
+ our_context.next_msg_ptr = our_context.next_msg_ptr->next;
+ display_message((GtkWidget *)maintext, msgtext);
+ free_citadel_list(&msgtext);
+ }
+}
+
+void do_goto(GtkWidget *widget, GtkWidget *w)
+{
+ citadel_parms *parms;
+ char *text;
+
+ parms = newparms();
+
+ if (!changed_goto)
+ {
+ if ((!our_context.new_msg_rooms) || (!our_context.next_new_msg_room))
+ {
+ if (our_context.new_msg_rooms)
+ free_citadel_list(&our_context.new_msg_rooms);
+ get_all_new_rooms(&our_context, &our_context.new_msg_rooms);
+ our_context.next_new_msg_room = our_context.new_msg_rooms;
+ if (!our_context.next_new_msg_room)
+ return;
+ citadel_parseparms(our_context.next_new_msg_room->listitem, parms);
+ if (our_context.new_msg_rooms)
+ {
+ next_goto_row = find_clist_row(roomlist, &text, parms->argv[0]);
+ }
+ }
+ gtk_clist_select_row(GTK_CLIST(roomlist), next_goto_row, 0);
+ our_context.next_new_msg_room = our_context.next_new_msg_room->next;
+ if (our_context.next_new_msg_room)
+ {
+ next_goto_row = find_clist_row(roomlist, &text, parms->argv[0]);
+ }
+ }
+
+ goto_room(&our_context, our_context.selected_room, NULL, parms, 1);
+ display_room_info((GtkWidget *)maintext, &our_context);
+
+/* get_room_last_n(1); */
+ get_room_new_msgs();
+ free_citadel_parms(&parms);
+ changed_goto = 0;
+}
+
+void do_connect(GtkWidget *widget, GtkWidget *text)
+{
+ citadel_parms *parms;
+ citadel_list *list;
+
+ strcpy(our_context.username, gtk_entry_get_text(GTK_ENTRY(user_e)));
+ strcpy(our_context.password, gtk_entry_get_text(GTK_ENTRY(pass_e)));
+ strcpy(our_context.host, gtk_entry_get_text(GTK_ENTRY(host_e)));
+ strcpy(lastusername, our_context.username);
+ strcpy(lastpassword, our_context.password);
+ strcpy(lasthost, our_context.hostname);
+
+ parms = newparms();
+
+ if (client_connect(&parms, &our_context, &list) <0)
+ {
+ print_gtk(text, "Unable to connect to host %s port %d.\n", our_context.host, our_context.port);
+ free_citadel_parms(&parms);
+ return;
+ }
+ reset_parms(&parms);
+
+ if (GTK_WIDGET_VISIBLE(user_info_window))
+ gtk_widget_destroy(user_info_window);
+
+ print_gtk(text, "Connected to %s port %d.\n", our_context.host, our_context.port);
+
+ display_list(text, list); /* Display the opening "hello" banner */
+ free_citadel_list(&list);
+
+ display_room_info(text, &our_context);
+ display_room_window();
+ printf("@@ done display_room_window()\n");
+ display_who_window();
+
+ get_room_new_msgs();
+
+ gtk_timeout_add(30000, update_func, NULL);
+ gtk_timeout_add(100000, get_room_msgs_func, (int)0);
+}
+
+void do_close(GtkWidget *widget, GtkWidget *w)
+{
+ if (our_context.connected)
+ {
+ print_gtk((GtkWidget *) maintext, "Disconnected from %s port %d.\n", our_context.host, our_context.port);
+ citadel_end_session(&our_context);
+ if (roomwindow)
+ {
+ gtk_widget_destroy(roomwindow);
+ roomlist = NULL;
+ }
+ if (whowindow)
+ {
+ gtk_widget_destroy(whowindow);
+ wholist = NULL;
+ }
+ }
+ return;
+}
+
+
+void do_posting(GtkWidget *widget, GtkWidget *t)
+{
+ int textlen, i;
+ int fd, c;
+ char ftemplate[256];
+ citadel_parms *parms;
+
+ parms = newparms();
+
+ sprintf(ftemplate, "/tmp/citgtk_XXXXXX");
+ fd = mkstemp(ftemplate);
+
+ textlen = gtk_text_get_length(GTK_TEXT(t));
+ for (i=0; i<textlen; i++)
+ {
+ c = GTK_TEXT_INDEX(GTK_TEXT(t), i);
+ if (write(fd, &c, 1) < 0)
+ {
+ perror("Write temp post data");
+ exit(1);
+ }
+ }
+ close(fd);
+
+ if (post_file(ftemplate, &our_context, parms)<0)
+ print_gtk((GtkWidget *)maintext, "Unable to post the message!\n");
+ else
+ print_gtk((GtkWidget *)maintext, "Message posted.\n");
+
+ get_room_new_msgs();
+ free_citadel_parms(&parms);
+ do_post(widget, t);
+ return;
+}
+
+
+void do_send_page(GtkWidget *widget, GtkWidget *w)
+{
+ int ret;
+ char *username=NULL;
+ char *msg=NULL;
+ char *sptr;
+ char newmsg[78];
+ int len, subamt;
+
+ if (page_user)
+ username = GTK_ENTRY(page_user)->text;
+ if (page_msg)
+ msg = GTK_ENTRY(page_msg)->text;
+
+ if (msg)
+ len = strlen(msg);
+ else
+ return;
+
+ sptr = msg;
+ while (len > 0)
+ {
+ if (len > 76)
+ subamt = 76;
+ else
+ subamt = len;
+
+ strncpy(newmsg, sptr, subamt);
+ sptr += subamt;
+ newmsg[subamt] = '\0';
+ len -= subamt;
+ if ((ret = send_page(&our_context, username, newmsg))<0)
+ {
+ fprintf(stderr, "Unable to send the page.\n");
+ return;
+ }
+
+ }
+
+ gtk_entry_set_text(GTK_ENTRY(page_msg), "");
+
+ return;
+}
+
+void client_quit(GtkWidget *widget, GtkWidget *window)
+{
+ do_close(NULL, NULL);
+ gtk_widget_destroy(window);
+ gtk_main_quit();
+}
+
+
+int create_main_window()
+{
+ create_display_window();
+ switchabout();
+ return 1;
+}
+
+int find_clist_row(GtkWidget *list, char **buf, char *searchstr)
+{
+ int finished = -1;
+ int row;
+
+ for (row=0;((row<GTK_CLIST(list)->rows) && (finished<0)); row++)
+ {
+ gtk_clist_get_text(GTK_CLIST(list), row, 0, buf);
+ if (!strncmp((*buf), searchstr, strlen(searchstr)))
+ {
+ finished = row;
+ }
+ }
+
+ return finished;
+}
+
+int get_room_msgs_func(int allrooms)
+{
+ citadel_list *list, *t_list;
+ citadel_parms *parms;
+ char *cptr;
+ int r;
+
+ if (!our_context.connected)
+ return FALSE;
+
+ parms = newparms();
+
+ if (allrooms)
+ get_all_rooms(&our_context, &list);
+ else
+ get_all_new_rooms(&our_context, &list);
+ for (t_list = list; t_list; t_list=t_list->next)
+ {
+ if (citadel_parseparms(t_list->listitem, parms)<0)
+ {
+ fprintf(stderr, "Error: Citadel parseparms failed of %s.\n", t_list->listitem);
+ return TRUE;
+ }
+
+ if ((r=find_clist_row(roomlist, &cptr, parms->argv[0]))<0)
+ {
+ fprintf(stderr, "Error- room %s not found!\n", parms->argv[0]);
+ exit(1);
+ }
+ else
+ printf("Room %s found on row #%d/%d\n", cptr, r, GTK_CLIST(roomlist)->rows);
+
+ reset_parms(&parms);
+
+ if (goto_room(&our_context, cptr, NULL, parms, 0)<0)
+ {
+ fprintf(stderr, "Error: Unable to go to room %s.\n", t_list->listitem);
+ return TRUE;
+ }
+
+ printf("Making row %d/1 %s\n", r, parms->argv[1]);
+ printf("Making row %d/2 %s\n", r, parms->argv[2]);
+ gtk_clist_set_text(GTK_CLIST(roomlist), r, 1, parms->argv[1]);
+ gtk_clist_set_text(GTK_CLIST(roomlist), r, 2, parms->argv[2]);
+ reset_parms(&parms);
+ }
+ free_citadel_list(&list);
+ reset_parms(&parms);
+
+ if (goto_room(&our_context, our_context.selected_room, NULL, parms, 0)<0)
+ {
+ fprintf(stderr, "Error: Unable to go to room %s.\n", t_list->listitem);
+ return TRUE;
+ }
+ free_citadel_parms(&parms);
+ return TRUE;
+}
+
+int update_func()
+{
+ citadel_list *list;
+
+ if (!our_context.connected)
+ return FALSE;
+
+ if (check_page(&our_context, &list)>0)
+ {
+ print_gtk(maintext, "Received page:\n");
+ display_list(maintext, list);
+ free_citadel_list(&list);
+ }
+
+ return TRUE;
+
+
+}
+
+int main(int argc, char **argv)
+{
+ char path[512];
+ gtk_set_locale();
+ gtk_init(&argc, &argv);
+ gdk_imlib_init();
+
+ snprintf(path, sizeof(path)-1, "%s/gcitrc", DATA_DIR);
+ path[sizeof(path)-1] = '\0';
+ gtk_rc_parse(path);
+
+ bzero(&our_context, sizeof(our_context));
+
+ create_main_window();
+
+ gtk_main();
+
+ return(0);
+}
+
+
--- /dev/null
+/*
+
+gcit.h
+the header file for the Gtk+ client frontend
+btx@calyx.net
+
+*/
+
+
+/* User definables */
+
+#define DEFAULT_HOST "127.0.0.1"
+#define DEFAULT_HOST_REVEAL "shaq.eop.gov"
+#define DEFAULT_ROOM_REVEAL "secret room"
+
+/* Not user definables */
+#define CITADEL_VERSION "Gtk Citadel Client v0.1"
+#define CITADEL_GTK_CLIID 1
+#define CITADEL_GTK_VERNO 1
+
+void display_room_window();
+void display_who_window();
+void do_post(GtkWidget *, GtkWidget *);
+void create_pager(GtkWidget *, GtkWidget *);
+int update_func();
+void do_connect(GtkWidget *, GtkWidget *);
+void get_room_new_msgs();
+int get_room_msgs_func();
+void do_goto(GtkWidget *, GtkWidget *);
+void do_posting(GtkWidget *, GtkWidget *);
+void do_send_page(GtkWidget *, GtkWidget *);
+void do_nextmsg(GtkWidget *, GtkWidget *);
+void do_close(GtkWidget *, GtkWidget *);
+void client_quit(GtkWidget *, GtkWidget *);
+int find_clist_row(GtkWidget *, char **, char *);
--- /dev/null
+
+style "text"
+{
+ font = "-misc-fixed-medium-r-normal--10-100-*-*-*-*-*-*"
+}
+
+style "labels"
+{
+ font = "-misc-fixed-medium-r-normal--10-100-*-*-*-*-*-*"
+}
+
+style "clistitems"
+{
+ font = "-misc-fixed-medium-r-normal--10-100-*-*-*-*-*-*"
+}
+
+style "treeitems"
+{
+ font = "-misc-fixed-medium-r-normal--10-100-*-*-*-*-*-*"
+}
+
+style "default"
+{
+ font = "-misc-fixed-medium-r-normal--10-100-*-*-*-*-*-*"
+}
+
+widget_class "*GtkText" style "text"
+widget_class "*GtkLabel" style "labels"
+widget_class "*GtkCList" style "clistitems"
+widget_class "*GtkTree" style "treeitems"
+widget_class "*GtkTreeItem" style "treeitems"
+widget_class "*" style "default"
--- /dev/null
+/*
+
+Misc. GTK display routines
+
+*/
+
+#include <stdio.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <sys/types.h>
+#include <netinet/ip.h>
+#include <gtk/gtk.h>
+#include <stdarg.h>
+
+GtkWidget *dialog_window = NULL;
+
+void print_gtk(GtkWidget *text, char *str, ...)
+{
+ char buf[256];
+ va_list va_args;
+
+ if (!text)
+ return;
+
+ va_start(va_args, str);
+ vsprintf(buf, str, va_args);
+
+ if (text)
+ {
+ if (!GTK_IS_TEXT(text))
+ printf("We have a non-text here - %s\n", buf);
+ else
+ gtk_text_insert(GTK_TEXT(text), NULL, NULL, NULL, buf, -1);
+ }
+ return;
+}
+
+void gtk_killyesno()
+{
+ if (dialog_window)
+ {
+ gtk_widget_destroy(dialog_window);
+ dialog_window = NULL;
+ }
+}
+
+void gtk_yesno(char *msg, char *title, int def, void *yesproc, void *noproc)
+{
+ GtkWidget *button, *label;
+
+ dialog_window = gtk_dialog_new();
+ gtk_signal_connect (GTK_OBJECT(dialog_window), "destroy",
+ GTK_SIGNAL_FUNC(gtk_widget_destroyed), &dialog_window);
+
+ gtk_window_set_title(GTK_WINDOW(dialog_window), title);
+ gtk_window_position(GTK_WINDOW(dialog_window), GTK_WIN_POS_MOUSE);
+
+ label = gtk_label_new(msg);
+ gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog_window)->vbox), label, TRUE, TRUE, 0);
+ gtk_widget_show(label);
+
+ button = gtk_button_new_with_label("Yes");
+ gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog_window)->action_area), button,
+ TRUE, TRUE, 0);
+
+ gtk_signal_connect(GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(yesproc), NULL);
+ if (def)
+ GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
+ if (def == 1)
+ gtk_widget_grab_default(button);
+ gtk_widget_show(button);
+
+ button = gtk_button_new_with_label("No");
+ gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog_window)->action_area), button,
+ TRUE, TRUE, 0);
+ gtk_signal_connect(GTK_OBJECT(button), "clicked", GTK_SIGNAL_FUNC(noproc), NULL);
+ if (def)
+ GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
+ if (def == 2)
+ gtk_widget_grab_default(button);
+ gtk_widget_show(button);
+ gtk_widget_show(dialog_window);
+}
--- /dev/null
+/*
+
+Misc. gtk display routines
+
+*/
+
+void print_gtk(GtkWidget *text, char *str, ...);
+void gtk_yesno(char *, char *, int, void *, void *);
+void gtk_killyesno();
--- /dev/null
+/*
+
+GUI ugliness offloaded here!
+
+*/
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <string.h>
+#include <gtk/gtk.h>
+#include <gdk/gdk.h>
+#include <gdk/gdkx.h>
+#include <sys/types.h>
+#include <sys/utsname.h>
+#ifdef HAS_GDK_IMLIB
+#include <gdk_imlib.h>
+#endif
+#include "client_api.h"
+#include "citadel_util.h"
+#include "gcit.h"
+#include "gtk_misc.h"
+
+GtkWidget *page_user, *page_msg, *user_e, *pass_e, *host_e;
+GtkWidget *user_info_window = NULL;
+GtkWidget *maintext, *posttext, *chattext, *roomlist, *wholist, *pager;
+GtkWidget *mainwindow, *roomwindow, *whowindow;
+GtkWidget *aboutwindow = NULL;
+GdkPixmap *pixmap;
+GtkWidget *image_drawing;
+extern client_context our_context;
+extern char lasthost[];
+extern char lastusername[];
+extern char lastpassword[];
+
+int changed_goto=0;
+int next_goto_row;
+int cur_goto_row;
+
+int get_user_info(GtkWidget *w1, GtkWidget *wt)
+{
+ GtkWidget *box1, *box2;
+ GtkWidget *separator;
+ GtkWidget *button;
+ GtkWidget *label;
+ struct utsname utsname;
+
+
+ if (!user_info_window)
+ {
+ our_context.port = 504;
+ our_context.devid = CITADEL_API_DEVID;
+ our_context.cliid = CITADEL_GTK_CLIID;
+ our_context.verno = CITADEL_GTK_VERNO;
+ strcpy(our_context.fake_host, DEFAULT_HOST_REVEAL);
+ strcpy(our_context.fake_room, DEFAULT_ROOM_REVEAL);
+ strcpy(our_context.clientstr, CITADEL_VERSION);
+ if (uname(&utsname) < 0)
+ strcpy(our_context.hostname, "unknown");
+ else
+ strncpy(our_context.hostname, utsname.nodename, sizeof(our_context.hostname));
+ user_info_window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ gtk_signal_connect (GTK_OBJECT (user_info_window), "destroy",
+ GTK_SIGNAL_FUNC(gtk_widget_destroyed),
+ &user_info_window);
+ gtk_window_set_title (GTK_WINDOW (user_info_window), "Please login");
+ gtk_widget_set_uposition(user_info_window, 401, 0);
+ gtk_container_border_width (GTK_CONTAINER (user_info_window), 0);
+
+ box1 = gtk_vbox_new (FALSE, 0);
+ gtk_container_add (GTK_CONTAINER (user_info_window), box1);
+ gtk_widget_show (box1);
+
+ box2 = gtk_vbox_new (FALSE, 5);
+ gtk_container_border_width (GTK_CONTAINER (box2), 5);
+ gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
+ gtk_widget_show (box2);
+
+ label = gtk_label_new("Host:");
+ gtk_box_pack_start(GTK_BOX (box2), label, TRUE, TRUE, 0);
+ gtk_widget_show (label);
+
+ host_e = gtk_entry_new ();
+ gtk_entry_set_text (GTK_ENTRY (host_e), lasthost);
+ gtk_editable_select_region (GTK_EDITABLE (host_e), 0, -1);
+ gtk_box_pack_start (GTK_BOX (box2), host_e, TRUE, TRUE, 0);
+ gtk_widget_show (host_e);
+
+ separator = gtk_hseparator_new();
+ gtk_box_pack_start(GTK_BOX(box2), separator, TRUE, TRUE, 0);
+ gtk_widget_show(separator);
+
+ label = gtk_label_new("Username:");
+ gtk_box_pack_start(GTK_BOX (box2), label, TRUE, TRUE, 0);
+ gtk_widget_show (label);
+
+ user_e = gtk_entry_new ();
+ gtk_entry_set_text (GTK_ENTRY (user_e), lastusername);
+ gtk_box_pack_start (GTK_BOX (box2), user_e, TRUE, TRUE, 0);
+ gtk_widget_show (user_e);
+
+ label = gtk_label_new("Password:");
+ gtk_box_pack_start(GTK_BOX (box2), label, TRUE, TRUE, 0);
+ gtk_widget_show (label);
+
+ pass_e = gtk_entry_new ();
+ gtk_entry_set_text (GTK_ENTRY (pass_e), lastpassword);
+ gtk_box_pack_start (GTK_BOX (box2), pass_e, TRUE, TRUE, 0);
+ gtk_entry_set_visibility(GTK_ENTRY(pass_e), FALSE);
+ gtk_widget_show (pass_e);
+
+ if (gtk_entry_get_text(GTK_ENTRY(user_e)))
+ gtk_entry_select_region(GTK_ENTRY(user_e), 0, strlen(gtk_entry_get_text(GTK_ENTRY(user_e)))-1);
+
+ separator = gtk_hseparator_new();
+ gtk_box_pack_start(GTK_BOX(box2), separator, TRUE, TRUE, 0);
+ gtk_widget_show(separator);
+
+ box2 = gtk_hbox_new(FALSE, 10);
+ gtk_container_border_width(GTK_CONTAINER(box2), 5);
+ gtk_box_pack_start(GTK_BOX(box1), box2, TRUE, TRUE, 0);
+ gtk_widget_show(box2);
+
+ button = gtk_button_new_with_label("Ok");
+ gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
+ GTK_SIGNAL_FUNC(do_connect),
+ GTK_OBJECT (maintext));
+ GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
+ gtk_widget_grab_default(button);
+ gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
+ gtk_widget_show (button);
+
+ button = gtk_button_new_with_label("Cancel");
+ gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
+ GTK_SIGNAL_FUNC(gtk_widget_destroy),
+ GTK_OBJECT (user_info_window));
+ gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
+ gtk_widget_show (button);
+
+ }
+
+ if (!GTK_WIDGET_VISIBLE(user_info_window))
+ gtk_widget_show(user_info_window);
+ else
+ gtk_widget_destroy(user_info_window);
+ return 1;
+}
+
+
+void select_room(GtkWidget *widget, int row, int col, GdkEventButton *bevent)
+{
+ char *text;
+
+ gtk_clist_get_text(GTK_CLIST(widget), row, 0, &text);
+ strcpy(our_context.selected_room, text);
+ changed_goto = 1;
+ return;
+}
+
+void select_who(GtkWidget *widget, int row, int col, GdkEventButton *bevent)
+{
+ char *text;
+
+ gtk_clist_get_text(GTK_CLIST(widget), row, 0, &text);
+ strcpy(our_context.selected_who, text);
+ return;
+}
+
+void display_room_window()
+{
+
+#define ROOM_COLS 4
+
+ static char *titles[ROOM_COLS] =
+ {
+ "Room Name",
+ "New Messages",
+ "Total Messages",
+ "Flags"
+ };
+
+ char text[ROOM_COLS][128];
+ char *texts[ROOM_COLS];
+ GtkWidget *box1;
+ GtkWidget *box2;
+ GtkWidget *clist;
+ GtkWidget *button;
+ GtkWidget *separator;
+ citadel_list *list, *t_list;
+ citadel_parms *parms;
+ char flagbuf[127];
+
+ if (!roomwindow)
+ {
+ roomwindow = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ gtk_signal_connect (GTK_OBJECT (roomwindow), "destroy",
+ GTK_SIGNAL_FUNC(gtk_widget_destroyed),
+ &roomwindow);
+ gtk_window_set_title (GTK_WINDOW (roomwindow), "Rooms");
+ gtk_widget_set_uposition(roomwindow, 0, 420);
+ gtk_container_border_width (GTK_CONTAINER (roomwindow), 0);
+ box1 = gtk_vbox_new (FALSE, 0);
+ gtk_container_add (GTK_CONTAINER (roomwindow), box1);
+ gtk_widget_show (box1);
+
+ gtk_widget_set_usize(roomwindow, 380, 250);
+ box2 = gtk_vbox_new (FALSE, 5);
+ gtk_container_border_width (GTK_CONTAINER (box2), 5);
+ gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
+ gtk_widget_show (box2);
+ clist = gtk_clist_new_with_titles (ROOM_COLS, titles);
+ gtk_clist_set_row_height (GTK_CLIST (clist), 20);
+ gtk_signal_connect (GTK_OBJECT (clist),
+ "select_row",
+ (GtkSignalFunc) select_room,
+ NULL);
+ gtk_clist_set_column_width (GTK_CLIST (clist), 0, 100);
+ gtk_clist_set_selection_mode (GTK_CLIST (clist), GTK_SELECTION_BROWSE);
+ gtk_clist_set_policy (GTK_CLIST (clist),
+ GTK_POLICY_AUTOMATIC,
+ GTK_POLICY_AUTOMATIC);
+ gtk_container_border_width (GTK_CONTAINER (clist), 5);
+ gtk_box_pack_start (GTK_BOX (box2), clist, TRUE, TRUE, 0);
+
+ gtk_clist_set_column_width (GTK_CLIST (clist), 0, 90);
+ gtk_clist_set_column_width (GTK_CLIST (clist), 1, 90);
+ gtk_clist_set_column_width (GTK_CLIST (clist), 2, 90);
+ gtk_clist_set_column_width (GTK_CLIST (clist), 3, 150);
+
+ gtk_widget_show (clist);
+
+ roomlist = clist;
+
+ separator = gtk_hseparator_new ();
+ gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0);
+ gtk_widget_show (separator);
+ box2 = gtk_hbox_new (FALSE, 5);
+ gtk_container_border_width (GTK_CONTAINER (box2), 5);
+ gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0);
+ gtk_widget_show (box2);
+
+ button = gtk_button_new_with_label ("Goto");
+ gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
+ GTK_SIGNAL_FUNC(do_goto),
+ NULL);
+ gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
+ gtk_widget_show (button);
+
+ button = gtk_button_new_with_label ("Update");
+ gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
+ GTK_SIGNAL_FUNC(get_room_msgs_func),
+ (void *)1);
+ gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
+ GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
+ gtk_widget_grab_default (button);
+ gtk_widget_show (button);
+
+ parms = newparms();
+ get_all_rooms(&our_context, &list);
+ texts[0] = text[0];
+ texts[1] = text[1];
+ texts[2] = text[2];
+ texts[3] = text[3];
+
+ for (t_list = list; (t_list); t_list = t_list->next)
+ {
+ if ((!t_list->listitem) || (!t_list->listitem[0]))
+ continue;
+/* printf("Working with listitem=%s\n", t_list->listitem); */
+ citadel_parseparms(t_list->listitem, parms);
+/* printf("There are %d args.\n", parms->argc); */
+ strcpy(text[0], parms->argv[0]);
+ get_flagbuf(atoi(parms->argv[1]), flagbuf, sizeof(flagbuf));
+ strncpy(text[3], flagbuf, sizeof(text[3])-1);
+ reset_parms(&parms);
+ strcpy(text[1], "0");
+ strcpy(text[2], "");
+ gtk_clist_append (GTK_CLIST (clist), texts);
+ }
+
+ free_citadel_list(&list);
+ free_citadel_parms(&parms);
+ changed_goto = 0;
+ }
+ if (!GTK_WIDGET_VISIBLE (roomwindow))
+ {
+ gtk_widget_show (roomwindow);
+ return;
+ }
+ else
+ {
+ gtk_widget_destroy (roomwindow);
+ roomlist = NULL;
+ }
+}
+
+
+
+GdkPixmap *make_pixmap_from_filename(char *fn, GtkWidget *image_drawing, int *w, int *h)
+{
+ GdkImlibImage *im;
+ GdkPixmap *pmap;
+
+ im = gdk_imlib_load_image(fn);
+ *w = im->rgb_width;
+ *h = im->rgb_height;
+ gdk_imlib_render(im, *w, *h);
+ pmap = gdk_imlib_move_image(im);
+ gdk_imlib_kill_image(im);
+ return pmap;
+}
+
+void draw_img(GtkWidget *widget, GdkEventConfigure *event)
+{
+ if (!image_drawing)
+ {
+ fprintf(stderr, "No image drawing!\n");
+ return;
+ }
+ if (!image_drawing->window)
+ {
+ fprintf(stderr, "No image drawing window!\n");
+ return;
+ }
+ if (!pixmap)
+ {
+ fprintf(stderr, "No pixmap!\n");
+ return;
+ }
+
+ gdk_window_set_back_pixmap(image_drawing->window, pixmap, FALSE);
+ gdk_window_clear(image_drawing->window);
+ gdk_flush();
+}
+
+void button_win(GtkWidget *widget, GdkEventButton *event)
+{
+ gtk_widget_destroy(aboutwindow);
+}
+
+void switchabout()
+{
+ char fn[256];
+ int w, h;
+
+ if (!aboutwindow)
+ {
+ aboutwindow= gtk_window_new(GTK_WINDOW_TOPLEVEL);
+ gtk_widget_set_name(aboutwindow, "About");
+ gtk_widget_set_uposition(aboutwindow, 400,400);
+
+ gtk_window_set_policy (GTK_WINDOW(aboutwindow), TRUE, TRUE, FALSE);
+
+ gtk_signal_connect (GTK_OBJECT (aboutwindow), "destroy",
+ GTK_SIGNAL_FUNC(gtk_widget_destroyed), &aboutwindow);
+ gtk_window_set_title (GTK_WINDOW (aboutwindow), "About");
+ gtk_container_border_width (GTK_CONTAINER (aboutwindow), 0);
+
+ image_drawing = gtk_drawing_area_new();
+ sprintf(fn, "%s/gcit.gif", Q_PIXMAP_DIR);
+ pixmap = make_pixmap_from_filename(fn, image_drawing, &w, &h);
+ gtk_drawing_area_size(GTK_DRAWING_AREA(image_drawing),w, h);
+ gtk_signal_connect(GTK_OBJECT(image_drawing),"configure_event",GTK_SIGNAL_FUNC(draw_img), NULL);
+ gtk_signal_connect(GTK_OBJECT(image_drawing),"button_press_event",GTK_SIGNAL_FUNC(button_win), NULL);
+ gtk_widget_set_events(image_drawing,GDK_BUTTON_PRESS_MASK);
+ gtk_container_add(GTK_CONTAINER(aboutwindow),image_drawing);
+ gtk_widget_show(image_drawing);
+ }
+ if (!GTK_WIDGET_VISIBLE(aboutwindow))
+ gtk_widget_show(aboutwindow);
+ else
+ gtk_widget_destroy(aboutwindow);
+
+ return;
+
+}
+
+void display_who_window()
+{
+#define ROOM_COLS 4
+
+ static char *titles[ROOM_COLS] =
+ {
+ "User Name",
+ "Room",
+ "Host",
+ "Flags"
+ };
+
+ char text[ROOM_COLS][50];
+ char *texts[ROOM_COLS];
+ GtkWidget *box1;
+ GtkWidget *box2;
+ GtkWidget *clist;
+ GtkWidget *button;
+ GtkWidget *separator;
+ citadel_list *list, *t_list;
+ citadel_parms *parms;
+
+ if (!whowindow)
+ {
+ whowindow = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ gtk_signal_connect (GTK_OBJECT (whowindow), "destroy",
+ GTK_SIGNAL_FUNC(gtk_widget_destroyed),
+ &whowindow);
+ gtk_window_set_title (GTK_WINDOW (whowindow), "Who");
+ gtk_widget_set_uposition(whowindow, 385, 420);
+ gtk_container_border_width (GTK_CONTAINER (whowindow), 0);
+ box1 = gtk_vbox_new (FALSE, 0);
+ gtk_container_add (GTK_CONTAINER (whowindow), box1);
+ gtk_widget_show (box1);
+
+ gtk_widget_set_usize(whowindow, 380, 250);
+ box2 = gtk_vbox_new (FALSE, 5);
+ gtk_container_border_width (GTK_CONTAINER (box2), 5);
+ gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
+ gtk_widget_show (box2);
+ clist = gtk_clist_new_with_titles (ROOM_COLS, titles);
+ gtk_clist_set_row_height (GTK_CLIST (clist), 20);
+ gtk_signal_connect (GTK_OBJECT (clist),
+ "select_row",
+ (GtkSignalFunc) select_who,
+ NULL);
+ gtk_clist_set_column_width (GTK_CLIST (clist), 0, 100);
+ gtk_clist_set_selection_mode (GTK_CLIST (clist), GTK_SELECTION_BROWSE);
+ gtk_clist_set_policy (GTK_CLIST (clist),
+ GTK_POLICY_AUTOMATIC,
+ GTK_POLICY_AUTOMATIC);
+ gtk_container_border_width (GTK_CONTAINER (clist), 5);
+ gtk_box_pack_start (GTK_BOX (box2), clist, TRUE, TRUE, 0);
+
+ gtk_clist_set_column_width (GTK_CLIST (clist), 0, 90);
+ gtk_clist_set_column_width (GTK_CLIST (clist), 1, 90);
+ gtk_clist_set_column_width (GTK_CLIST (clist), 2, 90);
+ gtk_clist_set_column_width (GTK_CLIST (clist), 3, 150);
+
+ gtk_widget_show (clist);
+
+ wholist = clist;
+
+ separator = gtk_hseparator_new ();
+ gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0);
+ gtk_widget_show (separator);
+ box2 = gtk_hbox_new (FALSE, 5);
+ gtk_container_border_width (GTK_CONTAINER (box2), 5);
+ gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0);
+ gtk_widget_show (box2);
+
+ button = gtk_button_new_with_label ("Page");
+ gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
+ GTK_SIGNAL_FUNC(create_pager),
+ NULL);
+ gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
+ GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
+ gtk_widget_grab_default (button);
+ gtk_widget_show (button);
+
+ button = gtk_button_new_with_label ("Update");
+ gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
+ GTK_SIGNAL_FUNC(do_goto),
+ NULL);
+ gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
+ GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
+ gtk_widget_grab_default (button);
+ gtk_widget_show (button);
+
+ texts[0] = text[0];
+ texts[1] = text[1];
+ texts[2] = text[2];
+ texts[3] = text[3];
+
+ parms = newparms();
+
+ get_who_list(&our_context, &list);
+ for (t_list = list; t_list; t_list = t_list->next)
+ {
+ citadel_parseparms(t_list->listitem, parms);
+ strcpy(text[0], parms->argv[1]);
+ citadel_parseparms(t_list->listitem, parms);
+ strcpy(text[1], parms->argv[2]);
+ citadel_parseparms(t_list->listitem, parms);
+ strcpy(text[2], parms->argv[3]);
+ citadel_parseparms(t_list->listitem, parms);
+ if (parms->argv[7])
+ strcpy(text[3], parms->argv[7]);
+ else
+ strcpy(text[3], "N/A");
+ gtk_clist_append (GTK_CLIST (clist), texts);
+ reset_parms(&parms);
+ }
+
+ free_citadel_list(&list);
+ free_citadel_parms(&parms);
+ }
+ if (!GTK_WIDGET_VISIBLE (whowindow))
+ gtk_widget_show (whowindow);
+ else
+ {
+ gtk_widget_destroy (whowindow);
+ wholist = NULL;
+ }
+}
+
+
+void do_post(GtkWidget *widget, GtkWidget *w)
+{
+ static GtkWidget *window = NULL;
+ GtkWidget *box1, *box2, *button, *table, *separator, *hscrollbar;
+ GtkWidget *vscrollbar, *text;
+
+ if (!window)
+ {
+ window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ gtk_widget_set_name (window, "text window");
+ gtk_widget_set_usize (window, 400, 400);
+ gtk_widget_set_uposition(window, 505, 0);
+ gtk_window_set_policy (GTK_WINDOW(window), TRUE, TRUE, FALSE);
+ gtk_signal_connect (GTK_OBJECT (window), "destroy",
+ GTK_SIGNAL_FUNC(gtk_widget_destroyed),
+ &window);
+
+ gtk_window_set_title (GTK_WINDOW (window), "Post a message");
+ gtk_container_border_width (GTK_CONTAINER (window), 0);
+ box1 = gtk_vbox_new (FALSE, 0);
+ gtk_container_add (GTK_CONTAINER (window), box1);
+ gtk_widget_show (box1);
+ box2 = gtk_vbox_new (FALSE, 5);
+ gtk_container_border_width (GTK_CONTAINER (box2), 5);
+ gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
+ gtk_widget_show (box2);
+
+ table = gtk_table_new (2, 2, FALSE);
+ gtk_table_set_row_spacing (GTK_TABLE (table), 0, 2);
+ gtk_table_set_col_spacing (GTK_TABLE (table), 0, 2);
+ gtk_box_pack_start (GTK_BOX (box2), table, TRUE, TRUE, 0);
+ gtk_widget_show (table);
+
+ text = gtk_text_new (NULL, NULL);
+ gtk_text_set_editable (GTK_TEXT (text), TRUE);
+ gtk_table_attach (GTK_TABLE (table), text, 0, 1, 0, 1,
+ GTK_EXPAND | GTK_SHRINK | GTK_FILL,
+ GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0);
+ gtk_text_set_word_wrap(GTK_TEXT(text), TRUE);
+ gtk_widget_show (text);
+
+ posttext = (void *)text;
+
+ hscrollbar = gtk_hscrollbar_new (GTK_TEXT (text)->hadj);
+ gtk_table_attach (GTK_TABLE (table), hscrollbar, 0, 1, 1, 2,
+ GTK_EXPAND | GTK_FILL | GTK_SHRINK, GTK_FILL, 0, 0);
+
+ gtk_widget_show (hscrollbar);
+ vscrollbar = gtk_vscrollbar_new (GTK_TEXT (text)->vadj);
+ gtk_table_attach (GTK_TABLE (table), vscrollbar, 1, 2, 0, 1,
+ GTK_FILL, GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0);
+ gtk_widget_show (vscrollbar);
+ gtk_widget_realize (text);
+
+ separator = gtk_hseparator_new ();
+ gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0);
+ gtk_widget_show (separator);
+
+ box2 = gtk_hbox_new (FALSE, 5);
+ gtk_container_border_width (GTK_CONTAINER (box2), 5);
+ gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0);
+ gtk_widget_show (box2);
+
+
+ button = gtk_button_new_with_label ("Post");
+ gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
+ GTK_SIGNAL_FUNC(do_posting),
+ GTK_OBJECT(text));
+ gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
+ GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
+ gtk_widget_grab_default (button);
+ gtk_widget_show (button);
+
+ button = gtk_button_new_with_label ("Abort");
+ gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
+ GTK_SIGNAL_FUNC(gtk_widget_destroy),
+ GTK_OBJECT (window));
+ gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
+ gtk_widget_show (button);
+
+ }
+
+ if (!GTK_WIDGET_VISIBLE(window))
+ gtk_widget_show(window);
+ else
+ {
+ posttext = NULL;
+ gtk_widget_destroy(window);
+ }
+
+ return;
+
+}
+
+void create_pager(GtkWidget *widget, GtkWidget *wdw)
+{
+ static GtkWidget *window = NULL;
+ GtkWidget *box1;
+ GtkWidget *box2;
+ GtkWidget *button;
+ GtkWidget *label;
+ GtkWidget *separator;
+
+ if (!window)
+ {
+ window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+
+ gtk_signal_connect (GTK_OBJECT (window), "destroy",
+ GTK_SIGNAL_FUNC(gtk_widget_destroyed),
+ &window);
+
+ gtk_window_set_title (GTK_WINDOW (window), "Pager");
+ gtk_container_border_width (GTK_CONTAINER (window), 0);
+
+
+ box1 = gtk_vbox_new (FALSE, 0);
+ gtk_container_add (GTK_CONTAINER (window), box1);
+ gtk_widget_show (box1);
+
+
+ box2 = gtk_vbox_new (FALSE, 5);
+ gtk_container_border_width (GTK_CONTAINER (box2), 5);
+ gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
+ gtk_widget_show (box2);
+
+ label = gtk_label_new("Page who:");
+ gtk_box_pack_start(GTK_BOX(box2), label, TRUE, TRUE, 0);
+ gtk_widget_show(label);
+
+ page_user = gtk_entry_new ();
+ if (our_context.selected_who[0])
+ gtk_entry_set_text (GTK_ENTRY (page_user), our_context.selected_who);
+ else
+ gtk_entry_set_text (GTK_ENTRY (page_user), "");
+ gtk_editable_select_region (GTK_EDITABLE (page_user), 0, -1);
+ gtk_box_pack_start (GTK_BOX (box2), page_user, TRUE, TRUE, 0);
+ gtk_widget_show (page_user);
+
+ label = gtk_label_new("Message:");
+ gtk_box_pack_start(GTK_BOX(box2), label, TRUE, TRUE, 0);
+ gtk_widget_show(label);
+
+ page_msg = gtk_entry_new ();
+ gtk_entry_set_text (GTK_ENTRY (page_msg), "");
+ gtk_editable_select_region (GTK_EDITABLE (page_msg), 0, -1);
+ gtk_box_pack_start (GTK_BOX (box2), page_msg, TRUE, TRUE, 0);
+ gtk_widget_show (page_msg);
+
+ box2 = gtk_hbox_new (FALSE, 5);
+ gtk_container_border_width (GTK_CONTAINER (box2), 5);
+ gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0);
+ gtk_widget_show (box2);
+
+ button = gtk_button_new_with_label ("Send");
+ gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
+ GTK_SIGNAL_FUNC(do_send_page),
+ NULL);
+
+ separator = gtk_hseparator_new ();
+ gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0);
+ gtk_widget_show (separator);
+
+ gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
+ GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
+ gtk_widget_grab_default (button);
+ gtk_widget_show (button);
+
+ button = gtk_button_new_with_label ("Close");
+ gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
+ GTK_SIGNAL_FUNC(gtk_widget_destroy),
+ GTK_OBJECT (window));
+ gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
+ gtk_widget_show (button);
+
+ pager = window;
+ }
+
+ if (!GTK_WIDGET_VISIBLE (window))
+ gtk_widget_show (window);
+ else
+ {
+ gtk_widget_destroy (window);
+ pager = NULL;
+ }
+
+}
+
+int create_display_window()
+{
+ static GtkWidget *window = NULL;
+ GtkWidget *box1, *box2, *button, *table, *separator, *hscrollbar;
+ GtkWidget *vscrollbar, *text;
+
+ if (!window)
+ {
+ window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ gtk_widget_set_name (window, "text window");
+ gtk_widget_set_usize (window, 500, 400);
+ gtk_widget_set_uposition(window, 0, 0);
+ gtk_window_set_policy (GTK_WINDOW(window), TRUE, TRUE, FALSE);
+ gtk_signal_connect (GTK_OBJECT (window), "destroy",
+ GTK_SIGNAL_FUNC(gtk_widget_destroyed),
+ &window);
+
+ gtk_window_set_title (GTK_WINDOW (window), CITADEL_VERSION);
+ gtk_container_border_width (GTK_CONTAINER (window), 0);
+ box1 = gtk_vbox_new (FALSE, 0);
+ gtk_container_add (GTK_CONTAINER (window), box1);
+ gtk_widget_show (box1);
+ box2 = gtk_vbox_new (FALSE, 5);
+ gtk_container_border_width (GTK_CONTAINER (box2), 5);
+ gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
+ gtk_widget_show (box2);
+
+ table = gtk_table_new (2, 2, FALSE);
+ gtk_table_set_row_spacing (GTK_TABLE (table), 0, 2);
+ gtk_table_set_col_spacing (GTK_TABLE (table), 0, 2);
+ gtk_box_pack_start (GTK_BOX (box2), table, TRUE, TRUE, 0);
+ gtk_widget_show (table);
+
+ text = gtk_text_new (NULL, NULL);
+ gtk_text_set_editable (GTK_TEXT (text), FALSE);
+ gtk_table_attach (GTK_TABLE (table), text, 0, 1, 0, 1,
+ GTK_EXPAND | GTK_SHRINK | GTK_FILL,
+ GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0);
+ gtk_widget_show (text);
+
+ maintext = (void *)text;
+
+ hscrollbar = gtk_hscrollbar_new (GTK_TEXT (text)->hadj);
+ gtk_table_attach (GTK_TABLE (table), hscrollbar, 0, 1, 1, 2,
+ GTK_EXPAND | GTK_FILL | GTK_SHRINK, GTK_FILL, 0, 0);
+
+ gtk_widget_show (hscrollbar);
+ vscrollbar = gtk_vscrollbar_new (GTK_TEXT (text)->vadj);
+ gtk_table_attach (GTK_TABLE (table), vscrollbar, 1, 2, 0, 1,
+ GTK_FILL, GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0);
+ gtk_widget_show (vscrollbar);
+ gtk_widget_realize (text);
+
+ separator = gtk_hseparator_new ();
+ gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0);
+ gtk_widget_show (separator);
+
+ box2 = gtk_hbox_new (FALSE, 5);
+ gtk_container_border_width (GTK_CONTAINER (box2), 5);
+ gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0);
+ gtk_widget_show (box2);
+
+ button = gtk_button_new_with_label ("Connect");
+ gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
+ GTK_SIGNAL_FUNC(get_user_info),
+ GTK_OBJECT (text));
+ gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
+ gtk_widget_show (button);
+
+ button = gtk_button_new_with_label ("Next");
+ gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
+ GTK_SIGNAL_FUNC(do_nextmsg),
+ GTK_OBJECT (window));
+ gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
+ gtk_widget_show (button);
+
+ button = gtk_button_new_with_label ("Post");
+ gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
+ GTK_SIGNAL_FUNC(do_post),
+ GTK_OBJECT (window));
+ gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
+ gtk_widget_show (button);
+
+ button = gtk_button_new_with_label ("Close");
+ gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
+ GTK_SIGNAL_FUNC(do_close),
+ NULL);
+ gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
+ gtk_widget_show (button);
+
+ button = gtk_button_new_with_label ("Quit");
+ gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
+ GTK_SIGNAL_FUNC(client_quit),
+ GTK_OBJECT (window));
+ gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
+ GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
+ gtk_widget_grab_default (button);
+ gtk_widget_show (button);
+ }
+
+ if (!GTK_WIDGET_VISIBLE(window))
+ {
+ gtk_widget_show(window);
+ mainwindow = window;
+ }
+ else
+ {
+ gtk_widget_destroy(window);
+ maintext = NULL;
+ mainwindow = NULL;
+ }
+
+ return(1);
+}
--- /dev/null
+int get_user_info(GtkWidget *w1, GtkWidget *wt);
+void select_room(GtkWidget *widget, int row, int col, GdkEventButton *bevent);
+void select_who(GtkWidget *widget, int row, int col, GdkEventButton *bevent);
+void display_room_window();
+void switchabout();
+void display_who_window();
+void do_post(GtkWidget *widget, GtkWidget *w);
+void create_pager(GtkWidget *widget, GtkWidget *wdw);
+int create_display_window();
--- /dev/null
+# Citadel client makefile
+
+CC = gcc
+LIB_OBJS = tcp_trans.o citadel_util.o citadel_api.o client_api.o
+TARGET = ../libcli_cit.so
+
+all: $(TARGET)
+
+clean:
+ rm -f $(TARGET) *.o *~
+
+install: $(TARGET)
+ cp $(TARGET) /usr/lib/
+ ldconfig
+
+$(TARGET): $(LIB_OBJS)
+ $(CC) -shared -o $(TARGET) $(LIB_OBJS)
+
+tcp_trans.o: tcp_trans.c client_api.h transport.h
+
+citadel_util.o: transport.h client_api.h citadel_util.h citadel_util.c
+
+citadel_api.o: transport.h client_api.h citadel_api.h citadel_util.h citadel_api.c
+
+client_api.o: client_api.c client_api.h transport.h citadel_api.h citadel_util.h
--- /dev/null
+/*
+
+Citadel Api
+Brian Costello
+btx@calyx.net
+
+For description of any of these commands, read session.txt, distributed with
+the Citadel/UX source code.
+
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include "client_api.h"
+#include "transport.h"
+#include "citadel_util.h"
+#include "citadel_api.h"
+
+int failnum(int i)
+{
+ if (i == OK)
+ return(i);
+ if (i>0)
+ return(-1 * i);
+ else
+ return(i);
+}
+
+int send_cmd_parms_1(int sd, char *cmd, char *parm, citadel_parms *parms)
+{
+ int ret;
+
+ if (parm)
+ {
+ parms->argc = 1;
+ parms->argv[0] = parm;
+ }
+
+#ifdef DEBUG
+ printf("Sending parms\n");
+#endif
+ ret = citadel_sendparms(sd, parms, cmd, 1);
+ if (ret < 0)
+ return ret;
+
+ return(parms->return_code);
+}
+
+int send_single_cmd(int sd, char *cmd)
+{
+ int ret;
+ citadel_parms *parms;
+
+ if ((parms = newparms()) == NULL)
+ return -1;
+
+ ret = send_cmd_parms_1(sd, cmd, NULL, parms);
+ free_citadel_parms(&parms);
+
+ return ret;
+}
+
+int send_single_cmd_parm(int sd, char *cmd, char *parm)
+{
+ int ret;
+ citadel_parms *parms;
+
+ if ((parms = newparms()) == NULL)
+ return -1;
+
+ ret = send_cmd_parms_1(sd, cmd, parm, parms);
+ free_citadel_parms(&parms);
+
+ return ret;
+}
+
+int init_session(int sd)
+{
+ int ret;
+ citadel_parms parms;
+
+ ret = citadel_recvparms(sd, &parms);
+ if (ret < 0)
+ return(ret);
+
+ return(parms.return_code);
+}
+
+int cmd_noop(int sd)
+{
+ return(send_single_cmd(sd, "NOOP"));
+}
+
+int cmd_quit(int sd)
+{
+ return(send_single_cmd(sd, "QUIT"));
+}
+
+int cmd_echo(int sd, char *echostr)
+{
+ return(send_single_cmd_parm(sd, "ECHO", echostr));
+}
+
+int cmd_lout(int sd)
+{
+ return(send_single_cmd(sd, "LOUT"));
+}
+
+int cmd_user(int sd, char *username)
+{
+ int ret;
+
+ ret = send_single_cmd_parm(sd, "USER", username);
+ if (ret != MORE_DATA)
+ return(failnum(ret));
+ else
+ return 0;
+}
+
+int cmd_pass(int sd, char *password, citadel_parms *parms)
+{
+ int ret;
+
+ if ((ret = send_cmd_parms_1(sd, "PASS", password, parms)) != OK)
+ return(failnum(ret));
+ else
+ return 0;
+}
+
+int cmd_setp(int sd, char *password)
+{
+ int ret;
+
+ if ((ret = send_single_cmd_parm(sd, "SETP", password)) != OK)
+ return(failnum(ret));
+ else
+ return 0;
+}
+
+
+int cmd_last_room(int sd, char *cmd, citadel_list **list, int floorno)
+{
+ int ret;
+
+ ret = send_single_cmd(sd, cmd);
+ if (ret != LISTING_FOLLOWS)
+ {
+ return(failnum(ret));
+ }
+
+#ifdef DEBUG
+ printf("Receiving listing...\n");
+#endif
+ *list = NULL;
+ return(failnum(citadel_receive_listing(sd, list)));
+}
+
+int cmd_lkrn(int sd, citadel_list **list, int floorno)
+{
+ return(cmd_last_room(sd, "LKRN", list, floorno));
+}
+int cmd_lkro(int sd, citadel_list **list, int floorno)
+{
+ return(cmd_last_room(sd, "LKRO", list, floorno));
+}
+int cmd_lzrm(int sd, citadel_list **list, int floorno)
+{
+ return(cmd_last_room(sd, "LZRM", list, floorno));
+}
+int cmd_lkra(int sd, citadel_list **list, int floorno)
+{
+ return(cmd_last_room(sd, "LKRA", list, floorno));
+}
+int cmd_lkms(int sd, citadel_list **list, int floorno)
+{
+ return(cmd_last_room(sd, "LKMS", list, floorno));
+}
+
+int cmd_getu(int sd, citadel_parms *parms)
+{
+ int ret;
+
+ if ((ret = send_cmd_parms_1(sd, "GETU", NULL, parms)) != OK)
+ return(failnum(ret));
+ else
+ return 0;
+}
+
+int cmd_setu(int sd, int width, int height, int option_bits)
+{
+ int ret;
+ char strbuf[256];
+
+ snprintf(strbuf, sizeof(strbuf)-1, "SETU %d|%d|%d", width, height, option_bits);
+ strbuf[sizeof(strbuf)-1] = '\0';
+
+ if ((ret=send_single_cmd(sd, strbuf)) != OK)
+ return(failnum(ret));
+ else
+ return 0;
+}
+
+int cmd_goto(int sd, char *roomname, char *password, citadel_parms *parms)
+{
+ int ret;
+ char strbuf[256];
+
+ if (password)
+ snprintf(strbuf, sizeof(strbuf)-1, "GOTO %s|%s", roomname, password);
+ else
+ snprintf(strbuf, sizeof(strbuf)-1, "GOTO %s|", roomname);
+
+ strbuf[sizeof(strbuf)-1] = '\0';
+
+ if ((ret = send_cmd_parms_1(sd, strbuf, NULL, parms)) != OK)
+ return(failnum(ret));
+ else
+ return 0;
+}
+
+int cmd_msgs(int sd, citadel_list **list, char *cmd, int number)
+{
+ int ret;
+ char strbuf[CITADEL_STR_SIZE];
+
+ if (number>0)
+ snprintf(strbuf, CITADEL_STR_SIZE-1, "MSGS %s|%d", cmd, number);
+ else
+ snprintf(strbuf, CITADEL_STR_SIZE-1, "MSGS %s", cmd);
+
+ strbuf[CITADEL_STR_SIZE-1] = '\0';
+
+ if ((ret = send_single_cmd(sd, strbuf)) != LISTING_FOLLOWS)
+ return(failnum(ret));
+
+ *list = NULL;
+ return(failnum(citadel_receive_listing(sd, list)));
+}
+
+
+int cmd_msg0(int sd, citadel_list **list, int msgnum, int header_only)
+{
+ int ret;
+ char strbuf[CITADEL_STR_SIZE];
+
+ snprintf(strbuf, CITADEL_STR_SIZE-1, "MSG0 %d|%d", msgnum, header_only);
+
+ strbuf[CITADEL_STR_SIZE-1] = '\0';
+ if ((ret = send_single_cmd(sd, strbuf)) != LISTING_FOLLOWS)
+ return(failnum(ret));
+
+ *list = NULL;
+ return(failnum(citadel_receive_listing(sd, list)));
+}
+
+int cmd_whok(int sd, citadel_list **list)
+{
+ int ret;
+
+ ret = send_single_cmd(sd, "WHOK");
+ if (ret != LISTING_FOLLOWS)
+ {
+ return(failnum(ret));
+ }
+
+ *list = NULL;
+ return(failnum(citadel_receive_listing(sd, list)));
+}
+
+int cmd_info(int sd, citadel_list **list)
+{
+ int ret;
+
+ ret = send_single_cmd(sd, "INFO");
+ if (ret != LISTING_FOLLOWS)
+ {
+ return(failnum(ret));
+ }
+
+ *list = NULL;
+ return(failnum(citadel_receive_listing(sd, list)));
+}
+
+int cmd_rdir(int sd, citadel_parms *parms, citadel_list **list)
+{
+ int ret;
+
+ ret = send_cmd_parms_1(sd, "RDIR", NULL, parms);
+ if (ret != LISTING_FOLLOWS)
+ {
+ return(failnum(ret));
+ }
+ return(failnum(citadel_receive_listing(sd, list)));
+}
+
+int cmd_slrp(int sd, int msgnum, int highest, citadel_parms *parms)
+{
+ int ret;
+ char strbuf[32];
+
+ if (!highest)
+ snprintf(strbuf, CITADEL_STR_SIZE-1, "%d", msgnum);
+ else
+ strcpy(strbuf, "HIGHEST");
+
+ if ((ret = send_cmd_parms_1(sd, "SLRP", strbuf, parms)) != OK)
+ return(failnum(ret));
+ else
+ return(1);
+}
+
+int cmd_invt(int sd, char *username)
+{
+ int ret;
+ char strbuf[CITADEL_STR_SIZE];
+
+ snprintf(strbuf, CITADEL_STR_SIZE-1, "INVT %s", username);
+
+ strbuf[CITADEL_STR_SIZE-1] = '\0';
+ if ((ret = send_single_cmd(sd, strbuf)) != OK)
+ return(failnum(ret));
+
+ return(1);
+}
+
+int cmd_kick(int sd, char *username)
+{
+ int ret;
+ char strbuf[CITADEL_STR_SIZE];
+
+ snprintf(strbuf, CITADEL_STR_SIZE-1, "KICK %s", username);
+
+ strbuf[CITADEL_STR_SIZE-1] = '\0';
+ if ((ret = send_single_cmd(sd, strbuf)) != OK)
+ return(failnum(ret));
+
+ return(1);
+}
+
+int cmd_getr(int sd, citadel_parms *parms)
+{
+ int ret;
+
+ if ((ret = send_cmd_parms_1(sd, "GETR", NULL, parms)) != OK)
+ return(failnum(ret));
+ else
+ return(1);
+}
+
+int cmd_setr(int sd, char *roomname, char *password, char *directory, int flags, int bump, int floorno)
+{
+ int ret;
+ char strbuf[CITADEL_STR_SIZE];
+
+ snprintf(strbuf, CITADEL_STR_SIZE-1, "SETR %s|%s|%s|%d|%d|%d", roomname, (password) ? password : "",
+ (directory) ? directory : "", flags, bump, floorno);
+
+ strbuf[CITADEL_STR_SIZE-1] = '\0';
+ if ((ret = send_single_cmd(sd, strbuf)) != OK)
+ return(failnum(ret));
+ return(1);
+}
+
+int cmd_geta(int sd, citadel_parms *parms)
+{
+ int ret;
+ if ((ret = send_cmd_parms_1(sd, "GETA", NULL, parms)) != OK)
+ return(failnum(ret));
+ else
+ return(1);
+}
+
+int cmd_seta(int sd, char *newaide)
+{
+ int ret;
+
+ if ((ret = send_single_cmd_parm(sd, "SETA", newaide)) != OK)
+ return(failnum(ret));
+ else
+ return(1);
+}
+
+int cmd_ent0(int sd, int postflag, char *recipient, int anonymous, int format, char *postname, citadel_parms *parms, char *local_filename)
+{
+ int ret;
+ char strbuf[CITADEL_STR_SIZE];
+
+ snprintf(strbuf, CITADEL_STR_SIZE-1, "ENT0 %d|%s|%d|%d|%s|", postflag, (recipient) ? recipient : "",
+ anonymous, format, (postname) ? postname : "");
+
+ strbuf[CITADEL_STR_SIZE-1] = '\0';
+ if ((ret = send_cmd_parms_1(sd, strbuf, NULL, parms)) == OK)
+ return(1);
+
+ if (ret == SEND_LISTING)
+ ret = citadel_send_listing_file(sd,local_filename);
+
+ return(ret);
+}
+
+int cmd_rinf(int sd, citadel_list **list)
+{
+ int ret;
+
+ ret = send_single_cmd(sd, "RINF");
+ if (ret != LISTING_FOLLOWS)
+ {
+ return(failnum(ret));
+ }
+ return(failnum(citadel_receive_listing(sd, list)));
+}
+
+
+int cmd_mesg(int sd, char *msgname, citadel_list **list)
+{
+ int ret;
+
+ ret = send_single_cmd_parm(sd, "MESG", msgname);
+ if (ret != LISTING_FOLLOWS)
+ {
+ return(failnum(ret));
+ }
+
+ *list = NULL;
+ return(failnum(citadel_receive_listing(sd, list)));
+}
+
+int cmd_rwho(int sd, citadel_list **list)
+{
+ int ret;
+
+ ret = send_single_cmd(sd, "RWHO");
+ if (ret != LISTING_FOLLOWS)
+ {
+ return(failnum(ret));
+ }
+
+ *list = NULL;
+ return(failnum(citadel_receive_listing(sd, list)));
+}
+
+int cmd_iden(int sd, int devid, int cliid, int verno, char *clientstr, char *hostname)
+{
+ int ret;
+ char strbuf[CITADEL_STR_SIZE];
+
+ snprintf(strbuf, CITADEL_STR_SIZE-1, "IDEN %d|%d|%d|%s|%s|", devid, cliid, verno,
+ clientstr, hostname);
+
+ strbuf[CITADEL_STR_SIZE-1] = '\0';
+ if ((ret = send_single_cmd(sd, strbuf)) != OK)
+ return(failnum(ret));
+
+ return(1);
+}
+
+
+int cmd_sexp(int sd, char *username, char *msg)
+{
+ int ret;
+ char strbuf[256];
+
+ snprintf(strbuf, sizeof(strbuf)-1, "SEXP %s|%s", username, msg);
+ strbuf[sizeof(strbuf)-1] = '\0';
+
+ if ((ret = send_single_cmd(sd, strbuf)) != OK)
+ {
+ fprintf(stderr, "Command %s failed in cmd_sexp\n", strbuf);
+ return(failnum(ret));
+ }
+
+ return 1;
+}
+
+int cmd_pexp(int sd, citadel_list **list)
+{
+ int ret;
+
+ if ((ret = send_single_cmd(sd, "PEXP")) != LISTING_FOLLOWS)
+ {
+#ifdef DEBUG
+ fprintf(stderr, "No express message waiting! Returning %d\n", failnum(ret));
+#endif
+ return(failnum(ret));
+ }
+
+ *list = NULL;
+ return(failnum(citadel_receive_listing(sd, list)));
+}
+
+int cmd_hchg(int sd, char *hostname)
+{
+ int ret;
+
+ if ((ret = send_single_cmd_parm(sd, "HCHG", hostname)) != OK)
+ {
+ fprintf(stderr, "cmd_hchg was unable to send the cmd HCHG %s.\n",hostname);
+ return(failnum(ret));
+ }
+
+ return 1;
+}
+
+int cmd_rchg(int sd, char *roomname)
+{
+ int ret;
+
+ if ((ret = send_single_cmd_parm(sd, "RCHG", roomname)) != OK)
+ {
+ fprintf(stderr, "cmd_rchg was unable to send the cmd RCHG %s.\n",roomname);
+ return(failnum(ret));
+ }
+
+ return 1;
+}
+int cmd_uchg(int sd, char *username)
+{
+ int ret;
+
+ if ((ret = send_single_cmd_parm(sd, "UCHG", username)) != OK)
+ {
+ fprintf(stderr, "cmd_uchg was unable to send the cmd UCHG %s.\n",username);
+ return(failnum(ret));
+ }
+
+ return 1;
+}
--- /dev/null
+/*
+
+Creeping citadel api of death
+Brian Costello
+btx@calyx.net
+
+*/
+
+int init_session(int);
+
+int cmd_noop(int sd);
+int cmd_echo(int sd, char *echostr);
+int cmd_quit(int sd);
+int cmd_lout(int sd);
+
+int cmd_user(int sd, char *username);
+int cmd_pass(int sd, char *password, citadel_parms *parms);
+int cmd_setp(int sd, char *password);
+
+/* floorno < 0 = all floors listed */
+int cmd_lkrn(int sd, citadel_list **list, int floorno);
+int cmd_lkro(int sd, citadel_list **list, int floorno);
+int cmd_lzrm(int sd, citadel_list **list, int floorno);
+int cmd_lkra(int sd, citadel_list **list, int floorno);
+int cmd_lrms(int sd, citadel_list **list, int floorno);
+
+int cmd_getu(int sd, citadel_parms *parms);
+int cmd_setu(int sd, int width, int height, int option_bits);
+int cmd_goto(int sd, char *roomname, char *password, citadel_parms *parms);
+int cmd_msgs(int sd, citadel_list **list, char *cmd, int number);
+int cmd_msg0(int sd, citadel_list **list, int msgnum, int header_only);
+
+int cmd_whok(int sd, citadel_list **list); /* aide only */
+int cmd_info(int sd, citadel_list **list);
+int cmd_rdir(int sd, citadel_parms *parms, citadel_list **list);
+int cmd_slrp(int sd, int msgnum, int highest, citadel_parms *parms);
+
+int cmd_invt(int sd, char *username); /* aide only */
+int cmd_kick(int sd, char *username);
+int cmd_getr(int sd, citadel_parms *parms);
+int cmd_setr(int sd, char *roomname, char *password, char *directory, int flags, int bump, int floorno);
+
+int cmd_geta(int sd, citadel_parms *parms);
+int cmd_seta(int sd, char *newaide);
+int cmd_ent0(int sd, int postflag, char *recipient, int anonymous, int format, char *postname, citadel_parms *parms, char *local_filename);
+int cmd_rinf(int sd, citadel_list **list);
+
+int cmd_mesg(int sd, char *msgname, citadel_list **list);
+int cmd_rwho(int sd, citadel_list **list);
+
+/* Cit 4.01 */
+int cmd_iden(int sd, int, int, int, char *, char *);
+int cmd_sexp(int sd, char *username, char *msg);
+int cmd_pexp(int sd, citadel_list **list);
+
+/* Cit 5.02 */
+
+int cmd_hchg(int sd, char *hostname);
+int cmd_rchg(int sd, char *roomname);
+int cmd_uchg(int sd, char *username);
+
+
+/* Unimplemented */
+
+int cmd_newu(int sd, char *username);
+int cmd_dele(int sd, int msgno);
+int cmd_move(int sd, int msgno, char *target_room);
+int cmd_kill(int sd, int act_delete, char *nextroom);
+int cmd_cre8(int sd, int flag, char *newname, int access, char *password, int floorno);
+int cmd_forg(int sd, char *nextroom);
+int cmd_gnur(int sd, citadel_list **list);
+int cmd_greg(int sd, citadel_list **list);
+int cmd_vali(int sd, char *username, int access_level);
+int cmd_einf(int sd, citadel_list **list);
+int cmd_list(int sd, citadel_list **list);
+int cmd_regi(int sd, citadel_list *list);
+int cmd_chek(int sd, citadel_parms *parms);
+int cmd_delf(int sd, char *filename);
+int cmd_movf(int sd, char *filename, char *target_room);
+int cmd_netf(int sd, char *filename, char *node_name);
+int cmd_open(int sd, char *filename, citadel_parms *parms);
+int cmd_clos(int sd);
+int cmd_read(int sd, char *buf, int start_pos,int num_bytes);
+int cmd_uopn(int sd, char *filename, citadel_parms *parms);
+int cmd_ucls(int sd, int save);
+int cmd_writ(int sd, char *buf, int nbytes);
+int cmd_quser(int sd, char *username, citadel_parms *parms);
+int cmd_oimg(int sd, char *filename, char *parm);
+
+/* Cit/UX 4.01 cmds */
+
+int cmd_netp(int sd, char *nodename, char *password);
+int cmd_nuop(int sd);
+int cmd_ndop(int sd, citadel_parms *parms);
+int cmd_lflr(int sd, citadel_list **list);
+int cmd_cflr(int sd, char *floorname, int makefloor);
+int cmd_kflr(int sd, int floornum, int killfloor);
+int cmd_eflr(int sd, int floornum, char *newname);
+int cmd_iden(int sd, int, int, int, char *, char *);
+int cmd_ipgm(int sd, char *password);
+int cmd_chat(int sd);
+
+/* Cit/UX 4.10 */
+
+int cmd_ebio(int sd, citadel_list *list);
+int cmd_rbio(int sd, char *username, citadel_list **list);
+
+/* Cit/UX 4.11 */
+
+int cmd_stel(int sd, int enter);
+int cmd_lbio(int sd, citadel_list *list);
+int cmd_msg2(int sd, citadel_list *list);
+
+/* Cit/UX 5.00 */
+
+int cmd_term(int sd, int taskno);
+int cmd_down(int sd);
+int cmd_scdn(int sd, int setflag);
+int cmd_emsg(int sd, char *filename, char *local_filename);
+int cmd_uimg(int sd, int upload, char *filename, char *local_filename);
+
+/* Cit/UX 5.02 */
+
+int cmd_time(int sd, long *time);
+int cmd_agup(int sd, citadel_parms *parms);
+int cmd_asup(int sd, citadel_parms *parms);
+
+/* Not implemented */
+/* int cmd_msg3() */
+/* int cmd_ent3() */
+/* int cmd_nset(int sd, */
--- /dev/null
+/*
+
+citadel_util.c
+btx@calyx.net
+
+These routines deal with the two citadel structures, parms and lists.
+
+*/
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/types.h>
+#include "client_api.h"
+#include "transport.h"
+#include "citadel_util.h"
+
+int get_num_args(char *line)
+{
+ int nargs;
+ char *cptr;
+
+ if (strlen(line) < 4)
+ return 0;
+
+ nargs = 1;
+
+ for (cptr = &line[4]; ((*cptr) && (*cptr != '\n')); cptr++)
+ {
+ if ((*cptr) == '|')
+ nargs++;
+ }
+
+ return nargs;
+}
+
+int get_arg_no(int argno, char *line, char *buf)
+{
+ int i,j;
+ int an=1;
+ for (i=0; ((i<strlen(line)) && (an <= argno)); i++)
+ {
+ if (line[i] == '|')
+ an++;
+ }
+
+ if (i==strlen(line))
+ {
+ fprintf(stderr, "ERror- trying to read arg # %d from %s\n", argno, line);
+ return -1;
+ }
+ for (j=0; ((line[i] != '|') && (line[i] != '\0')); j++)
+ {
+ buf[j] = line[i++];
+ }
+
+ buf[j] = '\0';
+ return OK;
+}
+
+int citadel_parseparms(char *line, citadel_parms *parms)
+{
+ int i;
+ char arg[256];
+ char nbuf[4];
+ char *eptr;
+
+ if (!parms)
+ {
+ fprintf(stderr, "Error: parms in citadel_parseparms is NULL!\n");
+ return -1;
+ }
+
+ if (!line)
+ {
+ fprintf(stderr, "Error: line in citadel_parseparms is NULL!\n");
+ return -1;
+ }
+
+ parms->line = (char *)strdup(line);
+ parms->argc = get_num_args(line);
+#ifdef DEBUG
+ printf("There are %d args in the line %s.\n", parms->argc, line);
+#endif
+
+ nbuf[3] = '\0';
+ nbuf[0] = line[0];
+ nbuf[1] = line[1];
+ nbuf[2] = line[2];
+
+ parms->return_code = strtol(nbuf, &eptr, 10);
+
+ for (i=0; i<parms->argc; i++)
+ {
+ if (eptr[0])
+ get_arg_no(i, line, arg);
+ else
+ get_arg_no(i, &line[4], arg);
+#ifdef DEBUG
+ printf("Got arg #%d - %s\n", i, arg);
+#endif
+ parms->argv[i] = (char *) strdup(arg);
+ }
+
+ return 0;
+}
+
+int free_citadel_parms(citadel_parms **parms)
+{
+ int i;
+
+ if ((!parms) || (!*parms))
+ {
+ fprintf(stderr, "Error: parms in free_citadel_parms is NULL!\n");
+ return -1;
+ }
+
+#ifdef DEBUG
+ printf("free_citadel_parms: argc=%d\n", (*parms)->argc);
+#endif
+
+ if ((*parms)->line)
+ free((*parms)->line);
+
+ for (i=0; i<(*parms)->argc; i++)
+ {
+ if ((*parms)->argv[i])
+ free ((*parms)->argv[i]);
+ }
+
+#ifdef DEBUG
+ printf("Freeing structure\n");
+#endif
+ free(*parms);
+ *parms = NULL;
+ return(0);
+}
+
+citadel_parms *newparms()
+{
+ citadel_parms *parms;
+
+ if ((parms = (citadel_parms *)malloc(sizeof(citadel_parms))) == NULL)
+ {
+ fprintf(stderr, "Malloc in newparms() failed\n");
+ exit(1);
+ }
+
+ bzero(parms, sizeof(citadel_parms));
+ parms->argc = 0;
+
+ return(parms);
+
+}
+
+int reset_parms(citadel_parms **parms)
+{
+ if (!parms)
+ return 0;
+
+ free_citadel_parms(parms);
+ if (!(*parms = newparms()))
+ {
+ fprintf(stderr, "Error: newparms() failed in reset_parms()!\n");
+ exit(1); /* fatal */
+ }
+#ifdef DEBUG
+ fprintf(stderr, "Parms reset.\n");
+#endif
+ return (*parms != NULL);
+}
+
+int get_line(int fd, char *line, int maxline)
+{
+ int cl = 0;
+ int n;
+
+ if (!line)
+ {
+ fprintf(stderr, "Error: line in citadel_recv is NULL!\n");
+ return -1;
+ }
+
+#ifdef DEBUG
+ fprintf(stderr, "Reading in get_line...\n");
+#endif
+ line[0] = '\0';
+
+ do
+ {
+ n = read(fd, &line[cl], 1);
+
+ if (n)
+ {
+ if (line[cl] == '\n')
+ line[cl] = '\0';
+
+ cl ++;
+ }
+ } while ((n) && (cl < maxline) && (line[cl-1]));
+
+ if (cl == maxline)
+ line[maxline-1] = '\0';
+
+ if (!n)
+ line[cl] = '\0';
+
+#ifdef DEBUG
+ printf("Received: %s\n", line);
+#endif
+ return(cl);
+}
+
+int citadel_recvparms(int sd, citadel_parms *parms)
+{
+ char strbuf[CITADEL_STR_SIZE];
+ int ret;
+
+ ret = citadel_recv_line(sd, strbuf, CITADEL_STR_SIZE);
+ if (ret < 0)
+ return(ret);
+
+ if ((ret=citadel_parseparms(strbuf, parms)) < 0)
+ {
+ fprintf(stderr, "Error: citadel_parseparms failed in citadel_recvparms\n");
+ }
+
+ return(ret);
+}
+
+int citadel_send_line(int sd, char *line)
+{
+ char strbuf[CITADEL_STR_SIZE+1];
+
+ strbuf[CITADEL_STR_SIZE] = '\0';
+ snprintf(strbuf, CITADEL_STR_SIZE, "%s\n", line);
+ return(citadel_send(sd, strbuf, strlen(strbuf)));
+}
+
+int citadel_sendparms(int sd, citadel_parms *parms, char *cmd, int expect)
+{
+ char strbuf[CITADEL_STR_SIZE];
+ int nb=0;
+ int i;
+ int ret;
+
+ strbuf[0] = '\0';
+
+ strcpy(strbuf, cmd);
+
+ if (parms)
+ {
+ strcat(strbuf, " ");
+ nb += strlen(strbuf)+1;
+
+ for (i=0; i<parms->argc; i++)
+ {
+ if ((nb + strlen(parms->argv[i]) + 2) > CITADEL_STR_SIZE)
+ break;
+
+ if (i > 0)
+ {
+ strcat(strbuf, "|");
+ nb += 1;
+ }
+
+ strcat(strbuf, parms->argv[i]);
+ nb += strlen(parms->argv[i]);
+ }
+ }
+ strcat(strbuf, "\n");
+ nb += 1;
+
+ ret = citadel_send(sd, strbuf, nb);
+ if ((ret < 0) || (!expect))
+ return(ret);
+
+ ret = citadel_recvparms(sd, parms);
+ return(ret);
+}
+
+int add_citadel_list(citadel_list **first_list, char *item)
+{
+ citadel_list *newlist, *t_list;
+
+#ifdef DEBUG
+ fprintf(stderr, "Adding %s to the citadel list\n", item);
+#endif
+
+ if ((newlist = (citadel_list *)malloc(sizeof(citadel_list))) == NULL)
+ {
+ fprintf(stderr, "Malloc failed in add_citadel_list!\n");
+ exit(1);
+ }
+
+ newlist->next = NULL;
+ newlist->listitem = (char *)strdup(item);
+
+ if (!first_list)
+ {
+ fprintf(stderr, "Firstlist is NULL in add_citadel_list!\n");
+ return -1;
+ }
+
+ if (!(*first_list))
+ {
+ *first_list = newlist;
+ return 1;
+ }
+
+ for (t_list = *first_list; t_list->next; t_list=t_list->next)
+ ;
+
+ t_list->next = newlist;
+
+ return(1);
+}
+
+int free_citadel_list(citadel_list **first_list)
+{
+ citadel_list *t_list, *n_list;
+
+ if (!first_list)
+ {
+ fprintf(stderr, "First_list is NULL in add_citadel_list!\n");
+ return -1;
+ }
+
+ for (t_list = *first_list; t_list; t_list = n_list)
+ {
+ n_list = t_list->next;
+
+ if (t_list->listitem)
+ free(t_list->listitem);
+
+ free(t_list);
+ }
+
+ *first_list = NULL;
+
+ return(1);
+}
+
+/*
+ * citadel_receive_listing() - receives a citadel listing. Assumes
+ * LISTING_FOLLOWS has already been received by the client. Pass this
+ * the socket descriptor and a list not yet allocated.
+ */
+
+int citadel_receive_listing(int sd, citadel_list **list)
+{
+ char strbuf[CITADEL_STR_SIZE];
+ int ret;
+ int notdone;
+
+ do
+ {
+ ret = citadel_recv_line(sd, strbuf, CITADEL_STR_SIZE);
+ if (ret < 1)
+ return(ret);
+
+ notdone = (strcmp(strbuf, "000"));
+ if (notdone)
+ add_citadel_list(list, strbuf);
+
+ } while (notdone);
+
+ return OK;
+}
+
+/*
+ * citadel_send_listing() - sends a citadel listing. Assumes
+ * SEND_FOLLOWS has already been received by the client. Pass this
+ * the socket descriptor and a filled list.
+ */
+
+int citadel_send_listing(int sd, citadel_list *list)
+{
+ int ret;
+ citadel_list *t_list;
+ char strbuf[256];
+
+ if (!list)
+ {
+ fprintf(stderr, "Error: list is NULL in citadel_send_listing!\n");
+ return -1;
+ }
+
+ for (t_list = list; t_list; t_list=t_list->next)
+ {
+ snprintf(strbuf, sizeof(strbuf)-1, "%s\n", t_list->listitem);
+ ret = citadel_send(sd, strbuf, strlen(strbuf));
+ if (ret < 0)
+ return(ret);
+ }
+
+ ret = citadel_send(sd, "000\n", 4);
+
+ return(ret);
+}
+
+/*
+ * citadel_send_listing_file(char *) - sends a citadel listing from the
+ * file filename. This assumes SEND_FOLLOWS has already been received
+ * by the client. Pass this the socket descriptor and the filename
+ */
+
+int citadel_send_listing_file(int sd, char *filename)
+{
+ int ret;
+ int fd;
+ int l;
+ char strbuf[CITADEL_STR_SIZE];
+
+ if (!filename)
+ {
+ fprintf(stderr, "Error: filename is NULL in citadel_send_listing_file!\n");
+ return -1;
+ }
+
+ if ((fd = open(filename, O_RDONLY)) < 0)
+ {
+ fprintf(stderr, "Error- filename %s does not exist!\n", filename);
+ return(-1);
+ }
+
+ do
+ {
+ l = get_line(fd, strbuf, sizeof(strbuf));
+
+ if (l > 0)
+ {
+/* If there's a blank in the first, despite l == 1,
+ * it means the line was just a \n.
+ */
+ if (!strbuf[0])
+ {
+ strcpy(strbuf, "\n");
+ l = 3;
+ }
+
+ ret = citadel_send_line(sd, strbuf);
+ if (ret < 0)
+ {
+ close(fd);
+ return(ret);
+ }
+ }
+ } while (l>0);
+
+ ret = citadel_send(sd, "000\n", 4);
+
+ close(fd);
+
+ return(1);
+}
+
+
--- /dev/null
+#define CITADEL_STR_SIZE 1024
+
+int citadel_parseparms(char *line, citadel_parms *parms);
+
+ /*
+ * int citadel_sendparms(int sd, citadel_parms *parms, int expect) - sends
+ * the parms structure parms to the server on descriptor sd. Expect
+ * controls whether the client expects to receive a response.
+ * This returns 1 if all of the requested functions worked, otherwise it
+ * returns 0.
+ *
+ */
+
+int citadel_sendparms(int sd, citadel_parms *parms, char *cmd, int expect);
+int citadel_recvparms(int sd, citadel_parms *parms);
+int free_citadel_parms(citadel_parms **parms);
+
+int citadel_receive_listing(int sd, citadel_list **list);
+int citadel_send_listing(int sd, citadel_list *list);
+int citadel_send_listing_file(int sd, char *filename);
+int add_citadel_list(citadel_list **first_list, char *item);
+
+int free_citadel_list(citadel_list **first_list);
+citadel_parms *newparms();
+int reset_parms(citadel_parms **);
--- /dev/null
+/*
+
+A wrapper around the citadel_api and, to a lesser extent, transport.
+Brian Costello
+btx@calyx.net
+
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include "client_api.h"
+#include "citadel_util.h"
+#include "citadel_api.h"
+#include "transport.h"
+
+/*
+
+get_form takes a formname, and returns the citadel form (MESG) in list
+
+*/
+
+int get_form(int sd, char *formname, citadel_list **list)
+{
+ int ret;
+ if ((ret=cmd_mesg(sd, formname, list)) < 0)
+ {
+ fprintf(stderr, "Error in disp_form\n");
+ return -1;
+ }
+
+ return 1;
+}
+
+int get_all_rooms(client_context *our_context, citadel_list **list)
+{
+ int ret;
+
+ if ((ret = cmd_lkra(our_context->sd, list, -1)) < 0)
+ {
+ fprintf(stderr, "cmd_lkra failed in get_all_rooms.\n");
+ return -1;
+ }
+ return 1;
+}
+
+int get_all_new_rooms(client_context *our_context, citadel_list **list)
+{
+ int ret;
+
+ if ((ret = cmd_lkrn(our_context->sd, list, -1)) < 0)
+ {
+ fprintf(stderr, "cmd_lkrn failed in get_all_new_rooms.\n");
+ return -1;
+ }
+ return 1;
+}
+
+
+/*
+
+get_new_msg_list returns a list of the new message numbers in the current
+room.
+
+*/
+
+int get_new_msg_list(client_context *our_context, citadel_list **list)
+{
+ if (cmd_msgs(our_context->sd, list, "NEW", 0)<0)
+ {
+ fprintf(stderr, "cmd_msgs failed in get_new_msg_list().\n");
+ return -1;
+ }
+
+ return 1;
+}
+
+/*
+
+get_last_msg_list returns a list of the last <num_last> message numbers from
+the current room.
+
+*/
+
+int get_last_msg_list(client_context *our_context, int num_last, citadel_list **list)
+{
+ if (cmd_msgs(our_context->sd, list, "LAST", num_last)<0)
+ {
+ fprintf(stderr, "cmd_msgs failed in get_new_msg_list().\n");
+ return -1;
+ }
+
+ return 1;
+}
+
+/*
+
+get_msg_num returns a list containing the text of message number <msgnum>.
+msgnum is determined by calling get_new_msg_list() or similar function.
+
+*/
+
+int get_msg_num(client_context *our_context, int msgnum, citadel_list **list)
+{
+ *list = NULL;
+
+#ifdef DEBUG
+ printf("get_msg_num - getting message #%d\n", msgnum);
+#endif
+ if (cmd_msg0(our_context->sd, list, msgnum, 0)<0)
+ {
+ fprintf(stderr, "cmd_msg0 failed in get_msg_num().\n");
+ return -1;
+ }
+
+ return 1;
+}
+
+/*
+
+goto_room goes to room <roomname> with a password <password>. If password is
+null, no password is transmitted. If reset_msgs is set, the room's messages
+are all marked read. The parms from the goto command update our_context.
+
+*/
+
+int goto_room(client_context *our_context, char *roomname, char *password, citadel_parms *parms, int reset_msgs)
+{
+ citadel_parms *othparms;
+
+
+ if (reset_msgs)
+ {
+ othparms = newparms();
+
+ if (cmd_slrp(our_context->sd, 0, 1, othparms)<0)
+ {
+ fprintf(stderr, "cmd_slrp failed in goto_room.\n");
+ return -1;
+ }
+
+ free_citadel_parms(&othparms);
+ }
+
+ if (cmd_goto(our_context->sd, roomname, password, parms)<0)
+ {
+ fprintf(stderr, "Unable to goto room %s!\n", roomname);
+ return -1;
+ }
+
+ if (parms->argc < 9)
+ {
+ fprintf(stderr, "Only %d parms returned from GOTO!\n", parms->argc);
+ return -1;
+ }
+
+ strcpy(our_context->roomname, parms->argv[0]);
+ if (password)
+ strcpy(our_context->roompass, password);
+ else
+ our_context->roompass[0] = '\0';
+
+ our_context->unread_msg = atoi(parms->argv[1]);
+ our_context->num_msg = atoi(parms->argv[2]);
+ our_context->info_flag = atoi(parms->argv[3]);
+ our_context->room_flags = atoi(parms->argv[4]);
+ our_context->highest_msg_num = atoi(parms->argv[5]);
+ our_context->highest_read_msg = atoi(parms->argv[6]);
+ our_context->is_mail_room = atoi(parms->argv[7]);
+ our_context->is_room_aide = atoi(parms->argv[8]);
+ if (parms->argc > 9)
+ our_context->new_mail_msgs = atoi(parms->argv[9]);
+ if (parms->argc > 10)
+ our_context->room_floor_no = atoi(parms->argv[10]);
+
+ if (parms->line[3] == '*')
+ our_context->message_waiting = 1;
+ return 1;
+}
+
+/*
+
+Sends filename <filename> over as a post
+
+*/
+
+int post_file(char *filename, client_context *our_context, citadel_parms *parms)
+{
+ int ret;
+
+ ret = cmd_ent0(our_context->sd, 1, NULL, 0, 1, NULL, parms, filename);
+ return(ret);
+}
+
+/*
+
+client_connect sets up a citadel connection. It connects, using the underlying
+transport, inits the session, logs in, gets server information, gives client
+information, returns the opening form in list, and finally goes to _BASEROOM_,
+returning the parms from cmd_goto in parms.
+
+*/
+int client_connect(citadel_parms **parms, client_context *our_context, citadel_list **list)
+{
+ int sd;
+
+ if ((sd = citadel_connect(our_context->host, our_context->port))<0)
+ {
+ fprintf(stderr, "Failed to connect to host %s.\n", our_context->host);
+ return -1;
+ }
+
+ our_context->sd = sd;
+
+ init_session(sd);
+
+ if (cmd_user(sd, our_context->username)<0)
+ {
+ fprintf(stderr, "cmd_user failed in client_connect\n");
+ return -1;
+ }
+
+ if (cmd_pass(sd, our_context->password, *parms)<0)
+ {
+ fprintf(stderr, "cmd_pass failed in client_connect\n");
+ return -1;
+ }
+
+ if ((*parms)->argc < 6)
+ {
+ fprintf(stderr, "cmd_pass returned %d parms instead of 6 in client_connect()\n", (*parms)->argc);
+ return -1;
+ }
+
+ our_context->connected = 1;
+ strcpy(our_context->username, (*parms)->argv[0]);
+ our_context->access_level = atoi((*parms)->argv[1]);
+ our_context->times_called = atoi((*parms)->argv[2]);
+ our_context->messages_posted = atoi((*parms)->argv[3]);
+ our_context->flags = atoi((*parms)->argv[4]);
+ our_context->user_number = atoi((*parms)->argv[5]);
+
+ if (our_context->fake_host[0])
+ {
+ if (cmd_hchg(sd, our_context->fake_host) < 0)
+ {
+ fprintf(stderr, "cmd_hchg failed in client_connect()\n");
+ return -1;
+ }
+ }
+
+ if (our_context->fake_room[0])
+ {
+ if (cmd_rchg(sd, our_context->fake_room) < 0)
+ {
+ fprintf(stderr, "cmd_rchg failed in client_connect()\n");
+ return -1;
+ }
+ }
+
+ if (cmd_info(sd, list)<0)
+ {
+ fprintf(stderr, "cmd_info failed in client_connect()\n");
+ return -1;
+ }
+
+/* @@ insert cmd_info code here! */
+
+ free_citadel_list(list);
+
+ cmd_iden(sd, our_context->devid, our_context->cliid, our_context->verno, our_context->clientstr, our_context->hostname);
+
+ reset_parms(parms);
+
+ get_form(sd, "hello", list);
+
+ goto_room(our_context, "_BASEROOM_", NULL, (*parms), 0);
+
+ return sd;
+}
+
+int citadel_end_session(client_context *our_context)
+{
+ cmd_quit(our_context->sd);
+ citadel_disconnect(our_context->sd);
+ our_context->connected = 0;
+ return 1;
+}
+
+
+/*
+
+Returns a comma delimited description of each room's attributes:
+ private
+ guessname
+ upload
+ visdir
+ anon2
+ prefonly
+*/
+
+void get_flagbuf(int flags, char *flagbuf, int flaglen)
+{
+ int i;
+
+ flagbuf[0] = '\0';
+ snprintf(flagbuf, flaglen-1, "%s%s%s%s%s%s%s%s%s%s%s%s%s", (flags & QR_PERMANENT) ? " Permanent": "",
+ (flags & QR_PRIVATE) ? " Private": "",(flags & QR_PASSWORDED) ? " Passworded": "",
+ (flags & QR_GUESSNAME) ? " Guessname": "",(flags & QR_DIRECTORY) ? " Directory": "",
+ (flags & QR_VISDIR) ? " (Visible)": "",(flags & QR_UPLOAD) ? " Upload": "",
+ (flags & QR_DOWNLOAD) ? " Download": "", (flags & QR_ANONONLY) ? " Anonymous-only": "",
+ (flags & QR_ANON2) ? " Anonymous option": "",(flags & QR_NETWORK) ? " Networked": "",
+ (flags & QR_PREFONLY) ? " Preferred-only": "",(flags & QR_READONLY) ? " Read-only": "");
+ flagbuf[flaglen-1] = '\0';
+
+ i =2;
+ while (i<strlen(flagbuf))
+ {
+ if (flagbuf[i] == ' ')
+ {
+ flagbuf[i] = ',';
+ i++;
+ }
+ i++;
+ }
+}
+
+int get_who_list(client_context *our_context, citadel_list **list)
+{
+ if (cmd_rwho(our_context->sd, list) < 0)
+ {
+ fprintf(stderr, "cmd_rwho failed in get_who_list().\n");
+ return -1;
+ }
+
+ return 1;
+}
+
+int send_page(client_context *our_context, char *pagewho, char *message)
+{
+ int ret;
+
+ if ((!pagewho) || (!message))
+ return -1;
+
+ if (cmd_sexp(our_context->sd, pagewho, message) < 0)
+ {
+ fprintf(stderr,"cmd_sexp failed in send_page.\n");
+ return ret;
+ }
+
+ return 1;
+}
+
+int check_page(client_context *our_context, citadel_list **list)
+{
+ int ret;
+
+ our_context->message_waiting = 0;
+ if ((ret = cmd_pexp(our_context->sd, list)) < 0)
+ {
+
+ /* No error msg - it's normal to have no page message :) */
+
+ return -1;
+ }
+
+ return 1;
+}
--- /dev/null
+/*
+
+Citadel client_api
+A wrapper around the citadel api
+Brian Costello
+btx@calyx.net
+
+*/
+
+#define MAXARGS 128
+#define CITADEL_API_DEVID 4 /* Code for Brian Costello */
+
+#define LISTING_FOLLOWS 100
+#define OK 200
+#define MORE_DATA 300
+#define SEND_LISTING 400
+#define ERROR 500
+#define BINARY_FOLLOWS 600
+#define SEND_BINARY 700
+#define START_CHAT_MODE 800
+
+#define QR_PERMANENT 1 /* Room does not purge */
+#define QR_PRIVATE 4 /* Set for any type of private room */
+#define QR_PASSWORDED 8 /* Set if there's a password too */
+#define QR_GUESSNAME 16 /* Set if it's a guessname room */
+#define QR_DIRECTORY 32 /* Directory room */
+#define QR_UPLOAD 64 /* Allowed to upload */
+#define QR_DOWNLOAD 128 /* Allowed to download */
+#define QR_VISDIR 256 /* Visible directory */
+#define QR_ANONONLY 512 /* Anonymous-Only room */
+#define QR_ANON2 1024 /* Anonymous-Option room */
+#define QR_NETWORK 2048 /* Shared network room */
+#define QR_PREFONLY 4096 /* Preferred status needed to enter */
+#define QR_READONLY 8192 /* Aide status required to post */
+
+
+
+typedef struct
+{
+ int return_code; /* The return code (OK, LISTING_FOLLOWS, ETC) */
+ char *line; /* The unmodified line */
+ int argc; /* The number of args */
+ char *argv[MAXARGS]; /* The args */
+} citadel_parms;
+
+typedef struct s_list
+{
+ char *listitem; /* The list string */
+ struct s_list *next; /* A pointer to the next one */
+} citadel_list;
+
+typedef struct
+{
+ int sd;
+ int connected;
+
+ char host[256];
+ u_short port;
+
+ char username[32];
+ char password[32];
+
+ int access_level;
+ int times_called;
+ int messages_posted;
+ int flags;
+ int user_number;
+
+ int message_waiting;
+
+ int devid;
+ int cliid;
+ int verno;
+ char clientstr[256];
+ char hostname[256];
+ char fake_room[256];
+ char fake_host[256];
+
+ char roomname[256];
+ char selected_room[256];
+ char roompass[256];
+ char selected_who[256];
+ int unread_msg;
+ int num_msg;
+ int info_flag;
+ int room_flags;
+ int highest_msg_num;
+ int highest_read_msg;
+ int is_mail_room;
+ int is_room_aide;
+ int new_mail_msgs;
+ int room_floor_no;
+
+ citadel_list *room_msgs;
+ citadel_list *next_msg_ptr;
+
+ citadel_list *new_msg_rooms;
+ citadel_list *next_new_msg_room;
+
+} client_context;
+
+int client_connect(citadel_parms **, client_context *, citadel_list **);
+int citadel_end_session(client_context *);
+int get_serv_info(client_context *);
+int post_file(char *, client_context *, citadel_parms *parms);
+int get_all_rooms(client_context *, citadel_list **list);
+int get_all_new_rooms(client_context *, citadel_list **list);
+void get_flagbuf(int, char *, int);
+int goto_room(client_context *, char *, char *, citadel_parms *, int);
+int get_new_msg_list(client_context *, citadel_list **list);
+int get_last_msg_list(client_context *, int num_last, citadel_list **list);
+int get_msg_num(client_context *, int msgnum, citadel_list **);
+int get_who_list(client_context *, citadel_list **);
+int send_page(client_context *, char *pagewho, char *message);
+int check_page(client_context *, citadel_list **list);
--- /dev/null
+/*
+
+Citadel TCP/IP transport layer
+Brian Costello
+btx@calyx.net
+
+*/
+
+#include <stdio.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include "client_api.h"
+#include "transport.h"
+
+int citadel_connect(char *host, u_short port)
+{
+ int sock=-1, ret;
+ struct sockaddr_in sin;
+
+ if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
+ {
+ perror("Citadel_connect");
+ return sock;
+ }
+
+ sin.sin_family = AF_INET;
+ sin.sin_port = htons(port);
+ sin.sin_addr.s_addr = inet_addr(host);
+
+ ret = connect(sock, &sin, sizeof(sin));
+
+ if (ret < 0)
+ {
+ perror("Citadel_connect - connect()");
+ return(ret);
+ }
+ return(sock);
+}
+
+int citadel_disconnect(int sd)
+{
+ int n;
+
+ if ((n=close(sd))<0)
+ return(n);
+ return(0);
+}
+
+int citadel_send(int sd, char *buf, int buflen)
+{
+ int n;
+
+ if (buflen < 1)
+ return(0);
+
+ n = write(sd, buf, buflen);
+
+#ifdef DEBUG
+ printf("Wrote: %s\n", buf);
+#endif
+
+ return(n);
+}
+
+int citadel_recv_line(int sd, char *buf, int buflen)
+{
+ int cl = 0;
+ int n;
+
+ if (!buf)
+ {
+ fprintf(stderr, "Error: BUF in citadel_recv is NULL!\n");
+ return -1;
+ }
+
+#ifdef DEBUG
+ fprintf(stderr,"Receiving in citadel_recv_line...\n");
+#endif
+
+ do
+ {
+ n = read(sd, &buf[cl], 1);
+ if (n)
+ {
+ if (buf[cl] == '\n')
+ buf[cl] = '\0';
+ cl++;
+ }
+ } while ((n) && (cl < buflen) && (buf[cl-1]));
+
+ if (cl == buflen)
+ buf[buflen-1] = '\0';
+
+ if (!n)
+ buf[cl] = '\0';
+
+#ifdef DEBUG
+ printf("Received: %s\n", buf);
+#endif
+ return(cl);
+
+}
+
+int citadel_recv(int sd, char *buf, int buflen)
+{
+ int n;
+
+ if (!buf)
+ {
+ fprintf(stderr, "Error: BUF in citadel_recv is NULL!\n");
+ return -1;
+ }
+
+#ifdef DEBUG
+ fprintf(stderr,"Receiving...\n");
+#endif
+ n = read(sd, buf, buflen);
+#ifdef DEBUG
+ buf[n] = '\0';
+ printf("Received: %s\n", buf);
+#endif
+ return(n);
+}
+
--- /dev/null
+#define DEBUG
+
+/*
+ * citadel_connect connects to the specified host/port combo. It returns
+ * the socket descriptor, or < 0 on failure.
+ *
+ */
+
+int citadel_connect(char *host, u_short port);
+
+/*
+ * citadel_disconnect - Immediately closes the specified descriptor (sd).
+ * Returns 1 on success, < 0 on failure.
+ *
+ */
+
+int citadel_disconnect(int sd);
+/*
+ * int citadel_send(int sd, char *buf, int buflen) - Sends the buflen
+ * bytes in buf to the socket sd. Returns either the length sent or < 0
+ * on failure.
+ */
+
+int citadel_send(int sd, char *buf, int buflen);
+
+/*
+ * int citadel_recv(int sd, char *buf, int buflen) - Receives up to buflen
+ * bytes in buf from the socket sd. Returns either the length received
+ * or < 0 on failure.
+ */
+
+int citadel_recv(int sd, char buf[], int buflen);
+
+/*
+ * int citadel_recv(int sd, char *buf, int buflen) - Receives up to buflen
+ * bytes in buf from the socket sd. Returns either the length received
+ * or < 0 on failure. Buf will be filled with ONE line. Note: THis is much
+ * less efficient than calling citadel_recv, so only call this when you need
+ * to.
+ */
+
+int citadel_recv_line(int sd, char buf[], int buflen);