Commit 8203e73f authored by deuce's avatar deuce
Browse files

A GTK+ based chat program similar to the Win32 chat.exe.

Requires SBBSCTRL to be set.
Accepts the node number as its only and required argument.
parent 853c4845
# GNUmakefile
#########################################################################
# Makefile for Synchronet monitor for Unix #
# For use with GNU make and GNU C Compiler or Borland Kylix C++ #
# @format.tab-size 4, @format.use-tabs true #
# #
# gcc: gmake #
# Borland (still in testing/debuging stage): gmake bcc=1 #
# #
# Optional build targets: dlls, utils, mono, all (default) #
#########################################################################
# $Id$
SRC_ROOT = ../..
include $(SRC_ROOT)/build/Common.gmake
ifeq ($(os),sunos)
LDFLAGS += -lnsl
endif
vpath %.c ..
CFLAGS += -I.. $(SMBLIB_CFLAGS) $(XPDEV-MT_CFLAGS) `pkg-config gtk+-2.0 --cflags`
LDFLAGS += $(SMBLIB_LDFLAGS) $(XPDEV-MT_LDFLAGS) $(MT_LDFLAGS) `pkg-config gtk+-2.0 --libs`
$(GTKCHAT): $(OBJS)
@echo Linking $@
$(QUIET)$(CC) $(LDFLAGS) $(OBJS) -o $@ $(SMBLIB_LIBS) $(XPDEV-MT_LIBS)
#include <gtk/gtk.h>
#include "chatfuncs.h"
#include "callbacks.h"
#include "interface.h"
#include "support.h"
gint
get_from_remote(gpointer data)
{
int ch;
gchar *outstr;
gchar instr[2];
int inbytes;
int outbytes;
instr[1]=0;
switch(chat_check_remote()) {
case 2: /* Chat active */
while(ch=chat_read_byte()) {
if(ch==-1) {
chat_close();
gtk_main_quit();
return(FALSE);
}
if(ch==8 || ch==127) {
GtkTextIter start;
GtkTextIter end;
gtk_text_buffer_get_iter_at_mark(
gtk_text_view_get_buffer(GTK_TEXT_VIEW(data))
,&start
,gtk_text_buffer_get_insert(
gtk_text_view_get_buffer(GTK_TEXT_VIEW(data))
)
);
end=start;
gtk_text_iter_backward_cursor_position(&end);
gtk_text_buffer_delete(
gtk_text_view_get_buffer(GTK_TEXT_VIEW(data))
,&start
,&end
);
}
else {
instr[0]=ch;
outstr=g_convert(instr, 1, "UTF-8", "CP437", &inbytes, &outbytes, NULL);
gtk_text_buffer_insert_at_cursor(
gtk_text_view_get_buffer(GTK_TEXT_VIEW(data))
,outstr
,1
);
g_free(outstr);
}
}
return(TRUE);
}
chat_close();
return(FALSE);
}
gint
connect_wait(gpointer data)
{
GtkWidget *MainWindow;
switch(chat_check_remote()) {
case -1: /* Error */
case 0: /* Remote has gone away */
chat_close();
return(FALSE);
case 1: /* Waiting for remote */
return(TRUE);
case 2: /* Chat active */
MainWindow = create_MainWindow ();
gtk_widget_hide (GTK_WIDGET(data));
gtk_widget_show (MainWindow);
return(FALSE);
}
return(TRUE);
}
void
on_MainWindow_destroy (GtkObject *object,
gpointer user_data)
{
chat_close();
gtk_main_quit();
}
gboolean
on_LocalText_key_press_event (GtkWidget *widget,
GdkEventKey *event,
gpointer user_data)
{
gchar *outstr;
gchar instr[2];
int inbytes;
int outbytes;
if(event->keyval=='\b' || event->keyval==127) {
GtkTextIter start;
GtkTextIter end;
chat_write_byte(event->keyval);
gtk_text_buffer_get_iter_at_mark(
gtk_text_view_get_buffer(GTK_TEXT_VIEW(widget))
,&start
,gtk_text_buffer_get_insert(
gtk_text_view_get_buffer(GTK_TEXT_VIEW(widget))
)
);
end=start;
gtk_text_iter_backward_cursor_position(&end);
gtk_text_buffer_delete(
gtk_text_view_get_buffer(GTK_TEXT_VIEW(widget))
,&start
,&end
);
}
if(event->keyval >= 32 && event->keyval < 127) {
instr[1]=0;
instr[0]=event->keyval;
outstr=g_convert(instr, 1, "UTF-8", "CP437", &inbytes, &outbytes, NULL);
gtk_text_buffer_insert_at_cursor(
gtk_text_view_get_buffer(GTK_TEXT_VIEW(widget))
,outstr
,1
);
g_free(outstr);
}
return FALSE;
}
void
on_CancelButton_clicked (GtkButton *button,
gpointer user_data)
{
chat_close();
gtk_main_quit();
}
#include <gtk/gtk.h>
void
on_MainWindow_destroy (GtkObject *object,
gpointer user_data);
gboolean
on_LocalText_key_press_event (GtkWidget *widget,
GdkEventKey *event,
gpointer user_data);
void
on_CancelButton_clicked (GtkButton *button,
gpointer user_data);
gint
get_from_remote(gpointer data);
gint
connect_wait(gpointer data);
#include <sys/types.h>
#include <sys/uio.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <time.h>
#include <utime.h>
#include <unistd.h>
#include "sbbs.h"
#include "chatfuncs.h"
#define PCHAT_LEN 1000
char usrname[128];
static node_t node;
static int nodenum;
static int in,out;
static char inpath[MAX_PATH+1];
static char outpath[MAX_PATH+1];
static scfg_t cfg;
static int togglechat(int on)
{
static int org_act;
int nodefile;
if(getnodedat(&cfg,nodenum,&node,&nodefile))
return(-1);
if(on) {
org_act=node.action;
if(org_act==NODE_PCHT)
org_act=NODE_MAIN;
node.misc|=NODE_LCHAT;
}
else {
node.action=org_act;
node.misc&=~NODE_LCHAT;
}
if(putnodedat(&cfg,nodenum,&node,nodefile))
return(-1);
return(0);
}
int chat_open(int node_num, char *ctrl_dir)
{
char *p;
char str[1024];
/* Read .cfg files here */
memset(&cfg,0,sizeof(cfg));
cfg.size=sizeof(cfg);
SAFECOPY(cfg.ctrl_dir,ctrl_dir);
if(!load_cfg(&cfg, NULL, TRUE, str))
return(-1);
nodenum=node_num;
if(getnodedat(&cfg,nodenum,&node,NULL))
return(-1);
username(&cfg,node.useron,usrname);
sprintf(outpath,"%slchat.dab",cfg.node_path[nodenum-1]);
if((out=sopen(outpath,O_RDWR|O_CREAT|O_BINARY,O_DENYNONE
,S_IREAD|S_IWRITE))==-1) {
return(-1);
}
sprintf(inpath,"%schat.dab",cfg.node_path[nodenum-1]);
if((in=sopen(inpath,O_RDWR|O_CREAT|O_BINARY,O_DENYNONE
,S_IREAD|S_IWRITE))==-1) {
close(out);
return(-1);
}
if((p=(char *)malloc(PCHAT_LEN))==NULL) {
close(in);
close(out);
return(-1);
}
memset(p,0,PCHAT_LEN);
write(in,p,PCHAT_LEN);
write(out,p,PCHAT_LEN);
free(p);
lseek(in,0,SEEK_SET);
lseek(out,0,SEEK_SET);
if(togglechat(TRUE))
return(-1);
return(0);
}
int chat_check_remote(void)
{
time_t now;
static time_t last_nodechk=0;
now=time(NULL);
if(now!=last_nodechk) {
if(getnodedat(&cfg,nodenum,&node,NULL)!=0)
return(-1); /* Failed to read nodedat! */
last_nodechk=now;
}
if(node.misc&NODE_LCHAT)
return(1); /* Still Waiting */
if(node.status==NODE_WFC || node.status>NODE_QUIET || node.action!=NODE_PCHT)
return(0); /* Remote has gone away */
if(in==-1)
return(0); /* Remote has gone away */
if(out==-1)
return(-1); /* Write error or some such */
return(2); /* Everything is good! */
}
int chat_read_byte(void)
{
unsigned char ch=0;
if(in==-1)
return(-1);
utime(inpath,NULL);
switch(read(in,&ch,1)) {
case -1:
close(in);
in=-1;
return(-1);
case 0:
if(lseek(in,0,SEEK_SET)==-1); /* Wrapped */
return(-1);
switch(read(in,&ch,1)) {
case -1:
close(in);
in=-1;
return(-1);
}
/* Fall-through */
case 1:
lseek(in,-1L,SEEK_CUR);
if(ch) {
write(in,"",1);
return(ch);
}
}
return(0);
}
int chat_write_byte(unsigned char ch)
{
if(out==-1)
return(-1);
if(lseek(out,0,SEEK_CUR)>=PCHAT_LEN)
lseek(out,0,SEEK_SET);
switch(write(out,&ch,1)) {
case -1:
close(out);
out=-1;
return(-1);
}
utime(outpath,NULL);
return(0);
}
int chat_close(void)
{
if(in != -1)
close(in);
if(out != -1)
close(out);
return(togglechat(FALSE));
}
#ifndef _CHATFUNCS_H_
#define _CHATFUNCS_H_
extern char usrname[128];
int chat_open(int node_num, char *ctrl_dir);
int chat_check_remote(void);
int chat_read_byte(void);
int chat_write_byte(unsigned char ch);
int chat_close(void);
#endif
<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd">
<glade-interface>
<widget class="GtkWindow" id="MainWindow">
<property name="width_request">400</property>
<property name="height_request">300</property>
<property name="visible">True</property>
<property name="title" translatable="yes">Synchronet Sysop Chat</property>
<property name="type">GTK_WINDOW_TOPLEVEL</property>
<property name="window_position">GTK_WIN_POS_NONE</property>
<property name="modal">False</property>
<property name="resizable">True</property>
<property name="destroy_with_parent">False</property>
<property name="icon_name">stock_help-chat</property>
<property name="decorated">True</property>
<property name="skip_taskbar_hint">False</property>
<property name="skip_pager_hint">False</property>
<property name="type_hint">GDK_WINDOW_TYPE_HINT_UTILITY</property>
<property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
<property name="focus_on_map">True</property>
<property name="urgency_hint">False</property>
<signal name="destroy" handler="on_MainWindow_destroy" last_modification_time="Wed, 08 Mar 2006 07:15:35 GMT"/>
<child>
<widget class="GtkVPaned" id="SplitPane">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="position">148</property>
<child>
<widget class="GtkTextView" id="RemoteText">
<property name="visible">True</property>
<property name="tooltip" translatable="yes">Remote Text Window</property>
<property name="editable">False</property>
<property name="overwrite">False</property>
<property name="accepts_tab">True</property>
<property name="justification">GTK_JUSTIFY_LEFT</property>
<property name="wrap_mode">GTK_WRAP_WORD</property>
<property name="cursor_visible">True</property>
<property name="pixels_above_lines">0</property>
<property name="pixels_below_lines">0</property>
<property name="pixels_inside_wrap">0</property>
<property name="left_margin">0</property>
<property name="right_margin">0</property>
<property name="indent">0</property>
<property name="text" translatable="yes"></property>
</widget>
<packing>
<property name="shrink">True</property>
<property name="resize">False</property>
</packing>
</child>
<child>
<widget class="GtkTextView" id="LocalText">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="has_focus">True</property>
<property name="editable">False</property>
<property name="overwrite">False</property>
<property name="accepts_tab">True</property>
<property name="justification">GTK_JUSTIFY_LEFT</property>
<property name="wrap_mode">GTK_WRAP_WORD</property>
<property name="cursor_visible">True</property>
<property name="pixels_above_lines">0</property>
<property name="pixels_below_lines">0</property>
<property name="pixels_inside_wrap">0</property>
<property name="left_margin">0</property>
<property name="right_margin">0</property>
<property name="indent">0</property>
<property name="text" translatable="yes"></property>
<signal name="key_press_event" handler="on_LocalText_key_press_event" last_modification_time="Wed, 08 Mar 2006 07:13:25 GMT"/>
</widget>
<packing>
<property name="shrink">True</property>
<property name="resize">True</property>
</packing>
</child>
</widget>
</child>
</widget>
<widget class="GtkWindow" id="WaitWindow">
<property name="visible">True</property>
<property name="title" translatable="yes">Waiting for user</property>
<property name="type">GTK_WINDOW_TOPLEVEL</property>
<property name="window_position">GTK_WIN_POS_NONE</property>
<property name="modal">False</property>
<property name="resizable">True</property>
<property name="destroy_with_parent">False</property>
<property name="decorated">True</property>
<property name="skip_taskbar_hint">False</property>
<property name="skip_pager_hint">False</property>
<property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property>
<property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
<property name="focus_on_map">True</property>
<property name="urgency_hint">False</property>
<child>
<widget class="GtkFixed" id="fixed1">
<property name="width_request">400</property>
<property name="height_request">40</property>
<property name="visible">True</property>
<child>
<widget class="GtkLabel" id="MessageLabel">
<property name="width_request">400</property>
<property name="height_request">16</property>
<property name="visible">True</property>
<property name="label" translatable="yes">Waiting for user to connect.</property>
<property name="use_underline">False</property>
<property name="use_markup">False</property>
<property name="justify">GTK_JUSTIFY_LEFT</property>
<property name="wrap">False</property>
<property name="selectable">False</property>
<property name="xalign">0.5</property>
<property name="yalign">0.5</property>
<property name="xpad">0</property>
<property name="ypad">0</property>
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
<property name="width_chars">-1</property>
<property name="single_line_mode">False</property>
<property name="angle">0</property>
</widget>
<packing>
<property name="x">0</property>
<property name="y">0</property>
</packing>
</child>
<child>
<widget class="GtkButton" id="CancelButton">
<property name="width_request">88</property>
<property name="height_request">24</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="relief">GTK_RELIEF_NORMAL</property>
<property name="focus_on_click">True</property>
<signal name="clicked" handler="on_CancelButton_clicked" last_modification_time="Thu, 09 Mar 2006 02:41:33 GMT"/>
<child>
<widget class="GtkAlignment" id="alignment1">
<property name="visible">True</property>
<property name="xalign">0.5</property>
<property name="yalign">0.5</property>
<property name="xscale">0</property>
<property name="yscale">0</property>
<property name="top_padding">0</property>
<property name="bottom_padding">0</property>
<property name="left_padding">0</property>
<property name="right_padding">0</property>
<child>
<widget class="GtkHBox" id="hbox1">
<property name="visible">True</property>
<property name="homogeneous">False</property>
<property name="spacing">2</property>
<child>
<widget class="GtkImage" id="image1">
<property name="visible">True</property>
<property name="stock">gtk-cancel</property>
<property name="icon_size">4</property>
<property name="xalign">0.5</property>
<property name="yalign">0.5</property>
<property name="xpad">0</property>
<property name="ypad">0</property>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="label2">
<property name="visible">True</property>
<property name="label" translatable="yes">Cancel</property>
<property name="use_underline">True</property>
<property name="use_markup">False</property>
<property name="justify">GTK_JUSTIFY_LEFT</property>
<property name="wrap">False</property>
<property name="selectable">False</property>
<property name="xalign">0.5</property>
<property name="yalign">0.5</property>
<property name="xpad">0</property>
<property name="ypad">0</property>
<property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
<property name="width_chars">-1</property>
<property name="single_line_mode">False</property>
<property name="angle">0</property>
</widget>
<packing>
<property name="padding">0</property>
<property name="expand">False</property>
<property name="fill">False</property>
</packing>
</child>
</widget>
</child>
</widget>
</child>
</widget>
<packing>
<property name="x">160</property>
<property name="y">16</property>
</packing>
</child>
</widget>
</child>
</widget>
</glade-interface>
<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
<!DOCTYPE glade-project SYSTEM "http://glade.gnome.org/glade-project-2.0.dtd">