]> code.citadel.org Git - citadel.git/commitdiff
Initial revision
authorNathan Bryant <loanshark@uncensored.citadel.org>
Mon, 2 Nov 1998 20:03:25 +0000 (20:03 +0000)
committerNathan Bryant <loanshark@uncensored.citadel.org>
Mon, 2 Nov 1998 20:03:25 +0000 (20:03 +0000)
21 files changed:
gcit/Makefile [new file with mode: 0644]
gcit/gtk/Makefile [new file with mode: 0644]
gcit/gtk/TODO [new file with mode: 0644]
gcit/gtk/citclirc [new file with mode: 0644]
gcit/gtk/gcit.c [new file with mode: 0644]
gcit/gtk/gcit.gif [new file with mode: 0644]
gcit/gtk/gcit.h [new file with mode: 0644]
gcit/gtk/gcitrc [new file with mode: 0644]
gcit/gtk/gtk_misc.c [new file with mode: 0644]
gcit/gtk/gtk_misc.h [new file with mode: 0644]
gcit/gtk/gui.c [new file with mode: 0644]
gcit/gtk/gui.h [new file with mode: 0644]
gcit/libcli_cit/Makefile [new file with mode: 0644]
gcit/libcli_cit/citadel_api.c [new file with mode: 0644]
gcit/libcli_cit/citadel_api.h [new file with mode: 0644]
gcit/libcli_cit/citadel_util.c [new file with mode: 0644]
gcit/libcli_cit/citadel_util.h [new file with mode: 0644]
gcit/libcli_cit/client_api.c [new file with mode: 0644]
gcit/libcli_cit/client_api.h [new file with mode: 0644]
gcit/libcli_cit/tcp_trans.c [new file with mode: 0644]
gcit/libcli_cit/transport.h [new file with mode: 0644]

diff --git a/gcit/Makefile b/gcit/Makefile
new file mode 100644 (file)
index 0000000..a3fa1dd
--- /dev/null
@@ -0,0 +1,28 @@
+# 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 ..)
+
diff --git a/gcit/gtk/Makefile b/gcit/gtk/Makefile
new file mode 100644 (file)
index 0000000..b7a87be
--- /dev/null
@@ -0,0 +1,34 @@
+# 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
diff --git a/gcit/gtk/TODO b/gcit/gtk/TODO
new file mode 100644 (file)
index 0000000..9986c61
--- /dev/null
@@ -0,0 +1,4 @@
+Things not done with the Gtk client:
+
+- New user login
+- Chat
diff --git a/gcit/gtk/citclirc b/gcit/gtk/citclirc
new file mode 100644 (file)
index 0000000..8bff77b
--- /dev/null
@@ -0,0 +1,32 @@
+
+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"
diff --git a/gcit/gtk/gcit.c b/gcit/gtk/gcit.c
new file mode 100644 (file)
index 0000000..8cb7429
--- /dev/null
@@ -0,0 +1,515 @@
+/*
+
+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);
+}
+
+
diff --git a/gcit/gtk/gcit.gif b/gcit/gtk/gcit.gif
new file mode 100644 (file)
index 0000000..dc603f0
Binary files /dev/null and b/gcit/gtk/gcit.gif differ
diff --git a/gcit/gtk/gcit.h b/gcit/gtk/gcit.h
new file mode 100644 (file)
index 0000000..6900a10
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+
+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 *);
diff --git a/gcit/gtk/gcitrc b/gcit/gtk/gcitrc
new file mode 100644 (file)
index 0000000..8bff77b
--- /dev/null
@@ -0,0 +1,32 @@
+
+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"
diff --git a/gcit/gtk/gtk_misc.c b/gcit/gtk/gtk_misc.c
new file mode 100644 (file)
index 0000000..aa3ce32
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+
+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);
+}
diff --git a/gcit/gtk/gtk_misc.h b/gcit/gtk/gtk_misc.h
new file mode 100644 (file)
index 0000000..74c087b
--- /dev/null
@@ -0,0 +1,9 @@
+/*
+
+Misc. gtk display routines
+
+*/
+
+void print_gtk(GtkWidget *text, char *str, ...);
+void gtk_yesno(char *, char *, int, void *, void *);
+void gtk_killyesno();
diff --git a/gcit/gtk/gui.c b/gcit/gtk/gui.c
new file mode 100644 (file)
index 0000000..fe3d2db
--- /dev/null
@@ -0,0 +1,806 @@
+/*
+
+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);
+}
diff --git a/gcit/gtk/gui.h b/gcit/gtk/gui.h
new file mode 100644 (file)
index 0000000..2174b3f
--- /dev/null
@@ -0,0 +1,9 @@
+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();
diff --git a/gcit/libcli_cit/Makefile b/gcit/libcli_cit/Makefile
new file mode 100644 (file)
index 0000000..a8c6324
--- /dev/null
@@ -0,0 +1,25 @@
+# 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
diff --git a/gcit/libcli_cit/citadel_api.c b/gcit/libcli_cit/citadel_api.c
new file mode 100644 (file)
index 0000000..8d066b9
--- /dev/null
@@ -0,0 +1,528 @@
+/*
+
+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;
+}
diff --git a/gcit/libcli_cit/citadel_api.h b/gcit/libcli_cit/citadel_api.h
new file mode 100644 (file)
index 0000000..0135a2f
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+
+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,  */
diff --git a/gcit/libcli_cit/citadel_util.c b/gcit/libcli_cit/citadel_util.c
new file mode 100644 (file)
index 0000000..12ac44c
--- /dev/null
@@ -0,0 +1,460 @@
+/*
+
+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);
+}
+
+
diff --git a/gcit/libcli_cit/citadel_util.h b/gcit/libcli_cit/citadel_util.h
new file mode 100644 (file)
index 0000000..8b9ea55
--- /dev/null
@@ -0,0 +1,25 @@
+#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 **);
diff --git a/gcit/libcli_cit/client_api.c b/gcit/libcli_cit/client_api.c
new file mode 100644 (file)
index 0000000..10a7163
--- /dev/null
@@ -0,0 +1,369 @@
+/*
+
+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;
+}
diff --git a/gcit/libcli_cit/client_api.h b/gcit/libcli_cit/client_api.h
new file mode 100644 (file)
index 0000000..1ef0279
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+
+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);
diff --git a/gcit/libcli_cit/tcp_trans.c b/gcit/libcli_cit/tcp_trans.c
new file mode 100644 (file)
index 0000000..4957b26
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+
+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);
+}
+
diff --git a/gcit/libcli_cit/transport.h b/gcit/libcli_cit/transport.h
new file mode 100644 (file)
index 0000000..bb8d0a1
--- /dev/null
@@ -0,0 +1,42 @@
+#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);