This is talk.c in view mode; [Download] [Up]
/* $Id: talk.c,v 1.2 1995/12/19 19:30:47 eilts Exp eilts $ */
#include "bbs.h"
int talkscreen(const int sockd, const confrecordtyp *confrecord)
{
int k, n, zeilen;
char c=' ', buf[BUFSIZE];
const char *promptptr;
WINDOW *w_win, *r_win;
FD_SET_T readset;
clear();
zeilen = (LINES -1) / 2;
if ((w_win=newwin(zeilen,0,0,0)) == NULL ||
(r_win=newwin(0,0,zeilen+1,0)) == NULL) {
errormsg(E_SYSLOG|E_USER,confrecord,"bbs","talkscreen","cannot create windows");
return(-1);
}
scrollok(w_win,TRUE);
scrollok(r_win,TRUE);
move(zeilen,0);
promptptr = msg("talkscreen",0,confrecord->userrecord.lang);
n = strlen(promptptr);
for (k=0; k<(COLS-n)/2; k++) addch('-');
addstr(promptptr);
for (k=(COLS-n)/2+n; k<COLS; k++) addch('-');
refresh();
FD_ZERO(&readset);
do {
FD_SET(sockd, &readset);
FD_SET(STDIN_FILENO, &readset);
if (select(sockd+1,FD_SETPTR_CAST &readset,NULL,NULL,NULL) > 0) {
if (FD_ISSET(STDIN_FILENO, &readset)) {
n = read(STDIN_FILENO,(void *)buf,(SIZE_T)BUFSIZE);
if ((c=inserttalktext(buf,n,w_win)) != ESCAPE_KEY) {
sendn(sockd,(void *)buf,(SIZE_T)n,0);
}
}
if (FD_ISSET(sockd, &readset)) {
n = recv(sockd,(void *)buf,(SIZE_T)BUFSIZE,0);
inserttalktext(buf,n,r_win);
}
}
} while (c != ESCAPE_KEY);
delwin(w_win);
delwin(r_win);
clear();
refresh();
return(0);
}
char inserttalktext(char *buf, const int n, WINDOW *win)
{
int k, x_p, y_p;
SIZE_T nchars;
char c=' ';
for (k=0; k<n; k++) {
c = buf[k];
if (buf[k] == ESCAPE_KEY) {
buf[k] = ' ';
#if defined(FIONREAD) && ! defined (NO_TV_USEC)
usleep(200000);
if (ioctl(STDIN_FILENO,FIONREAD,&nchars) >= 0) {
if (nchars > 0) {
c = ' ';
}
}
#endif
}
if (c==BACKSPACE_KEY || c==DELETE_KEY) {
getyx(win,y_p,x_p);
if (x_p > 0) {
x_p--;
mvwdelch(win,y_p,x_p);
}
else if (y_p > 0) {
y_p--;
x_p = COLS - 1;
wmove(win,y_p,x_p);
while(x_p>0 && isspace(winch(win))) {
x_p--;
wmove(win,y_p,x_p);
}
if (x_p == COLS-1) {
mvwdelch(win,y_p,x_p);
}
else if (x_p > 0) {
wmove(win,y_p,x_p+1);
}
}
}
else if ((isprint(c) || isspace(c)) && c != ESCAPE_KEY) {
waddch(win,c);
}
}
wrefresh(win);
return(c);
}
int iniconnecttouser(const PID_T remotepid, const confrecordtyp *confrecord)
{
PID_T mypid;
int n, sockd, nsockd, len, lang;
struct sockaddr_un saun;
char sockname[TALKSOCKNAMELEN+1], sockpath[PATH_MAX+1];
char cset[] = {'Q','\0'};
SIGSET_T sigset;
lang = confrecord->userrecord.lang;
/* Talk beim Daemon anmelden */
mypid = getpid();
n = iniconnecttouserd(mypid, remotepid, sockname, confrecord);
if (n == 1) {
writetouser(confrecord,msg("iniconnecttouser",4,lang));
}
if (n != 0) {
praeleaveiniconnecttouser();
return(n);
}
/* Talksocket aufbauen */
nsockd = 0;
if ((sockd=socket(AF_UNIX,SOCK_STREAM,0))<0) {
errormsg(E_SYSLOG|E_USER,confrecord,"bbs","iniconnecttouser","socket: %m");
praeleaveiniconnecttouser();
return(-2);
}
BZERO(&saun, sizeof(saun));
saun.sun_family = AF_UNIX;
sprintf(sockpath,"%s/%s",confrecord->scratchdir,sockname);
strcpy(saun.sun_path,sockpath);
len = SUN_LEN(&saun);
#ifdef SCM_RIGHTS
saun.sun_len = len;
#endif
unlink(saun.sun_path);
if (bind(sockd,(struct sockaddr *)&saun,len)<0) {
errormsg(E_SYSLOG|E_USER,confrecord,"bbs","iniconnecttouser","bind %s: %m",
sockpath);
praeleaveiniconnecttouser();
return(-2);
}
if (listen(sockd,5)<0) {
errormsg(E_SYSLOG|E_USER,confrecord,"bbs","iniconnecttouser",
"listen %s: %m", sockpath);
praeleaveiniconnecttouser();
return(-2);
}
/* Ansprungstellen fuer Signale einrichten */
/* zunaechst eventuell veraltetes sigusr2 loeschen */
sigpending(&sigset);
if (sigismember(&sigset, SIGUSR2)) {
setsighandler(SIGUSR2, SIG_IGN);
sigprocmask(SIG_UNBLOCK, &sigset, NULL);
}
if (sigsetjmp(sigusr1env,(int)FALSE)==0) {
canjump_sigusr1 = TRUE;
setsighandler(SIGUSR1,sighandler);
if (sigsetjmp(sigusr2env,(int)FALSE)==0) {
canjump_sigusr2 = TRUE;
setsighandler(SIGUSR2,sighandler);
}
else {
/* Ablehnung oder Beendigung vom Annehmer */
abortconnecttouser(mypid,remotepid,sockd,sockpath,confrecord);
if (nsockd) {
close(nsockd);
writetouser(confrecord,msg("iniconnecttouser",0,lang));
}
else {
writetouser(confrecord,msg("iniconnecttouser",1,lang));
}
return(0);
}
/* Annehmer um Annahme benachrichtigen */
sigemptyset(&sigset);
sigaddset(&sigset, SIGUSR1);
sigaddset(&sigset, SIGUSR2);
sigprocmask(SIG_BLOCK,&sigset,NULL);
if (kill(remotepid,SIGUSR1) < 0) {
errormsg(E_SYSLOG|E_USER,confrecord,"bbs","iniconnecttouser",
"kill SIGUSR1 %d: %m",remotepid);
praeleaveiniconnecttouser();
return(-2);
}
sigprocmask(SIG_UNBLOCK,&sigset,NULL);
/* Auf Antwortsignal warten */
getkeyonprompt(msg("iniconnecttouser",2,lang),cset,TRUE,FALSE,"",
confrecord);
/* 'Q' (oder Escape) wurde gedrueckt */
abortconnecttouser(mypid,remotepid,sockd,sockpath,confrecord);
writetouser(confrecord,msg("iniconnecttouser",3,lang));
return(0);
}
else {
/* Annehmer hat angenommen */
if ((nsockd=accept(sockd,(struct sockaddr *)&saun,&len))<0) {
errormsg(E_SYSLOG|E_USER,confrecord,"bbs","iniconnecttouser","accept: %m");
praeleaveiniconnecttouser();
return(-2);
}
/* Dialog durchfuehren */
talkscreen(nsockd, confrecord);
/* hierher gelangt man dann, wenn man selber beendet */
close(nsockd);
abortconnecttouser(mypid,remotepid,sockd,sockpath,confrecord);
writetouser(confrecord,msg("iniconnecttouser",0,lang));
}
praeleaveiniconnecttouser();
return(0);
}
void praeleaveiniconnecttouser(void)
{
SIGSET_T sigset;
sigemptyset(&sigset);
sigaddset(&sigset, SIGUSR1);
sigaddset(&sigset, SIGUSR2);
sigprocmask(SIG_BLOCK,&sigset,NULL);
setsighandler(SIGUSR1,sigtalkaccepthandler);
canjump_sigusr2 = FALSE;
}
int abortconnecttouser(const PID_T inipid, const PID_T rempid,
const int tsockd, const char *talksockpath,
const confrecordtyp *confrecord)
{
int sockd, n;
char bstr[BEFSTRLEN+1];
/* Talksocket schliessen und entfernen */
close(tsockd);
if (unlink(talksockpath) < 0) {
errormsg(E_SYSLOG|E_USER,confrecord,"bbs","abortconnecttouser",
"cannot remove talk-socket %s: %m",talksockpath);
}
/* Signalbehandlung zuruecksetzen */
praeleaveiniconnecttouser();
/* Talk beim Daemon abmelden */
if ((sockd=connect2bbsd(confrecord))<0) {
errormsg(E_SYSLOG|E_USER,confrecord,"bbs","abortconnecttouser",
"connection to daemon failed");
exit(1);
}
sprintf(bstr,"#%2d\n",DO_TALKABORT);
sendn(sockd,(void *)bstr,(SIZE_T)BEFSTRLEN,0);
sendn(sockd,(void *)&inipid,(SIZE_T)sizeof(PID_T),0);
sendn(sockd,(void *)&rempid,(SIZE_T)sizeof(PID_T),0);
recvn(sockd,(void *)&n,(SIZE_T)sizeof(int),0);
unconnect2bbsd(sockd,confrecord);
/* Beendigung an Annehmer melden */
if (kill(rempid,SIGUSR2) < 0) {
errormsg(E_SYSLOG|E_USER,confrecord,"bbs","abortconnecttouser",
"kill SIGUSR2 %d: %m",rempid);
return(-2);
}
return(0);
}
int remconnecttouser(const confrecordtyp *confrecord)
{
int n, sockd, len, lang;
struct sockaddr_un saun;
char sockname[TALKSOCKNAMELEN+1], prompt[2*S_STRLEN+1], key;
char cset[] = {'A','Q','\0'};
sessionrecordtyp sr;
SIGSET_T sigset;
lang = confrecord->userrecord.lang;
/* falls Initiator bereits abgebrochen hat sofort zurueckkehren */
sigpending(&sigset);
if (sigismember(&sigset,SIGUSR2)) {
setsighandler(SIGUSR2, SIG_IGN);
sigemptyset(&sigset);
sigaddset(&sigset,SIGUSR2);
sigprocmask(SIG_UNBLOCK,&sigset,NULL);
return(0);
}
/* Initiator beim Daemon erfragen */
sendstatustodaemon(BBS_BUSY,confrecord);
if ((n=remconnecttouserd(&sr,sockname,getpid(),confrecord)) < 0) return(n);
/* Ansprungstelle fuer Beendigung der Verbindung */
sockd = 0;
if (sigsetjmp(sigusr2env,(int)FALSE)==0) {
canjump_sigusr2 = TRUE;
sigemptyset(&sigset);
sigaddset(&sigset,SIGALRM);
setsighandler2(SIGUSR2,sigset,sighandler);
sigemptyset(&sigset);
sigaddset(&sigset,SIGUSR2);
sigprocmask(SIG_UNBLOCK,&sigset,NULL);
}
else {
alarm(0);
setsighandler(SIGALRM, SIG_IGN);
sigemptyset(&sigset);
sigaddset(&sigset,SIGALRM);
sigprocmask(SIG_UNBLOCK,&sigset,NULL);
if (sockd) {
close(sockd);
writetouser(confrecord,msg("remconnecttouser",0,lang));
}
else {
writetouser(confrecord,msg("remconnecttouser",1,lang));
}
praeleaveremconnecttouser(0);
return(0);
}
/* User per Prompt abfragen */
move(LINES-1,0);
clrtoeol();
addstr("TALK:");
refresh();
putchar(BELL_KEY);
#ifdef NO_USLEEP
sleep(1);
#else
usleep(200000);
#endif
sprintf(prompt,msg("remconnecttouser",2,lang),sr.user);
setsighandler(SIGALRM,sighandler);
sigsetjmp(sigalrmenv,(int)TRUE);
canjump_sigalrm = TRUE;
alarm(5);
putchar(BELL_KEY);
key = getkeyonprompt(prompt,cset,TRUE,FALSE,"",confrecord);
alarm(0);
setsighandler(SIGALRM,SIG_IGN);
canjump_sigalrm = FALSE;
if (key == 'A') {
/* Talk angenommen */
/* Initiator Annahmebestaetigung senden */
if (kill(sr.pid,SIGUSR1) < 0) {
errormsg(E_SYSLOG|E_USER,confrecord,"bbs","remconnecttouser",
"kill SIGUSR1 %d: %m",sr.pid);
praeleaveremconnecttouser(sockd);
return(-2);
}
/* Verbindung aufnehmen */
if ((sockd=socket(AF_UNIX,SOCK_STREAM,0)) < 0) {
errormsg(E_SYSLOG|E_USER,confrecord,"bbs","remconnecttouser","socket: %m");
praeleaveremconnecttouser(sockd);
return(-2);
}
BZERO(&saun, sizeof(saun));
saun.sun_family = AF_UNIX;
sprintf(saun.sun_path,"%s/%s",confrecord->scratchdir,sockname);
len = SUN_LEN(&saun);
#ifdef SCM_RIGHTS
saun.sun_len = len;
#endif
if (connect(sockd,(struct sockaddr *)&saun,len) < 0) {
errormsg(E_SYSLOG|E_USER,confrecord,"bbs","remconnecttouser",
"connect %s: %m", saun.sun_path);
praeleaveremconnecttouser(sockd);
return(-2);
}
/* Dialog durchfuehren */
talkscreen(sockd, confrecord);
/* hierhin gelangt man nur, wenn der Annehmer (diese Seite) beendet */
/* Talkende an Initiator senden */
if (kill(sr.pid,SIGUSR2) < 0) {
errormsg(E_SYSLOG|E_USER,confrecord,"bbs","remconnecttouser",
"kill SIGUSR2 %d: %m",sr.pid);
praeleaveremconnecttouser(sockd);
return(-2);
}
}
else {
/* Talk ablehnen */
/* Initiator Ablehnung senden */
if (kill(sr.pid,SIGUSR2) < 0) {
errormsg(E_SYSLOG|E_USER,confrecord,"bbs","remconnecttouser",
"kill SIGUSR2 %d: %m",sr.pid);
praeleaveremconnecttouser(sockd);
return(-2);
}
}
/* der Initiator sendet immer SIGUSR2 zum beenden, auch wenn der Annehmer
zuerst beendete -> gegebenenfalls darauf warten (mit Timeout) */
sleep(TALKQUITTIMEOUT);
praeleaveremconnecttouser(sockd);
return(0);
}
void praeleaveremconnecttouser(const int sockd)
{
SIGSET_T sigset;
if (sockd) close(sockd);
canjump_sigusr2 = FALSE;
sigemptyset(&sigset);
sigaddset(&sigset,SIGUSR2);
sigprocmask(SIG_BLOCK,&sigset,NULL);
}
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.