00001
00002
00003 #include <sys/types.h>
00004 #include <sys/stat.h>
00005 #include <stdio.h>
00006 #include <string.h>
00007 #include <unistd.h>
00008 #include <stdlib.h>
00009 #include <ctype.h>
00010 #include <time.h>
00011 #include <net/hton.h>
00012 #include <net/gen/socket.h>
00013 #include <net/gen/in.h>
00014 #include <net/gen/netdb.h>
00015
00016 #include "talk.h"
00017 #include "talkd.h"
00018 #include "process.h"
00019 #include "finduser.h"
00020
00021 struct entry {
00022 struct entry *prev;
00023 struct talk_request rq;
00024 time_t expire;
00025 struct entry *next;
00026 };
00027
00028 _PROTOTYPE(static int announce, (struct talk_request *request, char *rhost));
00029 _PROTOTYPE(static struct talk_request *lookup, (struct talk_request *request, int type));
00030 _PROTOTYPE(static int addreq, (struct talk_request *request));
00031 _PROTOTYPE(static delete_invite, (long id));
00032 _PROTOTYPE(static long nextid, (void));
00033 _PROTOTYPE(static void delete, (struct entry *e));
00034
00035 static struct entry *entry = (struct entry *)NULL;
00036
00037 int processrequest(request, reply)
00038 struct talk_request *request;
00039 struct talk_reply *reply;
00040 {
00041 char *p;
00042 struct talk_request *rq;
00043 struct hostent *hp;
00044
00045 reply->version = TALK_VERSION;
00046 reply->type = request->type;
00047 reply->answer = 0;
00048 reply->junk = 0;
00049 reply->id = htonl(0);
00050
00051
00052
00053 if(request->version != TALK_VERSION) {
00054 reply->answer = BADVERSION;
00055 return(0);
00056 }
00057
00058
00059 if(ntohs(request->addr.sa_family) != AF_INET) {
00060 reply->answer = BADADDR;
00061 return(0);
00062 }
00063
00064
00065 if(ntohs(request->ctl_addr.sa_family) != AF_INET) {
00066 reply->answer = BADCTLADDR;
00067 return(0);
00068 }
00069
00070
00071 p = request->luser;
00072 while(*p)
00073 if(!isprint(*p)) {
00074 reply->answer = FAILED;
00075 return(0);
00076 } else
00077 p++;
00078
00079 switch(request->type) {
00080 case ANNOUNCE:
00081 reply->answer = find_user(request->ruser, request->rtty);
00082 if(reply->answer != SUCCESS) break;
00083 hp = gethostbyaddr((char *)&request->ctl_addr.sin_addr, sizeof(ipaddr_t), AF_INET);
00084 if(hp == (struct hostent *)NULL) {
00085 reply->answer = MACHINE_UNKNOWN;
00086 break;
00087 }
00088 if((rq = lookup(request, 1)) == (struct talk_request *)NULL) {
00089 reply->id = addreq(request);
00090 reply->answer = announce(request, hp->h_name);
00091 break;
00092 }
00093 if(ntohl(request->id) > ntohl(rq->id)) {
00094 rq->id = nextid();
00095 reply->id = rq->id;
00096 reply->answer = announce(request, hp->h_name);
00097 } else {
00098 reply->id = rq->id;
00099 reply->answer = SUCCESS;
00100 }
00101 break;
00102 case LEAVE_INVITE:
00103 rq = lookup(request, 1);
00104 if(rq == (struct talk_request *)NULL)
00105 reply->id = addreq(request);
00106 else {
00107 reply->id = rq->id;
00108 reply->answer = SUCCESS;
00109 }
00110 break;
00111 case LOOK_UP:
00112 if((rq = lookup(request, 0)) == (struct talk_request *)NULL)
00113 reply->answer = NOT_HERE;
00114 else {
00115 reply->id = rq->id;
00116 memcpy((char *)&reply->addr, (char *)&rq->addr, sizeof(reply->addr));
00117 reply->answer = SUCCESS;
00118 }
00119 break;
00120 case DELETE:
00121 reply->answer = delete_invite(request->id);
00122 break;
00123 default:
00124 reply->answer = UNKNOWN_REQUEST;
00125 }
00126
00127 return(0);
00128 }
00129
00130 static int announce(request, rhost)
00131 struct talk_request *request;
00132 char *rhost;
00133 {
00134 char tty[5+TTY_SIZE+1];
00135 struct stat st;
00136 FILE *fp;
00137 time_t now;
00138 struct tm *tm;
00139
00140 sprintf(tty, "/dev/%s", request->rtty);
00141
00142 if(stat(tty, &st) < 0)
00143 return(PERMISSION_DENIED);
00144
00145 if(!(st.st_mode & S_IWGRP))
00146 return(PERMISSION_DENIED);
00147
00148 if((fp = fopen(tty, "w")) == (FILE *)NULL)
00149 return(PERMISSION_DENIED);
00150
00151 (void) time(&now);
00152
00153 tm = localtime(&now);
00154
00155 fprintf(fp, "\007\007\007\rtalkd: Message from talkd@%s at %d:%02d:%02d\r\n",
00156 myhostname, tm->tm_hour, tm->tm_min, tm->tm_sec);
00157 fprintf(fp, "talkd: %s@%s would like to talk to you\r\n",
00158 request->luser, rhost);
00159 fprintf(fp, "talkd: to answer type: talk %s@%s\r\n",
00160 request->luser, rhost);
00161
00162 fclose(fp);
00163
00164 return(SUCCESS);
00165 }
00166
00167 static struct talk_request *lookup(request, type)
00168 struct talk_request *request;
00169 int type;
00170 {
00171 time_t now;
00172 struct entry *e;
00173
00174 (void) time(&now);
00175
00176 for(e = entry; e != (struct entry *)NULL; e = e->next) {
00177 if(now > e->expire) {
00178 delete(e);
00179 continue;
00180 }
00181 if(type == 0) {
00182 if(!strncmp(request->luser, e->rq.ruser, USER_SIZE) &&
00183 !strncmp(request->ruser, e->rq.luser, USER_SIZE) &&
00184 e->rq.type == LEAVE_INVITE)
00185 return(&e->rq);
00186 } else {
00187 if(request->type == e->rq.type &&
00188 request->pid == e->rq.pid &&
00189 !strncmp(request->luser, e->rq.luser, USER_SIZE) &&
00190 !strncmp(request->ruser, e->rq.ruser, USER_SIZE)) {
00191 e->expire = now + MAX_LIFE;
00192 return(&e->rq);
00193 }
00194 }
00195 }
00196 return((struct talk_request *)NULL);
00197 }
00198
00199 static int addreq(request)
00200 struct talk_request *request;
00201 {
00202 time_t now;
00203 struct entry *e;
00204
00205 (void) time(&now);
00206 request->id = nextid();
00207 e = (struct entry *) malloc(sizeof(struct entry));
00208 if(e == (struct entry *)NULL) {
00209 fprintf(stderr, "talkd: out of memory in insert table\n");
00210 exit(1);
00211 }
00212 e->expire = now + MAX_LIFE;
00213 memcpy((char *)&e->rq, (char *)request, sizeof(struct talk_request));
00214 e->next = entry;
00215 if(e->next != (struct entry *)NULL)
00216 e->next->prev = e;
00217 e->prev = (struct entry *)NULL;
00218 entry = e;
00219 return(request->id);
00220 }
00221
00222 static int delete_invite(id)
00223 long id;
00224 {
00225 time_t now;
00226 struct entry *e;
00227
00228 (void) time(&now);
00229
00230 for(e = entry; e != (struct entry *)NULL; e = e->next) {
00231 if(now > e->expire) {
00232 delete(e);
00233 continue;
00234 }
00235 if(e->rq.id == id) {
00236 delete(e);
00237 return(SUCCESS);
00238 }
00239 }
00240 return(NOT_HERE);
00241 }
00242
00243 static void delete(e)
00244 struct entry *e;
00245 {
00246 if(e == (struct entry *)NULL) return;
00247
00248 if(entry == e)
00249 entry = e->next;
00250 else
00251 if(e->prev != (struct entry *)NULL)
00252 e->prev->next = e->next;
00253
00254 if(e->next != (struct entry *)NULL)
00255 e->next->prev = e->prev;
00256
00257 free((char *)e);
00258
00259 return;
00260 }
00261
00262 static long nextid()
00263 {
00264 static long id = 0;
00265
00266 id++;
00267 if(id <= 0) id = 1;
00268 return(htonl(id));
00269 }