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.