# # Talker server process. This is a simple example of how to implement a # talker system in Avios. This deals with all the commands and speech that # comes in from the clients , the clients themselves deal with the logons. # # Something to note here is that the pid of the client process is used as # the user identifier rather than their name as this keeps things simpler # as it saves translating the name into the users client process pid all the # time. # &stdalias.inc &stdprocs.inc #-------------- Set up the aliases ------------- alias 20 MAX_LINES alias "talkclient" TALKC alias "talkdata/passfile" PASSFILE alias "talkdata" DATADIR alias "Sorry - a system error has occured." SYSERROR #--------------- Global variables -------------- var @username @userdesc @userroom @userlines var @roomdesc @roomlinks @roomtopic @roomdata var @commands #--------------- Load room descriptions & links---------------- &roomdata.inc #------------------ Main procedure ------------------ proc main var pid line word name mesg room set commands "who look go desc tell shout" set commands [addstr commands " topic read write public private help"] call count_messages onint from nonchild deathproc di on write_room di on write_user in "MESG_Q" while TRUE while $mesg_cnt input pid line if $pcs:pid!=TALKC; continue; fi ### Check data type set word [head line] choose word value "LOGON" set name [elements line 2] if username?name!="" call write_user pid [format "\nYou are already logged on, killing other session...\n\n"] call write_user username?name "EXIT" set room userroom:username?name call set_roomdata room 3 [math [elements roomdata:room 3]-1] fi set username:pid name set userdesc:pid [tail [tail line]] set userroom:pid "hallway" set userlines:pid 0 call set_roomdata "hallway" 3 [math [elements roomdata:"hallway" 3]+1] call exec_com pid "look" call write_room "" pid [format "%s enters this world." name] break value "SAY" if [set mesg [tail line]]="" if userlines:pid; call exec_com pid "read"; fi break fi call write_user pid [format "You say: %s" mesg] call write_user pid "PRM" call write_room userroom:pid pid [format "%s says: %s" username:pid mesg] break value "COM" call exec_com pid [tail line] chosen wend wend endproc #---- Count the number of messages in all the rooms boards ---- proc count_messages var fd line room val cnt foreach room val in roomdata if [trap [set fd [open to read [format "%s/%s.B" DATADIR room]]]]=OK in fd set cnt 0 input line while [not $eof]; inc cnt; input line; wend close fd call set_roomdata room 2 cnt fi nexteach endproc #---- Set data element in roomdata array --- proc set_roomdata room pos value set roomdata:room [overelem roomdata:room value pos] endproc #---- Send a message to a users process ---- proc write_user pid mesg # Call standard lib routine call _loop_interrupt pid mesg endproc #---- This sends mesg to all talker clients (users) in the given room #---- except for except_pid. If room is "" then message is sent to all rooms. proc write_room room except_pid mesg var pid prog rm foreach pid prog in $pcs if prog!=TALKC or pid=except_pid or [elements [pcsinfo pid] 8]="IMAGE" continue fi if [trap [set rm userroom:pid]]!=OK; continue; fi if rm=room or room="" call write_user pid mesg fi nexteach endproc #---- See if given room exists ---- proc room_exists name var s v # Match whole name foreach s v in roomdesc if s=name; return s; fi nexteach # Match partial name foreach s v in roomdesc if [instr s name 1]=1; return s; fi nexteach endproc #---- We get sent here if a client died. ---= proc deathproc var pid s v room if [tail $int_mesg]!="DEAD"; return; fi set pid [head $int_mesg] foreach s v in username if s=pid call write_room "" pid [format "%s leaves this world." username:pid] set room userroom:pid call set_roomdata room 3 [math [elements roomdata:room 3]-1] set username:pid "" set userdesc:pid "" set userroom:pid "" return fi nexteach endproc #---- This deals with the commands ---- proc exec_com pid line var com s c set com [head line] if [not [member commands com]] foreach s c in commands if [instr c com 1]=1; set com c; break; fi nexteach fi choose com value "who"; call com_who pid; break value "look"; call com_look pid; break value "go"; call com_go pid [elements line 2]; break value "desc"; call com_desc pid [tail line]; break value "tell"; call com_tell pid [tail line]; break value "shout"; call com_shout pid [tail line]; break value "topic"; call com_topic pid [tail line]; break value "read"; call com_read pid; break value "write"; call com_write pid [tail line]; break value "public" value "private"; call com_access pid com; break value "help"; call com_help pid; break default call write_user pid "Unknown command." chosen if userlines:pid; return; fi call write_user pid "PRM" endproc #---- "who" command ---- proc com_who pid var pid2 name call write_user pid [format "\n~BB*** Current users at %s ***\n" [gettime time]] foreach pid2 name in username if name!="" call write_user pid [format "%s %s" name userdesc:pid2] fi nexteach call write_user pid "" endproc #---- "look" command ---- proc com_look pid var pid2 name uroom cnt priv var @pubpriv @a s r str set pubpriv "~FGPUBLIC~RS ~FRPRIVATE~RS" set uroom userroom:pid call write_user pid [format roomdesc:uroom] # Print room exits , private rooms have red names , else green set a roomlinks:uroom foreach s r in a if [head roomdata:r]; set str [addstr str "~FR" r " "] else; set str [addstr str "~FG" r " "]; fi nexteach call write_user pid [format "~FTExits are: %s\n" str] set cnt 0 foreach pid2 name in username if pid2!=pid and userroom:pid2=uroom if cnt=0 call write_user pid "~FTYou can see:~RS" inc cnt fi call write_user pid [format " %s %s\n" username:pid2 userdesc:pid2] fi nexteach if cnt=0; call write_user pid [format "~FTYou are all alone here.\n"]; fi set priv [math [head roomdata:uroom]+1] set str [addstr "Access is currently " pubpriv#priv " and there are ~FM~OL" \ [elements roomdata:uroom 2] "~RS messages on the board."] call write_user pid str if roomtopic:uroom=""; call write_user pid "There is no current topic." else; call write_user pid [format "The topic is: %s" roomtopic:uroom] fi endproc #---- "go" command ---- proc com_go pid newroom var uroom name set uroom userroom:pid set name username:pid if newroom="" call write_user pid "Go where?"; return fi call room_exists newroom if $result="" call write_user pid "There is no such room."; return else; set newroom $result fi if [not [member roomlinks:uroom newroom]] call write_user pid "You can't get there from here."; return fi if [head roomdata:newroom] call write_user pid "That room is currently private."; return fi call write_room newroom pid [format "%s enters from the %s." name uroom] set userroom:pid newroom call write_room uroom pid [format "%s goes to the %s." name newroom] call com_look pid endproc #---- "desc" command ---- proc com_desc pid desc var infd outfd line if desc="" call write_user pid "You must give a description."; return; fi if [trap [set infd [open to read PASSFILE]]] call write_user pid SYSERROR; return fi if [trap [set outfd [open to write "temp"]]] call write_user pid SYSERROR; close infd; return fi in infd; out outfd input line while [not $eof] if [elements line 2]=username:pid printnl [elements line 1 2] " " desc else; printnl line; fi input line wend close infd outfd in "MESG_Q"; out "STDOUT" rename "temp" PASSFILE set userdesc:pid desc call write_user pid "Description set." endproc #---- "tell" command ----- proc com_tell pid line var name if [count line]<2 call write_user pid "Tell who what?"; return fi set name [head line] set name [overstr name [upperstr [midstr name 1]] 1] if name=username:pid call write_user pid "Talking to yourself is the first sign of madness!" return fi if username?name="" call write_user pid "There is no such user."; return fi call write_user pid [format "You tell %s: %s" name [tail line]] call write_user username?name [format "~OL%s tells you:~RS %s" username:pid [tail line]] endproc #---- "shout" command ----- proc com_shout pid mesg if mesg="" call write_user pid "Shout what?"; return fi call write_user pid [format "You shout: %s" mesg] call write_room "" pid [format "~OL%s shouts:~RS %s" username:pid mesg] endproc #---- "topic" command ----- proc com_topic pid topic if topic="" call write_user pid "You must give a topic."; return fi call write_user pid [format "Topic set to: %s" topic] call write_room userroom:pid pid [format "%s has set the topic to: %s" username:pid topic] set roomtopic:userroom:pid topic endproc #---- "read" command ----- proc com_read pid var fd line lcnt pcnt room set room userroom:pid if [trap [set fd [open to read [format "%s/%s.B" DATADIR room]]]] call write_user pid "There are no messages on the board."; return fi call write_room room pid [format "%s reads the message board." username:pid] if userlines:pid=0 call write_user pid [format "\n~BB*** The %s message board ***\n" room] fi # Read through file in fd set lcnt 0 set pcnt 0 while [not $eof] and pcnt<MAX_LINES input line inc lcnt if lcnt>userlines:pid call write_user pid line inc pcnt fi wend close fd in "MESG_Q" if $eof; set userlines:pid 0 else set userlines:pid lcnt call write_user pid "~RV*** Press any key to continue ***" fi endproc #---- "write" command ----- proc com_write pid mesg var fd room board cnt if mesg="" call write_user pid "Write what?"; return fi set room userroom:pid if [trap [set fd [open to append [format "%s/%s.B" DATADIR room]]]] call write_user pid SYSERROR; return fi out fd printnl [format "~FT[%s, %s]: ~RS~OL%s:~RS %s" [gettime date] [gettime time] username:pid mesg] close fd out "STDOUT" call write_user pid "You write the message on the board." call write_room room pid [format "%s writes a message on the board." username:pid] set cnt [math [elements roomdata:room 2]+1] call set_roomdata room 2 cnt endproc #---- "public" & "private" commands ----- proc com_access pid com var room priv cnt set room userroom:pid set priv [head roomdata:room] if com="private" if priv call write_user pid "The room is already private."; return fi set cnt [elements roomdata:room 3] if cnt<2 call write_user pid "You need at least 2 people to make a room private." return fi call write_user pid "Room set to ~FRPRIVATE." call write_room room pid [format "%s has set the room to ~FRPRIVATE." username:pid] call set_roomdata room 1 1 return fi if [not priv] call write_user pid "The room is already public."; return fi call write_user pid "Room set to ~FGPUBLIC." call write_room room pid [format "%s has set the room to ~FGPUBLIC." username:pid] call set_roomdata room 1 0 endproc #--- "help" command proc com_help pid var i str call write_user pid [format "\n~BB*** Commands ***\n"] for i 1 to [count commands] set str [addstr str [format "%-10s " [elements commands i]]] if [math i%5]=0 call write_user pid str; set str "" fi next if str!="" call write_user pid str fi call write_user pid [format "\n~FGRemember all commands start with a '.'\n"] endproc