Hex Artifact Content
Not logged in

Artifact 2ef536f349b27ab6b3566efd52c837ba2ad17c37:


0000: 5c 20 6d 65 73 73 61 67 65 73 20 20 20 20 20 20  \ messages      
0010: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
0020: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20                  
0030: 20 20 20 20 20 30 36 61 75 67 32 30 31 34 70 79       06aug2014py
0040: 0a 0a 5c 20 43 6f 70 79 72 69 67 68 74 20 28 43  ..\ Copyright (C
0050: 29 20 32 30 31 34 2d 32 30 31 36 20 20 20 42 65  ) 2014-2016   Be
0060: 72 6e 64 20 50 61 79 73 61 6e 0a 0a 5c 20 54 68  rnd Paysan..\ Th
0070: 69 73 20 70 72 6f 67 72 61 6d 20 69 73 20 66 72  is program is fr
0080: 65 65 20 73 6f 66 74 77 61 72 65 3a 20 79 6f 75  ee software: you
0090: 20 63 61 6e 20 72 65 64 69 73 74 72 69 62 75 74   can redistribut
00a0: 65 20 69 74 20 61 6e 64 2f 6f 72 20 6d 6f 64 69  e it and/or modi
00b0: 66 79 0a 5c 20 69 74 20 75 6e 64 65 72 20 74 68  fy.\ it under th
00c0: 65 20 74 65 72 6d 73 20 6f 66 20 74 68 65 20 47  e terms of the G
00d0: 4e 55 20 41 66 66 65 72 6f 20 47 65 6e 65 72 61  NU Affero Genera
00e0: 6c 20 50 75 62 6c 69 63 20 4c 69 63 65 6e 73 65  l Public License
00f0: 20 61 73 20 70 75 62 6c 69 73 68 65 64 20 62 79   as published by
0100: 0a 5c 20 74 68 65 20 46 72 65 65 20 53 6f 66 74  .\ the Free Soft
0110: 77 61 72 65 20 46 6f 75 6e 64 61 74 69 6f 6e 2c  ware Foundation,
0120: 20 65 69 74 68 65 72 20 76 65 72 73 69 6f 6e 20   either version 
0130: 33 20 6f 66 20 74 68 65 20 4c 69 63 65 6e 73 65  3 of the License
0140: 2c 20 6f 72 0a 5c 20 28 61 74 20 79 6f 75 72 20  , or.\ (at your 
0150: 6f 70 74 69 6f 6e 29 20 61 6e 79 20 6c 61 74 65  option) any late
0160: 72 20 76 65 72 73 69 6f 6e 2e 0a 0a 5c 20 54 68  r version...\ Th
0170: 69 73 20 70 72 6f 67 72 61 6d 20 69 73 20 64 69  is program is di
0180: 73 74 72 69 62 75 74 65 64 20 69 6e 20 74 68 65  stributed in the
0190: 20 68 6f 70 65 20 74 68 61 74 20 69 74 20 77 69   hope that it wi
01a0: 6c 6c 20 62 65 20 75 73 65 66 75 6c 2c 0a 5c 20  ll be useful,.\ 
01b0: 62 75 74 20 57 49 54 48 4f 55 54 20 41 4e 59 20  but WITHOUT ANY 
01c0: 57 41 52 52 41 4e 54 59 3b 20 77 69 74 68 6f 75  WARRANTY; withou
01d0: 74 20 65 76 65 6e 20 74 68 65 20 69 6d 70 6c 69  t even the impli
01e0: 65 64 20 77 61 72 72 61 6e 74 79 20 6f 66 0a 5c  ed warranty of.\
01f0: 20 4d 45 52 43 48 41 4e 54 41 42 49 4c 49 54 59   MERCHANTABILITY
0200: 20 6f 72 20 46 49 54 4e 45 53 53 20 46 4f 52 20   or FITNESS FOR 
0210: 41 20 50 41 52 54 49 43 55 4c 41 52 20 50 55 52  A PARTICULAR PUR
0220: 50 4f 53 45 2e 20 20 53 65 65 20 74 68 65 0a 5c  POSE.  See the.\
0230: 20 47 4e 55 20 41 66 66 65 72 6f 20 47 65 6e 65   GNU Affero Gene
0240: 72 61 6c 20 50 75 62 6c 69 63 20 4c 69 63 65 6e  ral Public Licen
0250: 73 65 20 66 6f 72 20 6d 6f 72 65 20 64 65 74 61  se for more deta
0260: 69 6c 73 2e 0a 0a 5c 20 59 6f 75 20 73 68 6f 75  ils...\ You shou
0270: 6c 64 20 68 61 76 65 20 72 65 63 65 69 76 65 64  ld have received
0280: 20 61 20 63 6f 70 79 20 6f 66 20 74 68 65 20 47   a copy of the G
0290: 4e 55 20 41 66 66 65 72 6f 20 47 65 6e 65 72 61  NU Affero Genera
02a0: 6c 20 50 75 62 6c 69 63 20 4c 69 63 65 6e 73 65  l Public License
02b0: 0a 5c 20 61 6c 6f 6e 67 20 77 69 74 68 20 74 68  .\ along with th
02c0: 69 73 20 70 72 6f 67 72 61 6d 2e 20 20 49 66 20  is program.  If 
02d0: 6e 6f 74 2c 20 73 65 65 20 3c 68 74 74 70 3a 2f  not, see <http:/
02e0: 2f 77 77 77 2e 67 6e 75 2e 6f 72 67 2f 6c 69 63  /www.gnu.org/lic
02f0: 65 6e 73 65 73 2f 3e 2e 0a 0a 46 6f 72 77 61 72  enses/>...Forwar
0300: 64 20 61 76 61 6c 61 6e 63 68 65 2d 74 6f 20 28  d avalanche-to (
0310: 20 61 64 64 72 20 75 20 6f 3a 63 6f 6e 74 65 78   addr u o:contex
0320: 74 20 2d 2d 20 29 0a 46 6f 72 77 61 72 64 20 70  t -- ).Forward p
0330: 6b 2d 63 6f 6e 6e 65 63 74 20 28 20 6b 65 79 20  k-connect ( key 
0340: 75 20 63 6d 64 6c 65 6e 20 64 61 74 61 6c 65 6e  u cmdlen datalen
0350: 20 2d 2d 20 29 0a 46 6f 72 77 61 72 64 20 70 6b   -- ).Forward pk
0360: 2d 63 6f 6e 6e 65 63 74 3f 20 28 20 6b 65 79 20  -connect? ( key 
0370: 75 20 63 6d 64 6c 65 6e 20 64 61 74 61 6c 65 6e  u cmdlen datalen
0380: 20 2d 2d 20 66 6c 61 67 20 29 0a 46 6f 72 77 61   -- flag ).Forwa
0390: 72 64 20 61 64 64 72 2d 63 6f 6e 6e 65 63 74 20  rd addr-connect 
03a0: 28 20 6b 65 79 2b 61 64 64 72 20 75 20 63 6d 64  ( key+addr u cmd
03b0: 6c 65 6e 20 64 61 74 61 6c 65 6e 20 78 74 20 2d  len datalen xt -
03c0: 2d 20 29 0a 46 6f 72 77 61 72 64 20 70 6b 2d 70  - ).Forward pk-p
03d0: 65 65 6b 3f 20 28 20 61 64 64 72 20 75 30 20 2d  eek? ( addr u0 -
03e0: 2d 20 66 6c 61 67 20 29 0a 0a 3a 20 3f 68 61 73  - flag )..: ?has
03f0: 68 20 28 20 61 64 64 72 20 75 20 68 61 73 68 20  h ( addr u hash 
0400: 2d 2d 20 29 20 3e 72 0a 20 20 20 20 32 64 75 70  -- ) >r.    2dup
0410: 20 72 40 20 23 40 20 64 30 3d 20 49 46 20 20 22   r@ #@ d0= IF  "
0420: 22 20 32 73 77 61 70 20 72 3e 20 23 21 20 20 45  " 2swap r> #!  E
0430: 4c 53 45 20 20 32 64 72 6f 70 20 72 64 72 6f 70  LSE  2drop rdrop
0440: 20 20 54 48 45 4e 20 3b 0a 0a 56 61 72 69 61 62    THEN ;..Variab
0450: 6c 65 20 6f 74 72 2d 6d 6f 64 65 20 5c 20 67 6c  le otr-mode \ gl
0460: 6f 62 61 6c 20 6f 74 72 20 6d 6f 64 65 0a 0a 3a  obal otr mode..:
0470: 20 3e 67 72 6f 75 70 20 28 20 61 64 64 72 20 75   >group ( addr u
0480: 20 2d 2d 20 29 0a 20 20 20 20 32 64 75 70 20 6d   -- ).    2dup m
0490: 73 67 2d 67 72 6f 75 70 23 20 23 40 20 64 30 3d  sg-group# #@ d0=
04a0: 20 49 46 0a 09 6e 65 74 32 6f 3a 6e 65 77 2d 6d   IF..net2o:new-m
04b0: 73 67 20 3e 6f 20 32 64 75 70 20 74 6f 20 6d 73  sg >o 2dup to ms
04c0: 67 3a 6e 61 6d 65 24 0a 09 6f 74 72 2d 6d 6f 64  g:name$..otr-mod
04d0: 65 20 40 20 49 46 20 20 6d 73 67 3a 2b 6f 74 72  e @ IF  msg:+otr
04e0: 20 20 54 48 45 4e 0a 09 6f 20 6f 3e 0a 09 63 65    THEN..o o>..ce
04f0: 6c 6c 2d 20 5b 20 6d 73 67 2d 63 6c 61 73 73 20  ll- [ msg-class 
0500: 3e 6f 73 69 7a 65 20 40 20 63 65 6c 6c 2b 20 5d  >osize @ cell+ ]
0510: 4c 0a 09 32 6f 76 65 72 20 6d 73 67 2d 67 72 6f  L..2over msg-gro
0520: 75 70 23 20 23 21 0a 20 20 20 20 54 48 45 4e 20  up# #!.    THEN 
0530: 20 6c 61 73 74 23 20 63 65 6c 6c 2b 20 24 40 20   last# cell+ $@ 
0540: 64 72 6f 70 20 63 65 6c 6c 2b 20 74 6f 20 6d 73  drop cell+ to ms
0550: 67 2d 67 72 6f 75 70 2d 6f 0a 20 20 20 20 32 64  g-group-o.    2d
0560: 72 6f 70 20 3b 0a 0a 3a 20 61 76 61 6c 61 6e 63  rop ;..: avalanc
0570: 68 65 2d 6d 73 67 20 28 20 6d 73 67 20 75 31 20  he-msg ( msg u1 
0580: 6f 3a 63 6f 6e 6e 65 63 74 20 2d 2d 20 29 0a 20  o:connect -- ). 
0590: 20 20 20 5c 47 20 66 6f 72 77 61 72 64 20 6d 65     \G forward me
05a0: 73 73 61 67 65 20 74 6f 20 61 6c 6c 20 6e 65 78  ssage to all nex
05b0: 74 20 6e 6f 64 65 73 20 6f 66 20 74 68 61 74 20  t nodes of that 
05c0: 6d 65 73 73 61 67 65 20 67 72 6f 75 70 0a 20 20  message group.  
05d0: 20 20 7b 20 64 3a 20 6d 73 67 78 20 7d 0a 20 20    { d: msgx }.  
05e0: 20 20 6d 73 67 2d 67 72 6f 75 70 2d 6f 20 2e 6d    msg-group-o .m
05f0: 73 67 3a 70 65 65 72 73 5b 5d 20 24 40 0a 20 20  sg:peers[] $@.  
0600: 20 20 62 6f 75 6e 64 73 20 3f 44 4f 20 20 49 20    bounds ?DO  I 
0610: 40 20 6f 20 3c 3e 20 49 46 20 20 6d 73 67 78 20  @ o <> IF  msgx 
0620: 49 20 40 20 2e 61 76 61 6c 61 6e 63 68 65 2d 74  I @ .avalanche-t
0630: 6f 20 20 54 48 45 4e 0a 20 20 20 20 63 65 6c 6c  o  THEN.    cell
0640: 20 2b 4c 4f 4f 50 20 3b 0a 0a 56 61 72 69 61 62   +LOOP ;..Variab
0650: 6c 65 20 6d 73 67 2d 67 72 6f 75 70 24 0a 55 73  le msg-group$.Us
0660: 65 72 20 72 65 70 6c 61 79 2d 6d 6f 64 65 0a 55  er replay-mode.U
0670: 73 65 72 20 73 6b 69 70 2d 73 69 67 3f 0a 0a 53  ser skip-sig?..S
0680: 65 6d 61 20 6d 73 67 6c 6f 67 2d 73 65 6d 61 0a  ema msglog-sema.
0690: 0a 3a 20 3f 6d 73 67 2d 63 6f 6e 74 65 78 74 20  .: ?msg-context 
06a0: 28 20 2d 2d 20 6f 20 29 0a 20 20 20 20 6d 73 67  ( -- o ).    msg
06b0: 69 6e 67 2d 63 6f 6e 74 65 78 74 20 40 20 64 75  ing-context @ du
06c0: 70 20 30 3d 20 49 46 0a 09 64 72 6f 70 0a 09 6e  p 0= IF..drop..n
06d0: 65 74 32 6f 3a 6e 65 77 2d 6d 73 67 69 6e 67 20  et2o:new-msging 
06e0: 64 75 70 20 6d 73 67 69 6e 67 2d 63 6f 6e 74 65  dup msging-conte
06f0: 78 74 20 21 0a 20 20 20 20 54 48 45 4e 20 3b 0a  xt !.    THEN ;.
0700: 0a 3a 20 3e 63 68 61 74 69 64 20 28 20 67 72 6f  .: >chatid ( gro
0710: 75 70 20 75 20 2d 2d 20 69 64 20 75 20 29 20 20  up u -- id u )  
0720: 64 65 66 61 75 6c 74 6b 65 79 20 73 65 63 40 20  defaultkey sec@ 
0730: 6b 65 79 65 64 2d 68 61 73 68 23 31 32 38 20 3b  keyed-hash#128 ;
0740: 0a 0a 3a 20 6d 73 67 2d 6c 6f 67 40 20 28 20 2d  ..: msg-log@ ( -
0750: 2d 20 61 64 64 72 20 75 20 29 0a 20 20 20 20 5b  - addr u ).    [
0760: 3a 20 6d 73 67 2d 67 72 6f 75 70 2d 6f 20 2e 6d  : msg-group-o .m
0770: 73 67 3a 6c 6f 67 5b 5d 20 24 40 20 73 61 76 65  sg:log[] $@ save
0780: 2d 6d 65 6d 20 3b 5d 20 6d 73 67 6c 6f 67 2d 73  -mem ;] msglog-s
0790: 65 6d 61 20 63 2d 73 65 63 74 69 6f 6e 20 3b 0a  ema c-section ;.
07a0: 0a 3a 20 70 75 72 67 65 2d 6c 6f 67 20 28 20 2d  .: purge-log ( -
07b0: 2d 20 29 0a 20 20 20 20 5b 3a 20 6d 73 67 2d 67  - ).    [: msg-g
07c0: 72 6f 75 70 2d 6f 20 2e 6d 73 67 3a 6c 6f 67 5b  roup-o .msg:log[
07d0: 5d 20 7b 20 61 5b 5d 20 7d 0a 09 30 20 20 42 45  ] { a[] }..0  BE
07e0: 47 49 4e 20 20 64 75 70 20 61 5b 5d 20 24 5b 5d  GIN  dup a[] $[]
07f0: 23 20 75 3c 20 20 57 48 49 4c 45 0a 09 09 64 75  # u<  WHILE...du
0800: 70 20 61 5b 5d 20 24 5b 5d 40 20 63 68 65 63 6b  p a[] $[]@ check
0810: 2d 64 61 74 65 20 6e 69 70 20 6e 69 70 20 49 46  -date nip nip IF
0820: 0a 09 09 20 20 20 20 64 75 70 20 61 5b 5d 20 24  ...    dup a[] $
0830: 5b 5d 20 24 66 72 65 65 0a 09 09 20 20 20 20 61  [] $free...    a
0840: 5b 5d 20 6f 76 65 72 20 63 65 6c 6c 73 20 63 65  [] over cells ce
0850: 6c 6c 20 24 64 65 6c 0a 09 09 45 4c 53 45 0a 09  ll $del...ELSE..
0860: 09 20 20 20 20 31 2b 0a 09 09 54 48 45 4e 0a 09  .    1+...THEN..
0870: 52 45 50 45 41 54 20 20 64 72 6f 70 20 3b 5d 20  REPEAT  drop ;] 
0880: 6d 73 67 6c 6f 67 2d 73 65 6d 61 20 63 2d 73 65  msglog-sema c-se
0890: 63 74 69 6f 6e 20 3b 0a 0a 3a 20 73 65 72 69 61  ction ;..: seria
08a0: 6c 69 7a 65 2d 6c 6f 67 20 28 20 61 64 64 72 20  lize-log ( addr 
08b0: 75 20 2d 2d 20 24 61 64 64 72 20 29 0a 20 20 20  u -- $addr ).   
08c0: 20 5b 3a 20 62 6f 75 6e 64 73 20 3f 44 4f 0a 09   [: bounds ?DO..
08d0: 20 20 20 20 49 20 24 40 20 63 68 65 63 6b 2d 64      I $@ check-d
08e0: 61 74 65 20 30 3d 20 49 46 20 20 6e 65 74 32 6f  ate 0= IF  net2o
08f0: 2d 62 61 73 65 3a 24 2c 20 6e 65 74 32 6f 2d 62  -base:$, net2o-b
0900: 61 73 65 3a 6e 65 73 74 73 69 67 0a 09 20 20 20  ase:nestsig..   
0910: 20 45 4c 53 45 20 20 20 6d 73 67 28 20 2e 22 20   ELSE   msg( ." 
0920: 72 65 6d 6f 76 65 64 20 65 6e 74 72 79 20 22 20  removed entry " 
0930: 64 75 6d 70 20 29 65 6c 73 65 28 20 32 64 72 6f  dump )else( 2dro
0940: 70 20 29 20 20 54 48 45 4e 0a 20 20 20 20 20 20  p )  THEN.      
0950: 63 65 6c 6c 20 2b 4c 4f 4f 50 20 3b 5d 0a 20 20  cell +LOOP ;].  
0960: 20 20 67 65 6e 2d 63 6d 64 20 3b 0a 0a 56 61 72    gen-cmd ;..Var
0970: 69 61 62 6c 65 20 73 61 76 65 64 2d 6d 73 67 24  iable saved-msg$
0980: 0a 36 34 56 61 72 69 61 62 6c 65 20 73 61 76 65  .64Variable save
0990: 64 2d 6d 73 67 2d 74 69 63 6b 73 0a 0a 3a 20 73  d-msg-ticks..: s
09a0: 61 76 65 2d 6d 73 67 73 20 28 20 67 72 6f 75 70  ave-msgs ( group
09b0: 2d 6f 20 2d 2d 20 29 20 74 6f 20 6d 73 67 2d 67  -o -- ) to msg-g
09c0: 72 6f 75 70 2d 6f 0a 20 20 20 20 6d 73 67 28 20  roup-o.    msg( 
09d0: 2e 22 20 53 61 76 65 20 6d 65 73 73 61 67 65 73  ." Save messages
09e0: 20 69 6e 20 67 72 6f 75 70 20 22 20 6d 73 67 2d   in group " msg-
09f0: 67 72 6f 75 70 2d 6f 20 64 75 70 20 68 65 78 2e  group-o dup hex.
0a00: 20 2e 6d 73 67 3a 6e 61 6d 65 24 20 74 79 70 65   .msg:name$ type
0a10: 20 63 72 20 29 0a 20 20 20 20 3f 2e 6e 65 74 32   cr ).    ?.net2
0a20: 6f 2f 63 68 61 74 73 20 20 6e 65 74 32 6f 3a 6e  o/chats  net2o:n
0a30: 65 77 2d 6d 73 67 69 6e 67 20 3e 6f 0a 20 20 20  ew-msging >o.   
0a40: 20 6d 73 67 2d 6c 6f 67 40 20 6f 76 65 72 20 3e   msg-log@ over >
0a50: 72 20 20 73 65 72 69 61 6c 69 7a 65 2d 6c 6f 67  r  serialize-log
0a60: 20 65 6e 63 2d 66 69 6c 65 20 24 21 62 75 66 0a   enc-file $!buf.
0a70: 20 20 20 20 72 3e 20 66 72 65 65 20 74 68 72 6f      r> free thro
0a80: 77 20 20 64 69 73 70 6f 73 65 20 6f 3e 0a 20 20  w  dispose o>.  
0a90: 20 20 6d 73 67 2d 67 72 6f 75 70 2d 6f 20 2e 6d    msg-group-o .m
0aa0: 73 67 3a 6e 61 6d 65 24 20 3e 63 68 61 74 69 64  sg:name$ >chatid
0ab0: 20 2e 63 68 61 74 73 2f 20 65 6e 63 2d 66 69 6c   .chats/ enc-fil
0ac0: 65 6e 61 6d 65 20 24 21 0a 20 20 20 20 70 6b 2d  ename $!.    pk-
0ad0: 6f 66 66 20 20 6b 65 79 2d 6c 69 73 74 20 65 6e  off  key-list en
0ae0: 63 66 69 6c 65 2d 72 65 73 74 20 3b 0a 0a 3a 20  cfile-rest ;..: 
0af0: 73 61 76 65 2d 61 6c 6c 2d 6d 73 67 73 20 28 20  save-all-msgs ( 
0b00: 2d 2d 20 29 0a 20 20 20 20 73 61 76 65 64 2d 6d  -- ).    saved-m
0b10: 73 67 24 20 24 40 20 62 6f 75 6e 64 73 20 3f 44  sg$ $@ bounds ?D
0b20: 4f 20 20 49 20 40 20 73 61 76 65 2d 6d 73 67 73  O  I @ save-msgs
0b30: 20 20 63 65 6c 6c 20 2b 4c 4f 4f 50 0a 20 20 20    cell +LOOP.   
0b40: 20 73 61 76 65 64 2d 6d 73 67 24 20 24 66 72 65   saved-msg$ $fre
0b50: 65 20 3b 0a 0a 3a 20 73 61 76 65 2d 6d 73 67 73  e ;..: save-msgs
0b60: 3f 20 28 20 2d 2d 20 29 0a 20 20 20 20 73 61 76  ? ( -- ).    sav
0b70: 65 64 2d 6d 73 67 2d 74 69 63 6b 73 20 36 34 40  ed-msg-ticks 64@
0b80: 20 74 69 63 6b 65 72 20 36 34 40 20 36 34 75 3c   ticker 64@ 64u<
0b90: 3d 20 49 46 20 20 73 61 76 65 2d 61 6c 6c 2d 6d  = IF  save-all-m
0ba0: 73 67 73 0a 09 74 69 63 6b 73 20 63 6f 6e 66 69  sgs..ticks confi
0bb0: 67 3a 73 61 76 65 64 65 6c 74 61 26 20 32 40 20  g:savedelta& 2@ 
0bc0: 64 3e 36 34 20 36 34 2b 20 73 61 76 65 64 2d 6d  d>64 64+ saved-m
0bd0: 73 67 2d 74 69 63 6b 73 20 36 34 21 20 20 54 48  sg-ticks 64!  TH
0be0: 45 4e 20 3b 0a 0a 3a 20 6e 65 78 74 2d 73 61 76  EN ;..: next-sav
0bf0: 65 64 2d 6d 73 67 20 28 20 2d 2d 20 74 69 6d 65  ed-msg ( -- time
0c00: 20 29 0a 20 20 20 20 73 61 76 65 64 2d 6d 73 67   ).    saved-msg
0c10: 2d 74 69 63 6b 73 20 36 34 40 20 36 34 64 75 70  -ticks 64@ 64dup
0c20: 20 36 34 23 30 20 36 34 3d 20 49 46 0a 09 36 34   64#0 64= IF..64
0c30: 64 72 6f 70 20 74 69 63 6b 73 20 36 34 64 75 70  drop ticks 64dup
0c40: 20 73 61 76 65 64 2d 6d 73 67 2d 74 69 63 6b 73   saved-msg-ticks
0c50: 20 36 34 21 20 20 54 48 45 4e 20 3b 0a 0a 3a 20   64!  THEN ;..: 
0c60: 6d 73 67 2d 65 76 61 6c 20 28 20 61 64 64 72 20  msg-eval ( addr 
0c70: 75 20 2d 2d 20 29 0a 20 20 20 20 6e 65 74 32 6f  u -- ).    net2o
0c80: 3a 6e 65 77 2d 6d 73 67 69 6e 67 20 3e 6f 20 30  :new-msging >o 0
0c90: 20 74 6f 20 70 61 72 65 6e 74 20 64 6f 2d 63 6d   to parent do-cm
0ca0: 64 2d 6c 6f 6f 70 20 64 69 73 70 6f 73 65 20 6f  d-loop dispose o
0cb0: 3e 20 3b 0a 0a 3a 20 6c 6f 61 64 2d 6d 73 67 20  > ;..: load-msg 
0cc0: 28 20 67 72 6f 75 70 20 75 20 2d 2d 20 29 20 20  ( group u -- )  
0cd0: 32 64 75 70 20 3e 67 72 6f 75 70 0a 20 20 20 20  2dup >group.    
0ce0: 3e 63 68 61 74 69 64 20 2e 63 68 61 74 73 2f 20  >chatid .chats/ 
0cf0: 5b 3a 20 74 79 70 65 20 2e 22 20 2e 76 32 6f 22  [: type ." .v2o"
0d00: 20 3b 5d 20 24 74 6d 70 0a 20 20 20 20 32 64 75   ;] $tmp.    2du
0d10: 70 20 66 69 6c 65 2d 73 74 61 74 75 73 20 6e 69  p file-status ni
0d20: 70 20 6e 6f 2d 66 69 6c 65 23 20 3d 20 49 46 20  p no-file# = IF 
0d30: 20 32 64 72 6f 70 20 45 58 49 54 20 20 54 48 45   2drop EXIT  THE
0d40: 4e 0a 20 20 20 20 72 65 70 6c 61 79 2d 6d 6f 64  N.    replay-mod
0d50: 65 20 6f 6e 20 20 73 6b 69 70 2d 73 69 67 3f 20  e on  skip-sig? 
0d60: 6f 6e 0a 20 20 20 20 5b 27 5d 20 64 65 63 72 79  on.    ['] decry
0d70: 70 74 40 20 63 61 74 63 68 0a 20 20 20 20 3f 64  pt@ catch.    ?d
0d80: 75 70 2d 49 46 20 20 44 6f 45 72 72 6f 72 20 32  up-IF  DoError 2
0d90: 64 72 6f 70 0a 09 5c 20 74 72 79 20 72 65 61 64  drop..\ try read
0da0: 20 62 61 63 6b 75 70 20 69 6e 73 74 65 61 64 0a   backup instead.
0db0: 09 5b 3a 20 65 6e 63 2d 66 69 6c 65 6e 61 6d 65  .[: enc-filename
0dc0: 20 24 2e 20 27 7e 27 20 65 6d 69 74 20 3b 5d 20   $. '~' emit ;] 
0dd0: 24 74 6d 70 20 5b 27 5d 20 64 65 63 72 79 70 74  $tmp ['] decrypt
0de0: 40 20 63 61 74 63 68 0a 09 3f 64 75 70 2d 49 46  @ catch..?dup-IF
0df0: 20 20 44 6f 45 72 72 6f 72 20 32 64 72 6f 70 0a    DoError 2drop.
0e00: 09 45 4c 53 45 20 20 6d 73 67 2d 65 76 61 6c 20  .ELSE  msg-eval 
0e10: 20 54 48 45 4e 0a 20 20 20 20 45 4c 53 45 20 20   THEN.    ELSE  
0e20: 6d 73 67 2d 65 76 61 6c 20 20 54 48 45 4e 0a 20  msg-eval  THEN. 
0e30: 20 20 20 72 65 70 6c 61 79 2d 6d 6f 64 65 20 6f     replay-mode o
0e40: 66 66 20 20 73 6b 69 70 2d 73 69 67 3f 20 6f 66  ff  skip-sig? of
0e50: 66 20 20 65 6e 63 2d 66 69 6c 65 20 24 66 72 65  f  enc-file $fre
0e60: 65 20 3b 0a 0a 65 76 65 6e 74 3a 20 3a 3e 73 61  e ;..event: :>sa
0e70: 76 65 2d 6d 73 67 73 20 28 20 67 72 6f 75 70 2d  ve-msgs ( group-
0e80: 6f 20 2d 2d 20 29 20 73 61 76 65 64 2d 6d 73 67  o -- ) saved-msg
0e90: 24 20 2b 75 6e 69 71 75 65 24 20 3b 0a 65 76 65  $ +unique$ ;.eve
0ea0: 6e 74 3a 20 3a 3e 73 61 76 65 2d 61 6c 6c 2d 6d  nt: :>save-all-m
0eb0: 73 67 73 20 28 20 2d 2d 20 29 0a 20 20 20 20 73  sgs ( -- ).    s
0ec0: 61 76 65 2d 61 6c 6c 2d 6d 73 67 73 20 3b 0a 65  ave-all-msgs ;.e
0ed0: 76 65 6e 74 3a 20 3a 3e 6c 6f 61 64 2d 6d 73 67  vent: :>load-msg
0ee0: 20 28 20 67 72 6f 75 70 2d 6f 20 2d 2d 20 29 0a   ( group-o -- ).
0ef0: 20 20 20 20 2e 6d 73 67 3a 6e 61 6d 65 24 20 6c      .msg:name$ l
0f00: 6f 61 64 2d 6d 73 67 20 3b 0a 0a 3a 20 3e 6c 6f  oad-msg ;..: >lo
0f10: 61 64 2d 67 72 6f 75 70 20 28 20 67 72 6f 75 70  ad-group ( group
0f20: 20 75 20 2d 2d 20 29 0a 20 20 20 20 3e 67 72 6f   u -- ).    >gro
0f30: 75 70 20 6d 73 67 2d 67 72 6f 75 70 2d 6f 20 2e  up msg-group-o .
0f40: 6d 73 67 3a 6c 6f 67 5b 5d 20 24 40 6c 65 6e 20  msg:log[] $@len 
0f50: 30 3d 0a 20 20 20 20 49 46 20 20 3c 65 76 65 6e  0=.    IF  <even
0f60: 74 20 6d 73 67 2d 67 72 6f 75 70 2d 6f 20 65 6c  t msg-group-o el
0f70: 69 74 2c 20 3a 3e 6c 6f 61 64 2d 6d 73 67 0a 09  it, :>load-msg..
0f80: 70 61 72 65 6e 74 20 2e 77 61 69 74 2d 74 61 73  parent .wait-tas
0f90: 6b 20 40 0a 09 64 75 70 20 30 3d 20 49 46 20 20  k @..dup 0= IF  
0fa0: 64 72 6f 70 20 3f 66 69 6c 65 2d 74 61 73 6b 20  drop ?file-task 
0fb0: 20 54 48 45 4e 20 20 65 76 65 6e 74 3e 20 20 54   THEN  event>  T
0fc0: 48 45 4e 20 3b 0a 0a 3a 20 21 73 61 76 65 2d 61  HEN ;..: !save-a
0fd0: 6c 6c 2d 6d 73 67 73 20 28 20 2d 2d 20 29 0a 20  ll-msgs ( -- ). 
0fe0: 20 20 20 73 79 6e 63 66 69 6c 65 28 20 73 61 76     syncfile( sav
0ff0: 65 2d 61 6c 6c 2d 6d 73 67 73 20 29 65 6c 73 65  e-all-msgs )else
1000: 28 0a 20 20 20 20 3c 65 76 65 6e 74 20 3a 3e 73  (.    <event :>s
1010: 61 76 65 2d 61 6c 6c 2d 6d 73 67 73 20 3f 66 69  ave-all-msgs ?fi
1020: 6c 65 2d 74 61 73 6b 20 65 76 65 6e 74 7c 20 29  le-task event| )
1030: 20 3b 0a 0a 3a 20 73 61 76 65 2d 6d 73 67 73 26   ;..: save-msgs&
1040: 20 28 20 2d 2d 20 29 0a 20 20 20 20 73 79 6e 63   ( -- ).    sync
1050: 66 69 6c 65 28 20 6d 73 67 2d 67 72 6f 75 70 2d  file( msg-group-
1060: 6f 20 73 61 76 65 64 2d 6d 73 67 24 20 2b 75 6e  o saved-msg$ +un
1070: 69 71 75 65 24 20 29 65 6c 73 65 28 0a 20 20 20  ique$ )else(.   
1080: 20 3c 65 76 65 6e 74 20 6d 73 67 2d 67 72 6f 75   <event msg-grou
1090: 70 2d 6f 20 65 6c 69 74 2c 20 3a 3e 73 61 76 65  p-o elit, :>save
10a0: 2d 6d 73 67 73 20 3f 66 69 6c 65 2d 74 61 73 6b  -msgs ?file-task
10b0: 20 65 76 65 6e 74 3e 20 29 20 3b 0a 0a 30 20 56   event> ) ;..0 V
10c0: 61 6c 75 65 20 6c 6f 67 23 0a 32 56 61 72 69 61  alue log#.2Varia
10d0: 62 6c 65 20 6c 61 73 74 2d 6d 73 67 0a 0a 3a 20  ble last-msg..: 
10e0: 2b 6d 73 67 2d 6c 6f 67 20 28 20 61 64 64 72 20  +msg-log ( addr 
10f0: 75 20 2d 2d 20 61 64 64 72 27 20 75 27 20 2f 20  u -- addr' u' / 
1100: 30 20 30 20 29 0a 20 20 20 20 5b 3a 20 6d 73 67  0 0 ).    [: msg
1110: 2d 67 72 6f 75 70 2d 6f 20 2e 6d 73 67 3a 6c 6f  -group-o .msg:lo
1120: 67 5b 5d 20 24 69 6e 73 5b 5d 64 61 74 65 20 20  g[] $ins[]date  
1130: 64 75 70 20 20 64 75 70 20 30 3c 20 78 6f 72 20  dup  dup 0< xor 
1140: 74 6f 20 6c 6f 67 23 0a 09 6c 6f 67 23 20 6d 73  to log#..log# ms
1150: 67 2d 67 72 6f 75 70 2d 6f 20 2e 6d 73 67 3a 6c  g-group-o .msg:l
1160: 6f 67 5b 5d 20 24 5b 5d 40 20 6c 61 73 74 2d 6d  og[] $[]@ last-m
1170: 73 67 20 32 21 0a 09 30 3c 20 49 46 20 20 23 30  sg 2!..0< IF  #0
1180: 2e 20 20 45 4c 53 45 20 20 6c 61 73 74 2d 6d 73  .  ELSE  last-ms
1190: 67 20 32 40 20 20 54 48 45 4e 0a 20 20 20 20 3b  g 2@  THEN.    ;
11a0: 5d 20 6d 73 67 6c 6f 67 2d 73 65 6d 61 20 63 2d  ] msglog-sema c-
11b0: 73 65 63 74 69 6f 6e 20 3b 0a 3a 20 3f 73 61 76  section ;.: ?sav
11c0: 65 2d 6d 73 67 20 28 20 2d 2d 20 29 0a 20 20 20  e-msg ( -- ).   
11d0: 20 6d 73 67 28 20 2e 22 20 73 61 76 69 6e 67 20   msg( ." saving 
11e0: 6d 65 73 73 61 67 65 73 20 69 6e 20 67 72 6f 75  messages in grou
11f0: 70 20 22 20 6d 73 67 2d 67 72 6f 75 70 2d 6f 20  p " msg-group-o 
1200: 64 75 70 20 68 65 78 2e 20 2e 6d 73 67 3a 6e 61  dup hex. .msg:na
1210: 6d 65 24 20 74 79 70 65 20 63 72 20 29 0a 20 20  me$ type cr ).  
1220: 20 20 6d 73 67 2d 67 72 6f 75 70 2d 6f 20 2e 6d    msg-group-o .m
1230: 73 67 3a 3f 6f 74 72 20 72 65 70 6c 61 79 2d 6d  sg:?otr replay-m
1240: 6f 64 65 20 40 20 6f 72 20 30 3d 20 49 46 20 20  ode @ or 0= IF  
1250: 73 61 76 65 2d 6d 73 67 73 26 20 20 54 48 45 4e  save-msgs&  THEN
1260: 20 3b 0a 0a 53 65 6d 61 20 71 75 65 75 65 2d 73   ;..Sema queue-s
1270: 65 6d 61 0a 0a 5c 20 70 65 65 72 20 71 75 65 75  ema..\ peer queu
1280: 65 2c 20 69 6e 20 6d 73 67 20 63 6f 6e 74 65 78  e, in msg contex
1290: 74 0a 0a 3a 20 70 65 65 72 3e 20 28 20 2d 2d 20  t..: peer> ( -- 
12a0: 61 64 64 72 20 2f 20 30 20 29 0a 20 20 20 20 5b  addr / 0 ).    [
12b0: 3a 20 6d 73 67 3a 70 65 65 72 73 5b 5d 20 62 61  : msg:peers[] ba
12c0: 63 6b 3e 20 3b 5d 20 71 75 65 75 65 2d 73 65 6d  ck> ;] queue-sem
12d0: 61 20 63 2d 73 65 63 74 69 6f 6e 20 3b 0a 3a 20  a c-section ;.: 
12e0: 3e 70 65 65 72 20 28 20 61 64 64 72 20 75 20 2d  >peer ( addr u -
12f0: 2d 20 29 0a 20 20 20 20 5b 3a 20 6d 73 67 3a 70  - ).    [: msg:p
1300: 65 65 72 73 5b 5d 20 24 2b 5b 5d 21 20 3b 5d 20  eers[] $+[]! ;] 
1310: 71 75 65 75 65 2d 73 65 6d 61 20 63 2d 73 65 63  queue-sema c-sec
1320: 74 69 6f 6e 20 3b 0a 0a 5c 20 65 76 65 6e 74 73  tion ;..\ events
1330: 0a 0a 6d 73 67 2d 63 6c 61 73 73 20 63 6c 61 73  ..msg-class clas
1340: 73 20 65 6e 64 2d 63 6c 61 73 73 20 6d 73 67 2d  s end-class msg-
1350: 6e 6f 74 69 66 79 2d 63 6c 61 73 73 0a 0a 6d 73  notify-class..ms
1360: 67 2d 6e 6f 74 69 66 79 2d 63 6c 61 73 73 20 27  g-notify-class '
1370: 20 6e 65 77 20 73 74 61 74 69 63 2d 61 20 77 69   new static-a wi
1380: 74 68 2d 61 6c 6c 6f 63 61 74 65 72 20 43 6f 6e  th-allocater Con
1390: 73 74 61 6e 74 20 6d 73 67 2d 6e 6f 74 69 66 79  stant msg-notify
13a0: 2d 6f 0a 0a 3a 20 3e 6d 73 67 2d 6c 6f 67 20 28  -o..: >msg-log (
13b0: 20 61 64 64 72 20 75 20 2d 2d 20 61 64 64 72 27   addr u -- addr'
13c0: 20 75 20 29 0a 20 20 20 20 2b 6d 73 67 2d 6c 6f   u ).    +msg-lo
13d0: 67 20 3f 73 61 76 65 2d 6d 73 67 20 3b 0a 0a 3a  g ?save-msg ;..:
13e0: 20 64 6f 2d 6d 73 67 2d 6e 65 73 74 73 69 67 20   do-msg-nestsig 
13f0: 28 20 61 64 64 72 20 75 20 2d 2d 20 29 0a 20 20  ( addr u -- ).  
1400: 20 20 32 64 75 70 20 6d 73 67 2d 67 72 6f 75 70    2dup msg-group
1410: 2d 6f 20 2e 6d 73 67 3a 64 69 73 70 6c 61 79 0a  -o .msg:display.
1420: 20 20 20 20 6d 73 67 2d 6e 6f 74 69 66 79 2d 6f      msg-notify-o
1430: 20 2e 6d 73 67 3a 64 69 73 70 6c 61 79 20 3b 0a   .msg:display ;.
1440: 0a 3a 20 64 69 73 70 6c 61 79 2d 6c 61 73 74 6e  .: display-lastn
1450: 20 28 20 6e 20 2d 2d 20 29 0a 20 20 20 20 6d 73   ( n -- ).    ms
1460: 67 2d 67 72 6f 75 70 2d 6f 20 2e 6d 73 67 3a 72  g-group-o .msg:r
1470: 65 64 69 73 70 6c 61 79 20 3b 0a 3a 20 64 69 73  edisplay ;.: dis
1480: 70 6c 61 79 2d 73 79 6e 63 2d 64 6f 6e 65 20 28  play-sync-done (
1490: 20 2d 2d 20 29 0a 20 20 20 20 72 6f 77 73 20 20   -- ).    rows  
14a0: 6d 73 67 2d 67 72 6f 75 70 2d 6f 20 2e 6d 73 67  msg-group-o .msg
14b0: 3a 72 65 64 69 73 70 6c 61 79 20 3b 0a 0a 3a 20  :redisplay ;..: 
14c0: 64 69 73 70 6c 61 79 2d 6f 6e 65 2d 6d 73 67 20  display-one-msg 
14d0: 7b 20 64 3a 20 6d 73 67 74 20 2d 2d 20 7d 0a 20  { d: msgt -- }. 
14e0: 20 20 20 6d 73 67 2d 67 72 6f 75 70 2d 6f 20 3e     msg-group-o >
14f0: 6f 0a 20 20 20 20 6d 73 67 74 20 5b 27 5d 20 6d  o.    msgt ['] m
1500: 73 67 3a 64 69 73 70 6c 61 79 20 63 61 74 63 68  sg:display catch
1510: 20 49 46 20 20 2e 22 20 69 6e 76 61 6c 69 64 20   IF  ." invalid 
1520: 65 6e 74 72 79 22 20 20 63 72 20 20 32 64 72 6f  entry"  cr  2dro
1530: 70 20 20 54 48 45 4e 0a 20 20 20 20 6f 3e 20 3b  p  THEN.    o> ;
1540: 0a 0a 46 6f 72 77 61 72 64 20 73 69 6c 65 6e 74  ..Forward silent
1550: 2d 6a 6f 69 6e 0a 0a 5c 20 21 21 46 49 58 4d 45  -join..\ !!FIXME
1560: 21 21 20 73 68 6f 75 6c 64 20 75 73 65 20 61 6e  !! should use an
1570: 20 61 73 79 6e 63 68 72 6f 6e 6f 75 73 20 22 64   asynchronous "d
1580: 6f 2d 77 68 65 6e 2d 63 6f 6e 6e 65 63 74 65 64  o-when-connected
1590: 22 20 74 68 69 6e 67 0a 0a 3a 20 2b 75 6e 69 71  " thing..: +uniq
15a0: 75 65 2d 63 6f 6e 20 28 20 2d 2d 20 29 20 6f 20  ue-con ( -- ) o 
15b0: 6d 73 67 2d 67 72 6f 75 70 2d 6f 20 2e 6d 73 67  msg-group-o .msg
15c0: 3a 70 65 65 72 73 5b 5d 20 2b 75 6e 69 71 75 65  :peers[] +unique
15d0: 24 20 3b 0a 46 6f 72 77 61 72 64 20 2b 63 68 61  $ ;.Forward +cha
15e0: 74 2d 63 6f 6e 74 72 6f 6c 0a 0a 3a 20 63 68 61  t-control..: cha
15f0: 74 2d 73 69 6c 65 6e 74 2d 6a 6f 69 6e 20 28 20  t-silent-join ( 
1600: 2d 2d 20 29 0a 20 20 20 20 72 65 63 6f 6e 6e 65  -- ).    reconne
1610: 63 74 28 20 2e 22 20 73 69 6c 65 6e 74 20 6a 6f  ct( ." silent jo
1620: 69 6e 20 22 20 6f 20 68 65 78 2e 20 63 6f 6e 6e  in " o hex. conn
1630: 65 63 74 69 6f 6e 20 68 65 78 2e 20 63 72 20 29  ection hex. cr )
1640: 0a 20 20 20 20 6f 20 74 6f 20 63 6f 6e 6e 65 63  .    o to connec
1650: 74 69 6f 6e 0a 20 20 20 20 3f 6d 73 67 2d 63 6f  tion.    ?msg-co
1660: 6e 74 65 78 74 20 3e 6f 20 73 69 6c 65 6e 74 2d  ntext >o silent-
1670: 6c 61 73 74 23 20 40 20 74 6f 20 6c 61 73 74 23  last# @ to last#
1680: 20 6f 3e 0a 20 20 20 20 72 65 63 6f 6e 6e 65 63   o>.    reconnec
1690: 74 28 20 2e 22 20 6a 6f 69 6e 3a 20 22 20 6c 61  t( ." join: " la
16a0: 73 74 23 20 24 2e 20 63 72 20 29 0a 20 20 20 20  st# $. cr ).    
16b0: 2b 75 6e 69 71 75 65 2d 63 6f 6e 20 73 69 6c 65  +unique-con sile
16c0: 6e 74 2d 6a 6f 69 6e 20 3b 0a 0a 3a 20 63 68 61  nt-join ;..: cha
16d0: 74 2d 73 69 6c 65 6e 74 2d 72 71 64 20 28 20 6e  t-silent-rqd ( n
16e0: 20 2d 2d 20 29 0a 20 20 20 20 72 65 63 6f 6e 6e   -- ).    reconn
16f0: 65 63 74 28 20 2e 22 20 73 69 6c 65 6e 74 20 72  ect( ." silent r
1700: 65 71 75 73 74 22 20 63 72 20 29 0a 20 20 20 20  equst" cr ).    
1710: 63 6c 65 61 6e 2d 72 65 71 75 65 73 74 20 63 68  clean-request ch
1720: 61 74 2d 73 69 6c 65 6e 74 2d 6a 6f 69 6e 20 3b  at-silent-join ;
1730: 0a 0a 3a 20 3f 6e 61 74 20 28 20 2d 2d 20 29 20  ..: ?nat ( -- ) 
1740: 20 6f 20 74 6f 20 63 6f 6e 6e 65 63 74 69 6f 6e   o to connection
1750: 0a 20 20 20 20 6e 65 74 32 6f 2d 63 6f 64 65 20  .    net2o-code 
1760: 6e 61 74 2d 70 75 6e 63 68 20 65 6e 64 2d 63 6f  nat-punch end-co
1770: 64 65 20 3b 0a 0a 3a 20 3f 63 68 61 74 2d 6e 61  de ;..: ?chat-na
1780: 74 20 28 20 2d 2d 20 29 0a 20 20 20 20 5b 27 5d  t ( -- ).    [']
1790: 20 63 68 61 74 2d 73 69 6c 65 6e 74 2d 72 71 64   chat-silent-rqd
17a0: 20 72 71 64 21 20 3f 6e 61 74 20 3b 0a 0a 3a 20   rqd! ?nat ;..: 
17b0: 63 68 61 74 2d 72 71 64 2d 6e 61 74 20 28 20 6e  chat-rqd-nat ( n
17c0: 20 2d 2d 20 29 0a 20 20 20 20 72 65 63 6f 6e 6e   -- ).    reconn
17d0: 65 63 74 28 20 2e 22 20 63 68 61 74 20 72 65 71  ect( ." chat req
17e0: 20 64 6f 6e 65 2c 20 73 74 61 72 74 20 6e 61 74   done, start nat
17f0: 20 74 72 61 76 65 72 73 61 6c 22 20 63 72 20 29   traversal" cr )
1800: 0a 20 20 20 20 63 6f 6e 6e 65 63 74 2d 72 65 73  .    connect-res
1810: 74 20 20 2b 66 6c 6f 77 2d 63 6f 6e 74 72 6f 6c  t  +flow-control
1820: 20 2b 72 65 73 65 6e 64 20 3f 63 68 61 74 2d 6e   +resend ?chat-n
1830: 61 74 20 3b 0a 0a 3a 20 63 68 61 74 2d 72 71 64  at ;..: chat-rqd
1840: 2d 6e 6f 6e 61 74 20 28 20 6e 20 2d 2d 20 29 0a  -nonat ( n -- ).
1850: 20 20 20 20 72 65 63 6f 6e 6e 65 63 74 28 20 2e      reconnect( .
1860: 22 20 63 68 61 74 20 72 65 71 20 64 6f 6e 65 2c  " chat req done,
1870: 20 73 74 61 72 74 20 73 69 6c 65 6e 74 20 6a 6f   start silent jo
1880: 69 6e 22 20 63 72 20 29 0a 20 20 20 20 63 6f 6e  in" cr ).    con
1890: 6e 65 63 74 2d 72 65 73 74 20 20 2b 66 6c 6f 77  nect-rest  +flow
18a0: 2d 63 6f 6e 74 72 6f 6c 20 2b 72 65 73 65 6e 64  -control +resend
18b0: 20 63 68 61 74 2d 73 69 6c 65 6e 74 2d 6a 6f 69   chat-silent-joi
18c0: 6e 20 3b 0a 0a 55 73 65 72 20 70 65 65 72 2d 62  n ;..User peer-b
18d0: 75 66 0a 0a 3a 20 72 65 63 6f 6e 6e 65 63 74 2d  uf..: reconnect-
18e0: 63 68 61 74 20 28 20 61 64 64 72 20 75 20 24 63  chat ( addr u $c
18f0: 68 61 74 20 2d 2d 20 29 0a 20 20 20 20 70 65 65  hat -- ).    pee
1900: 72 2d 62 75 66 20 24 21 62 75 66 20 20 6c 61 73  r-buf $!buf  las
1910: 74 23 20 70 65 65 72 2d 62 75 66 20 24 40 0a 20  t# peer-buf $@. 
1920: 20 20 20 72 65 63 6f 6e 6e 65 63 74 28 20 2e 22     reconnect( ."
1930: 20 72 65 63 6f 6e 6e 65 63 74 20 22 20 32 64 75   reconnect " 2du
1940: 70 20 32 64 75 70 20 2b 20 31 2d 20 63 40 20 31  p 2dup + 1- c@ 1
1950: 2b 20 2d 20 2e 61 64 64 72 24 20 63 72 20 29 0a  + - .addr$ cr ).
1960: 20 20 20 20 72 65 63 6f 6e 6e 65 63 74 28 20 2e      reconnect( .
1970: 22 20 69 6e 20 67 72 6f 75 70 3a 20 22 20 6c 61  " in group: " la
1980: 73 74 23 20 64 75 70 20 68 65 78 2e 20 24 2e 20  st# dup hex. $. 
1990: 63 72 20 29 0a 20 20 20 20 30 20 3e 6f 20 24 41  cr ).    0 >o $A
19a0: 20 24 41 20 5b 3a 20 72 65 63 6f 6e 6e 65 63 74   $A [: reconnect
19b0: 28 20 2e 22 20 70 72 65 70 61 72 65 20 72 65 63  ( ." prepare rec
19c0: 6f 6e 6e 65 63 74 69 6f 6e 22 20 63 72 20 29 0a  onnection" cr ).
19d0: 20 20 20 20 20 20 3f 6d 73 67 2d 63 6f 6e 74 65        ?msg-conte
19e0: 78 74 20 3e 6f 20 73 69 6c 65 6e 74 2d 6c 61 73  xt >o silent-las
19f0: 74 23 20 21 20 6f 3e 0a 20 20 20 20 20 20 5b 27  t# ! o>.      ['
1a00: 5d 20 63 68 61 74 2d 72 71 64 2d 6e 61 74 20 5b  ] chat-rqd-nat [
1a10: 27 5d 20 63 68 61 74 2d 72 71 64 2d 6e 6f 6e 61  '] chat-rqd-nona
1a20: 74 20 69 6e 64 2d 61 64 64 72 20 40 20 73 65 6c  t ind-addr @ sel
1a30: 65 63 74 20 72 71 64 21 20 3b 5d 0a 20 20 20 20  ect rqd! ;].    
1a40: 61 64 64 72 2d 63 6f 6e 6e 65 63 74 20 32 64 75  addr-connect 2du
1a50: 70 20 64 30 3d 20 49 46 20 20 32 64 72 6f 70 20  p d0= IF  2drop 
1a60: 20 45 4c 53 45 20 20 61 76 61 6c 61 6e 63 68 65   ELSE  avalanche
1a70: 2d 74 6f 20 20 54 48 45 4e 20 6f 3e 20 3b 0a 0a  -to  THEN o> ;..
1a80: 65 76 65 6e 74 3a 20 3a 3e 61 76 61 6c 61 6e 63  event: :>avalanc
1a90: 68 65 20 28 20 61 64 64 72 20 75 20 6f 20 67 72  he ( addr u o gr
1aa0: 6f 75 70 20 2d 2d 20 29 0a 20 20 20 20 61 76 61  oup -- ).    ava
1ab0: 6c 61 6e 63 68 65 28 20 2e 22 20 41 76 61 6c 61  lanche( ." Avala
1ac0: 6e 63 68 65 20 74 6f 3a 20 22 20 64 75 70 20 68  nche to: " dup h
1ad0: 65 78 2e 20 63 72 20 29 0a 20 20 20 20 74 6f 20  ex. cr ).    to 
1ae0: 6d 73 67 2d 67 72 6f 75 70 2d 6f 20 2e 61 76 61  msg-group-o .ava
1af0: 6c 61 6e 63 68 65 2d 6d 73 67 20 3b 0a 65 76 65  lanche-msg ;.eve
1b00: 6e 74 3a 20 3a 3e 63 68 61 74 2d 72 65 63 6f 6e  nt: :>chat-recon
1b10: 6e 65 63 74 20 28 20 61 64 64 72 20 75 20 24 63  nect ( addr u $c
1b20: 68 61 74 20 6f 20 67 72 6f 75 70 20 2d 2d 20 29  hat o group -- )
1b30: 0a 20 20 20 20 74 6f 20 6d 73 67 2d 67 72 6f 75  .    to msg-grou
1b40: 70 2d 6f 20 2e 72 65 63 6f 6e 6e 65 63 74 2d 63  p-o .reconnect-c
1b50: 68 61 74 20 3b 0a 65 76 65 6e 74 3a 20 3a 3e 6d  hat ;.event: :>m
1b60: 73 67 2d 6e 65 73 74 73 69 67 20 28 20 24 61 64  sg-nestsig ( $ad
1b70: 64 72 20 6f 20 67 72 6f 75 70 20 2d 2d 20 29 0a  dr o group -- ).
1b80: 20 20 20 20 74 6f 20 6d 73 67 2d 67 72 6f 75 70      to msg-group
1b90: 2d 6f 20 3e 6f 20 7b 20 77 5e 20 6d 20 7d 20 6d  -o >o { w^ m } m
1ba0: 20 24 40 20 64 6f 2d 6d 73 67 2d 6e 65 73 74 73   $@ do-msg-nests
1bb0: 69 67 20 6d 20 24 66 72 65 65 20 6f 3e 0a 20 20  ig m $free o>.  
1bc0: 20 20 63 74 72 6c 20 4c 20 69 6e 73 6b 65 79 20    ctrl L inskey 
1bd0: 3b 0a 0a 5c 20 63 6f 6f 72 64 69 6e 61 74 65 73  ;..\ coordinates
1be0: 0a 0a 36 20 73 66 6c 6f 61 74 73 20 62 75 66 66  ..6 sfloats buff
1bf0: 65 72 3a 20 63 6f 6f 72 64 22 0a 39 30 65 20 63  er: coord".90e c
1c00: 6f 6f 72 64 22 20 73 66 6c 6f 61 74 2b 20 73 66  oord" sfloat+ sf
1c10: 21 0a 3a 20 63 6f 6f 72 64 40 20 28 20 2d 2d 20  !.: coord@ ( -- 
1c20: 61 64 64 72 20 75 20 29 20 63 6f 6f 72 64 22 20  addr u ) coord" 
1c30: 36 20 73 66 6c 6f 61 74 73 20 3b 0a 3a 20 73 66  6 sfloats ;.: sf
1c40: 5b 5d 40 20 28 20 61 64 64 72 20 69 20 2d 2d 20  []@ ( addr i -- 
1c50: 73 66 20 29 20 20 73 66 6c 6f 61 74 73 20 2b 20  sf )  sfloats + 
1c60: 73 66 40 20 3b 0a 3a 20 73 66 5b 5d 21 20 28 20  sf@ ;.: sf[]! ( 
1c70: 61 64 64 72 20 69 20 2d 2d 20 73 66 20 29 20 20  addr i -- sf )  
1c80: 73 66 6c 6f 61 74 73 20 2b 20 73 66 21 20 3b 0a  sfloats + sf! ;.
1c90: 0a 5b 49 46 44 45 46 5d 20 61 6e 64 72 6f 69 64  .[IFDEF] android
1ca0: 0a 20 20 20 20 72 65 71 75 69 72 65 20 75 6e 69  .    require uni
1cb0: 78 2f 6a 6e 69 2d 6c 6f 63 61 74 69 6f 6e 2e 66  x/jni-location.f
1cc0: 73 0a 20 20 20 20 61 6c 73 6f 20 61 6e 64 72 6f  s.    also andro
1cd0: 69 64 0a 20 20 20 20 3a 20 63 6f 6f 72 64 21 20  id.    : coord! 
1ce0: 28 20 2d 2d 20 29 20 6c 6f 63 61 74 69 6f 6e 20  ( -- ) location 
1cf0: 3f 64 75 70 2d 49 46 20 20 3e 6f 0a 09 20 20 20  ?dup-IF  >o..   
1d00: 20 67 65 74 4c 61 74 69 74 75 64 65 20 20 63 6f   getLatitude  co
1d10: 6f 72 64 22 20 30 20 73 66 5b 5d 21 0a 09 20 20  ord" 0 sf[]!..  
1d20: 20 20 67 65 74 4c 6f 6e 67 69 74 75 64 65 20 63    getLongitude c
1d30: 6f 6f 72 64 22 20 31 20 73 66 5b 5d 21 0a 09 20  oord" 1 sf[]!.. 
1d40: 20 20 20 67 65 74 41 6c 74 69 74 75 64 65 20 20     getAltitude  
1d50: 63 6f 6f 72 64 22 20 32 20 73 66 5b 5d 21 0a 09  coord" 2 sf[]!..
1d60: 20 20 20 20 67 65 74 53 70 65 65 64 20 20 20 20      getSpeed    
1d70: 20 63 6f 6f 72 64 22 20 33 20 73 66 5b 5d 21 0a   coord" 3 sf[]!.
1d80: 09 20 20 20 20 67 65 74 42 65 61 72 69 6e 67 20  .    getBearing 
1d90: 20 20 63 6f 6f 72 64 22 20 34 20 73 66 5b 5d 21    coord" 4 sf[]!
1da0: 0a 09 20 20 20 20 67 65 74 41 63 63 75 72 61 63  ..    getAccurac
1db0: 79 20 20 63 6f 6f 72 64 22 20 35 20 73 66 5b 5d  y  coord" 5 sf[]
1dc0: 21 0a 09 20 20 20 20 6f 3e 0a 09 45 4c 53 45 0a  !..    o>..ELSE.
1dd0: 09 20 20 20 20 73 74 61 72 74 2d 67 70 73 0a 09  .    start-gps..
1de0: 54 48 45 4e 20 3b 0a 20 20 20 20 3a 6e 6f 6e 61  THEN ;.    :nona
1df0: 6d 65 20 6c 65 76 65 6c 23 20 40 20 30 3e 20 49  me level# @ 0> I
1e00: 46 20 20 2d 31 20 6c 65 76 65 6c 23 20 2b 21 0a  F  -1 level# +!.
1e10: 09 45 4c 53 45 20 20 63 74 72 6c 20 55 20 69 6e  .ELSE  ctrl U in
1e20: 73 6b 65 79 20 63 74 72 6c 20 44 20 69 6e 73 6b  skey ctrl D insk
1e30: 65 79 20 54 48 45 4e 20 3b 20 69 73 20 61 62 61  ey THEN ; is aba
1e40: 63 6b 0a 20 20 20 20 70 72 65 76 69 6f 75 73 0a  ck.    previous.
1e50: 5b 45 4c 53 45 5d 0a 20 20 20 20 5b 49 46 44 45  [ELSE].    [IFDE
1e60: 46 5d 20 68 61 73 2d 67 70 73 64 3f 0a 09 73 22  F] has-gpsd?..s"
1e70: 20 75 6e 69 78 2f 67 70 73 6c 69 62 2e 66 73 22   unix/gpslib.fs"
1e80: 20 27 20 72 65 71 75 69 72 65 64 20 63 61 74 63   ' required catc
1e90: 68 20 5b 49 46 5d 0a 09 20 20 20 20 32 64 72 6f  h [IF]..    2dro
1ea0: 70 20 3a 20 63 6f 6f 72 64 21 20 3b 0a 09 5b 45  p : coord! ;..[E
1eb0: 4c 53 45 5d 0a 09 20 20 20 20 30 20 56 61 6c 75  LSE]..    0 Valu
1ec0: 65 20 67 70 73 2d 6f 70 65 6e 65 64 3f 0a 09 20  e gps-opened?.. 
1ed0: 20 20 20 3a 20 63 6f 6f 72 64 21 20 28 20 2d 2d     : coord! ( --
1ee0: 20 29 20 67 70 73 2d 6f 70 65 6e 65 64 3f 20 30   ) gps-opened? 0
1ef0: 3d 20 49 46 0a 09 09 20 20 20 20 67 70 73 2d 6c  = IF...    gps-l
1f00: 6f 63 61 6c 2d 6f 70 65 6e 20 30 3d 20 74 6f 20  ocal-open 0= to 
1f10: 67 70 73 2d 6f 70 65 6e 65 64 3f 0a 09 09 20 20  gps-opened?...  
1f20: 20 20 67 70 73 2d 6f 70 65 6e 65 64 3f 20 30 3d    gps-opened? 0=
1f30: 20 3f 45 58 49 54 0a 09 09 54 48 45 4e 0a 09 09   ?EXIT...THEN...
1f40: 67 70 73 2d 66 69 78 20 7b 20 66 69 78 20 7d 0a  gps-fix { fix }.
1f50: 09 09 66 69 78 20 67 70 73 3a 67 70 73 5f 66 69  ..fix gps:gps_fi
1f60: 78 5f 74 2d 6c 61 74 69 74 75 64 65 20 20 64 66  x_t-latitude  df
1f70: 40 20 63 6f 6f 72 64 22 20 30 20 73 66 5b 5d 21  @ coord" 0 sf[]!
1f80: 0a 09 09 66 69 78 20 67 70 73 3a 67 70 73 5f 66  ...fix gps:gps_f
1f90: 69 78 5f 74 2d 6c 6f 6e 67 69 74 75 64 65 20 64  ix_t-longitude d
1fa0: 66 40 20 63 6f 6f 72 64 22 20 31 20 73 66 5b 5d  f@ coord" 1 sf[]
1fb0: 21 0a 09 09 66 69 78 20 67 70 73 3a 67 70 73 5f  !...fix gps:gps_
1fc0: 66 69 78 5f 74 2d 61 6c 74 69 74 75 64 65 20 20  fix_t-altitude  
1fd0: 64 66 40 20 63 6f 6f 72 64 22 20 32 20 73 66 5b  df@ coord" 2 sf[
1fe0: 5d 21 0a 09 09 66 69 78 20 67 70 73 3a 67 70 73  ]!...fix gps:gps
1ff0: 5f 66 69 78 5f 74 2d 73 70 65 65 64 20 20 20 20  _fix_t-speed    
2000: 20 64 66 40 20 63 6f 6f 72 64 22 20 33 20 73 66   df@ coord" 3 sf
2010: 5b 5d 21 0a 09 09 66 69 78 20 67 70 73 3a 67 70  []!...fix gps:gp
2020: 73 5f 66 69 78 5f 74 2d 74 72 61 63 6b 20 20 20  s_fix_t-track   
2030: 20 20 64 66 40 20 63 6f 6f 72 64 22 20 34 20 73    df@ coord" 4 s
2040: 66 5b 5d 21 0a 09 09 66 69 78 20 67 70 73 3a 67  f[]!...fix gps:g
2050: 70 73 5f 66 69 78 5f 74 2d 65 70 78 20 64 66 40  ps_fix_t-epx df@
2060: 20 66 2a 2a 32 0a 09 09 66 69 78 20 67 70 73 3a   f**2...fix gps:
2070: 67 70 73 5f 66 69 78 5f 74 2d 65 70 79 20 64 66  gps_fix_t-epy df
2080: 40 20 66 2a 2a 32 0a 09 09 66 2b 20 66 73 71 72  @ f**2...f+ fsqr
2090: 74 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20  t               
20a0: 20 20 20 20 20 20 20 20 20 63 6f 6f 72 64 22 20           coord" 
20b0: 35 20 73 66 5b 5d 21 20 3b 0a 09 5b 54 48 45 4e  5 sf[]! ;..[THEN
20c0: 5d 0a 20 20 20 20 5b 45 4c 53 45 5d 0a 09 3a 20  ].    [ELSE]..: 
20d0: 63 6f 6f 72 64 21 20 28 20 2d 2d 20 29 20 3b 0a  coord! ( -- ) ;.
20e0: 20 20 20 20 5b 54 48 45 4e 5d 0a 5b 54 48 45 4e      [THEN].[THEN
20f0: 5d 0a 0a 3a 20 2e 63 6f 6f 72 64 73 20 28 20 61  ]..: .coords ( a
2100: 64 64 72 20 75 20 2d 2d 20 29 20 24 3e 61 6c 69  ddr u -- ) $>ali
2110: 67 6e 20 64 72 6f 70 0a 20 20 20 20 64 75 70 20  gn drop.    dup 
2120: 30 20 73 66 5b 5d 40 20 66 64 75 70 20 66 61 62  0 sf[]@ fdup fab
2130: 73 20 2e 64 65 67 20 66 30 3c 20 27 53 27 20 27  s .deg f0< 'S' '
2140: 4e 27 20 72 6f 74 20 73 65 6c 65 63 74 20 65 6d  N' rot select em
2150: 69 74 20 73 70 61 63 65 0a 20 20 20 20 64 75 70  it space.    dup
2160: 20 31 20 73 66 5b 5d 40 20 66 64 75 70 20 66 61   1 sf[]@ fdup fa
2170: 62 73 20 2e 64 65 67 20 66 30 3c 20 27 57 27 20  bs .deg f0< 'W' 
2180: 27 45 27 20 72 6f 74 20 73 65 6c 65 63 74 20 65  'E' rot select e
2190: 6d 69 74 20 73 70 61 63 65 0a 20 20 20 20 64 75  mit space.    du
21a0: 70 20 32 20 73 66 5b 5d 40 20 37 20 31 20 30 20  p 2 sf[]@ 7 1 0 
21b0: 66 2e 72 64 70 20 2e 22 20 6d 20 22 0a 20 20 20  f.rdp ." m ".   
21c0: 20 64 75 70 20 33 20 73 66 5b 5d 40 20 38 20 32   dup 3 sf[]@ 8 2
21d0: 20 30 20 66 2e 72 64 70 20 2e 22 20 6b 6d 2f 68   0 f.rdp ." km/h
21e0: 20 22 0a 20 20 20 20 64 75 70 20 34 20 73 66 5b   ".    dup 4 sf[
21f0: 5d 40 20 38 20 32 20 30 20 66 2e 72 64 70 20 2e  ]@ 8 2 0 f.rdp .
2200: 22 20 c2 b0 20 7e 22 0a 20 20 20 20 64 75 70 20  " ° ~".    dup 
2210: 35 20 73 66 5b 5d 40 20 66 73 70 6c 69 74 20 30  5 sf[]@ fsplit 0
2220: 20 2e 72 20 27 2e 27 20 65 6d 69 74 20 31 30 30   .r '.' emit 100
2230: 65 20 66 2a 20 66 3e 73 20 2e 23 23 20 2e 22 20  e f* f>s .## ." 
2240: 6d 22 0a 20 20 20 20 64 72 6f 70 20 3b 0a 0a 46  m".    drop ;..F
2250: 6f 72 77 61 72 64 20 6d 73 67 3a 6c 61 73 74 3f  orward msg:last?
2260: 0a 46 6f 72 77 61 72 64 20 6d 73 67 3a 6c 61 73  .Forward msg:las
2270: 74 0a 0a 3a 20 70 75 73 68 2d 6d 73 67 20 28 20  t..: push-msg ( 
2280: 61 64 64 72 20 75 20 6f 3a 70 61 72 65 6e 74 20  addr u o:parent 
2290: 2d 2d 20 29 0a 20 20 20 20 75 70 40 20 72 65 63  -- ).    up@ rec
22a0: 65 69 76 65 72 2d 74 61 73 6b 20 3c 3e 20 49 46  eiver-task <> IF
22b0: 0a 09 61 76 61 6c 61 6e 63 68 65 2d 6d 73 67 0a  ..avalanche-msg.
22c0: 20 20 20 20 45 4c 53 45 20 77 61 69 74 2d 74 61      ELSE wait-ta
22d0: 73 6b 20 40 20 3f 64 75 70 2d 49 46 0a 09 20 20  sk @ ?dup-IF..  
22e0: 20 20 3c 65 76 65 6e 74 20 3e 72 20 65 24 2c 20    <event >r e$, 
22f0: 6f 20 65 6c 69 74 2c 20 6d 73 67 2d 67 72 6f 75  o elit, msg-grou
2300: 70 2d 6f 20 65 6c 69 74 2c 0a 09 20 20 20 20 3a  p-o elit,..    :
2310: 3e 61 76 61 6c 61 6e 63 68 65 20 72 3e 20 65 76  >avalanche r> ev
2320: 65 6e 74 3e 0a 09 45 4c 53 45 20 20 32 64 72 6f  ent>..ELSE  2dro
2330: 70 20 20 54 48 45 4e 0a 20 20 20 20 54 48 45 4e  p  THEN.    THEN
2340: 20 3b 0a 3a 20 73 68 6f 77 2d 6d 73 67 20 28 20   ;.: show-msg ( 
2350: 61 64 64 72 20 75 20 2d 2d 20 29 0a 20 20 20 20  addr u -- ).    
2360: 70 61 72 65 6e 74 20 64 75 70 20 49 46 20 20 2e  parent dup IF  .
2370: 77 61 69 74 2d 74 61 73 6b 20 40 20 64 75 70 20  wait-task @ dup 
2380: 75 70 40 20 3c 3e 20 61 6e 64 20 20 54 48 45 4e  up@ <> and  THEN
2390: 0a 20 20 20 20 3f 64 75 70 2d 49 46 0a 09 3e 72  .    ?dup-IF..>r
23a0: 20 72 40 20 3c 68 69 64 65 3e 20 3c 65 76 65 6e   r@ <hide> <even
23b0: 74 20 24 6d 61 6b 65 20 65 6c 69 74 2c 20 6f 20  t $make elit, o 
23c0: 65 6c 69 74 2c 20 6d 73 67 2d 67 72 6f 75 70 2d  elit, msg-group-
23d0: 6f 20 65 6c 69 74 2c 20 3a 3e 6d 73 67 2d 6e 65  o elit, :>msg-ne
23e0: 73 74 73 69 67 0a 09 72 3e 20 65 76 65 6e 74 3e  stsig..r> event>
23f0: 0a 20 20 20 20 45 4c 53 45 20 20 64 6f 2d 6d 73  .    ELSE  do-ms
2400: 67 2d 6e 65 73 74 73 69 67 20 20 54 48 45 4e 20  g-nestsig  THEN 
2410: 3b 0a 0a 3a 20 64 61 74 65 3e 69 20 28 20 64 61  ;..: date>i ( da
2420: 74 65 20 2d 2d 20 69 20 29 0a 20 20 20 20 6d 73  te -- i ).    ms
2430: 67 2d 67 72 6f 75 70 2d 6f 20 2e 6d 73 67 3a 6c  g-group-o .msg:l
2440: 6f 67 5b 5d 20 24 73 65 61 72 63 68 5b 5d 64 61  og[] $search[]da
2450: 74 65 20 6d 73 67 2d 67 72 6f 75 70 2d 6f 20 2e  te msg-group-o .
2460: 6d 73 67 3a 6c 6f 67 5b 5d 20 24 5b 5d 23 20 31  msg:log[] $[]# 1
2470: 2d 20 75 6d 69 6e 20 3b 0a 3a 20 64 61 74 65 3e  - umin ;.: date>
2480: 69 27 20 28 20 64 61 74 65 20 2d 2d 20 69 20 29  i' ( date -- i )
2490: 0a 20 20 20 20 6d 73 67 2d 67 72 6f 75 70 2d 6f  .    msg-group-o
24a0: 20 2e 6d 73 67 3a 6c 6f 67 5b 5d 20 24 73 65 61   .msg:log[] $sea
24b0: 72 63 68 5b 5d 64 61 74 65 20 6d 73 67 2d 67 72  rch[]date msg-gr
24c0: 6f 75 70 2d 6f 20 2e 6d 73 67 3a 6c 6f 67 5b 5d  oup-o .msg:log[]
24d0: 20 24 5b 5d 23 20 75 6d 69 6e 20 3b 0a 3a 20 73   $[]# umin ;.: s
24e0: 69 67 68 61 73 68 3f 20 28 20 61 64 64 72 20 75  ighash? ( addr u
24f0: 20 2d 2d 20 66 6c 61 67 20 29 0a 20 20 20 20 6f   -- flag ).    o
2500: 76 65 72 20 6c 65 2d 36 34 40 20 64 61 74 65 3e  ver le-64@ date>
2510: 69 0a 20 20 20 20 64 75 70 20 30 3c 20 49 46 20  i.    dup 0< IF 
2520: 20 64 72 6f 70 20 32 64 72 6f 70 20 20 66 61 6c   drop 2drop  fal
2530: 73 65 20 20 45 58 49 54 20 20 54 48 45 4e 20 20  se  EXIT  THEN  
2540: 3e 72 0a 20 20 20 20 6f 76 65 72 20 6c 65 2d 36  >r.    over le-6
2550: 34 40 20 36 34 23 31 20 36 34 2b 20 64 61 74 65  4@ 64#1 64+ date
2560: 3e 69 27 20 3e 72 20 5b 20 31 20 36 34 73 20 5d  >i' >r [ 1 64s ]
2570: 4c 20 2f 73 74 72 69 6e 67 0a 20 20 20 20 72 3e  L /string.    r>
2580: 20 72 3e 20 55 2b 44 4f 0a 09 63 3a 30 6b 65 79   r> U+DO..c:0key
2590: 20 49 20 6d 73 67 2d 67 72 6f 75 70 2d 6f 20 2e   I msg-group-o .
25a0: 6d 73 67 3a 6c 6f 67 5b 5d 20 24 5b 5d 40 20 73  msg:log[] $[]@ s
25b0: 69 67 6f 6e 6c 79 40 20 3e 68 61 73 68 0a 09 32  igonly@ >hash..2
25c0: 64 75 70 20 68 61 73 68 74 6d 70 20 6f 76 65 72  dup hashtmp over
25d0: 20 73 74 72 3d 20 49 46 20 20 32 64 72 6f 70 20   str= IF  2drop 
25e0: 74 72 75 65 20 20 55 4e 4c 4f 4f 50 20 20 20 45  true  UNLOOP   E
25f0: 58 49 54 0a 09 45 4c 53 45 20 20 28 20 32 64 75  XIT..ELSE  ( 2du
2600: 70 20 38 35 74 79 70 65 20 2e 22 20 20 3c 3e 20  p 85type ."  <> 
2610: 22 20 68 61 73 68 74 6d 70 20 6f 76 65 72 20 38  " hashtmp over 8
2620: 35 74 79 70 65 20 29 20 20 54 48 45 4e 0a 20 20  5type )  THEN.  
2630: 20 20 4c 4f 4f 50 0a 20 20 20 20 32 64 72 6f 70    LOOP.    2drop
2640: 20 66 61 6c 73 65 20 3b 0a 0a 3a 20 6d 73 67 2d   false ;..: msg-
2650: 6b 65 79 21 20 28 20 61 64 64 72 20 75 20 2d 2d  key! ( addr u --
2660: 20 29 0a 20 20 20 20 30 20 6d 73 67 2d 67 72 6f   ).    0 msg-gro
2670: 75 70 2d 6f 20 2e 6d 73 67 3a 6b 65 79 73 5b 5d  up-o .msg:keys[]
2680: 20 5b 3a 20 72 6f 74 20 3e 72 20 32 6f 76 65 72   [: rot >r 2over
2690: 20 73 74 72 3d 20 72 3e 20 6f 72 20 3b 5d 20 24   str= r> or ;] $
26a0: 5b 5d 6d 61 70 0a 20 20 20 20 49 46 20 20 32 64  []map.    IF  2d
26b0: 72 6f 70 20 20 45 4c 53 45 20 20 5c 20 2e 22 20  rop  ELSE  \ ." 
26c0: 6d 73 67 2d 6b 65 79 2b 20 22 20 32 64 75 70 20  msg-key+ " 2dup 
26d0: 38 35 74 79 70 65 20 66 6f 72 74 68 3a 63 72 0a  85type forth:cr.
26e0: 09 24 6d 61 6b 65 20 6d 73 67 2d 67 72 6f 75 70  .$make msg-group
26f0: 2d 6f 20 2e 6d 73 67 3a 6b 65 79 73 5b 5d 20 3e  -o .msg:keys[] >
2700: 62 61 63 6b 20 20 54 48 45 4e 20 3b 0a 0a 5c 20  back  THEN ;..\ 
2710: 6d 65 73 73 61 67 65 20 63 6f 6d 6d 61 6e 64 73  message commands
2720: 0a 0a 73 63 6f 70 65 7b 20 6e 65 74 32 6f 2d 62  ..scope{ net2o-b
2730: 61 73 65 0a 0a 5c 67 20 0a 5c 67 20 23 23 23 20  ase..\g .\g ### 
2740: 6d 65 73 73 61 67 65 20 63 6f 6d 6d 61 6e 64 73  message commands
2750: 20 23 23 23 0a 5c 67 20 0a 0a 72 65 70 6c 79 2d   ###.\g ..reply-
2760: 74 61 62 6c 65 20 24 40 20 69 6e 68 65 72 69 74  table $@ inherit
2770: 2d 74 61 62 6c 65 20 6d 73 67 2d 74 61 62 6c 65  -table msg-table
2780: 0a 0a 24 32 30 20 6e 65 74 32 6f 3a 20 6d 73 67  ..$20 net2o: msg
2790: 2d 73 74 61 72 74 20 28 20 24 3a 70 6b 73 69 67  -start ( $:pksig
27a0: 20 2d 2d 20 29 20 5c 67 20 73 74 61 72 74 20 6d   -- ) \g start m
27b0: 65 73 73 61 67 65 0a 20 20 20 20 31 20 21 21 3e  essage.    1 !!>
27c0: 6f 72 64 65 72 3f 20 24 3e 20 6d 73 67 3a 73 74  order? $> msg:st
27d0: 61 72 74 20 3b 0a 2b 6e 65 74 32 6f 3a 20 6d 73  art ;.+net2o: ms
27e0: 67 2d 74 61 67 20 28 20 24 3a 74 61 67 20 2d 2d  g-tag ( $:tag --
27f0: 20 29 20 5c 67 20 74 61 67 67 69 6e 67 20 28 63   ) \g tagging (c
2800: 61 6e 20 62 65 20 61 6e 79 77 68 65 72 65 29 0a  an be anywhere).
2810: 20 20 20 20 24 3e 20 6d 73 67 3a 74 61 67 20 3b      $> msg:tag ;
2820: 0a 2b 6e 65 74 32 6f 3a 20 6d 73 67 2d 69 64 20  .+net2o: msg-id 
2830: 28 20 24 3a 69 64 20 2d 2d 20 29 20 5c 67 20 61  ( $:id -- ) \g a
2840: 20 68 61 73 68 20 69 64 0a 20 20 20 20 32 20 21   hash id.    2 !
2850: 21 3e 3d 6f 72 64 65 72 3f 20 24 3e 20 6d 73 67  !>=order? $> msg
2860: 3a 69 64 20 3b 0a 2b 6e 65 74 32 6f 3a 20 6d 73  :id ;.+net2o: ms
2870: 67 2d 63 68 61 69 6e 20 28 20 24 3a 64 61 74 65  g-chain ( $:date
2880: 73 2c 73 69 67 68 61 73 68 20 2d 2d 20 29 20 5c  s,sighash -- ) \
2890: 67 20 63 68 61 69 6e 65 64 20 74 6f 20 6d 65 73  g chained to mes
28a0: 73 61 67 65 5b 73 5d 0a 20 20 20 20 28 20 24 31  sage[s].    ( $1
28b0: 30 20 21 21 3e 3d 6f 72 64 65 72 3f 20 29 20 24  0 !!>=order? ) $
28c0: 3e 20 6d 73 67 3a 63 68 61 69 6e 20 3b 0a 2b 6e  > msg:chain ;.+n
28d0: 65 74 32 6f 3a 20 6d 73 67 2d 73 69 67 6e 61 6c  et2o: msg-signal
28e0: 20 28 20 24 3a 70 75 62 6b 65 79 20 2d 2d 20 29   ( $:pubkey -- )
28f0: 20 5c 67 20 73 69 67 6e 61 6c 20 6d 65 73 73 61   \g signal messa
2900: 67 65 20 74 6f 20 6f 6e 65 20 70 65 72 73 6f 6e  ge to one person
2910: 0a 20 20 20 20 24 3e 20 6d 73 67 3a 73 69 67 6e  .    $> msg:sign
2920: 61 6c 20 3b 0a 2b 6e 65 74 32 6f 3a 20 6d 73 67  al ;.+net2o: msg
2930: 2d 72 65 20 28 20 24 3a 68 61 73 68 20 29 20 5c  -re ( $:hash ) \
2940: 67 20 72 65 6c 61 74 65 20 74 6f 20 73 6f 6d 65  g relate to some
2950: 20 6f 62 6a 65 63 74 0a 20 20 20 20 34 20 21 21   object.    4 !!
2960: 3e 3d 6f 72 64 65 72 3f 20 24 3e 20 6d 73 67 3a  >=order? $> msg:
2970: 72 65 20 3b 0a 2b 6e 65 74 32 6f 3a 20 6d 73 67  re ;.+net2o: msg
2980: 2d 74 65 78 74 20 28 20 24 3a 6d 73 67 20 2d 2d  -text ( $:msg --
2990: 20 29 20 5c 67 20 73 70 65 63 69 66 79 20 6d 65   ) \g specify me
29a0: 73 73 61 67 65 20 73 74 72 69 6e 67 0a 20 20 20  ssage string.   
29b0: 20 38 20 21 21 3e 3d 6f 72 64 65 72 3f 20 24 3e   8 !!>=order? $>
29c0: 20 6d 73 67 3a 74 65 78 74 20 3b 0a 2b 6e 65 74   msg:text ;.+net
29d0: 32 6f 3a 20 6d 73 67 2d 6f 62 6a 65 63 74 20 28  2o: msg-object (
29e0: 20 24 3a 6f 62 6a 65 63 74 20 74 79 70 65 20 2d   $:object type -
29f0: 2d 20 29 20 5c 67 20 73 70 65 63 69 66 79 20 61  - ) \g specify a
2a00: 6e 20 6f 62 6a 65 63 74 2c 20 65 2e 67 2e 20 61  n object, e.g. a
2a10: 6e 20 69 6d 61 67 65 0a 20 20 20 20 38 20 21 21  n image.    8 !!
2a20: 3e 3d 6f 72 64 65 72 3f 20 36 34 3e 6e 20 24 3e  >=order? 64>n $>
2a30: 20 72 6f 74 20 6d 73 67 3a 6f 62 6a 65 63 74 20   rot msg:object 
2a40: 3b 0a 2b 6e 65 74 32 6f 3a 20 6d 73 67 2d 61 63  ;.+net2o: msg-ac
2a50: 74 69 6f 6e 20 28 20 24 3a 6d 73 67 20 2d 2d 20  tion ( $:msg -- 
2a60: 29 20 5c 67 20 73 70 65 63 69 66 79 20 61 63 74  ) \g specify act
2a70: 69 6f 6e 20 73 74 72 69 6e 67 0a 20 20 20 20 38  ion string.    8
2a80: 20 21 21 3e 3d 6f 72 64 65 72 3f 20 24 3e 20 6d   !!>=order? $> m
2a90: 73 67 3a 61 63 74 69 6f 6e 20 3b 0a 2b 6e 65 74  sg:action ;.+net
2aa0: 32 6f 3a 20 6d 73 67 2d 70 61 79 6d 65 6e 74 20  2o: msg-payment 
2ab0: 28 20 24 3a 63 6f 6e 74 72 61 63 74 20 2d 2d 20  ( $:contract -- 
2ac0: 29 20 5c 67 20 70 61 79 6d 65 6e 74 20 74 72 61  ) \g payment tra
2ad0: 6e 73 61 63 74 69 6f 6e 0a 20 20 20 20 38 20 21  nsaction.    8 !
2ae0: 21 3e 3d 6f 72 64 65 72 3f 20 24 3e 20 6d 73 67  !>=order? $> msg
2af0: 3a 70 61 79 6d 65 6e 74 20 3b 0a 2b 6e 65 74 32  :payment ;.+net2
2b00: 6f 3a 20 6d 73 67 2d 6f 74 72 69 66 79 20 28 20  o: msg-otrify ( 
2b10: 24 3a 64 61 74 65 2b 73 69 67 20 24 3a 6e 65 77  $:date+sig $:new
2b20: 64 61 74 65 2b 73 69 67 20 2d 2d 20 29 20 5c 67  date+sig -- ) \g
2b30: 20 74 75 72 6e 20 61 20 70 61 73 74 20 6d 65 73   turn a past mes
2b40: 73 61 67 65 20 69 6e 74 6f 20 4f 54 52 0a 20 20  sage into OTR.  
2b50: 20 20 24 3e 20 24 3e 20 6d 73 67 3a 6f 74 72 69    $> $> msg:otri
2b60: 66 79 20 3b 0a 2b 6e 65 74 32 6f 3a 20 6d 73 67  fy ;.+net2o: msg
2b70: 2d 63 6f 6f 72 64 20 28 20 24 3a 67 70 73 20 2d  -coord ( $:gps -
2b80: 2d 20 29 20 5c 67 20 47 50 53 20 63 6f 6f 72 64  - ) \g GPS coord
2b90: 69 6e 61 74 65 73 0a 20 20 20 20 38 20 21 21 3e  inates.    8 !!>
2ba0: 3d 6f 72 64 65 72 3f 20 24 3e 20 6d 73 67 3a 63  =order? $> msg:c
2bb0: 6f 6f 72 64 20 3b 0a 2b 6e 65 74 32 6f 3a 20 6d  oord ;.+net2o: m
2bc0: 73 67 2d 75 72 6c 20 28 20 24 3a 75 72 6c 20 2d  sg-url ( $:url -
2bd0: 2d 20 29 20 5c 67 20 73 70 65 63 69 66 79 20 6d  - ) \g specify m
2be0: 65 73 73 61 67 65 20 55 52 4c 0a 20 20 20 20 24  essage URL.    $
2bf0: 3e 20 6d 73 67 3a 75 72 6c 20 3b 0a 2b 6e 65 74  > msg:url ;.+net
2c00: 32 6f 3a 20 6d 73 67 2d 6c 69 6b 65 20 28 20 78  2o: msg-like ( x
2c10: 63 68 61 72 20 2d 2d 20 29 20 5c 67 20 61 64 64  char -- ) \g add
2c20: 20 61 20 6c 69 6b 65 0a 20 20 20 20 36 34 3e 6e   a like.    64>n
2c30: 20 6d 73 67 3a 6c 69 6b 65 20 3b 0a 2b 6e 65 74   msg:like ;.+net
2c40: 32 6f 3a 20 6d 73 67 2d 6c 6f 63 6b 20 28 20 24  2o: msg-lock ( $
2c50: 3a 6b 65 79 20 2d 2d 20 29 20 5c 67 20 6c 6f 63  :key -- ) \g loc
2c60: 6b 20 64 6f 77 6e 20 63 6f 6d 6d 75 6e 63 69 61  k down communcia
2c70: 74 69 6f 6e 0a 20 20 20 20 24 3e 20 6d 73 67 3a  tion.    $> msg:
2c80: 6c 6f 63 6b 20 3b 0a 2b 6e 65 74 32 6f 3a 20 6d  lock ;.+net2o: m
2c90: 73 67 2d 75 6e 6c 6f 63 6b 20 28 20 2d 2d 20 29  sg-unlock ( -- )
2ca0: 20 5c 67 20 75 6e 6c 6f 63 6b 20 63 6f 6d 6d 75   \g unlock commu
2cb0: 6e 69 63 61 74 69 6f 6e 0a 20 20 20 20 6d 73 67  nication.    msg
2cc0: 3a 75 6e 6c 6f 63 6b 20 3b 0a 2b 6e 65 74 32 6f  :unlock ;.+net2o
2cd0: 3a 20 6d 73 67 2d 70 65 72 6d 73 20 28 20 24 3a  : msg-perms ( $:
2ce0: 70 6b 20 70 65 72 6d 20 2d 2d 20 29 20 5c 67 20  pk perm -- ) \g 
2cf0: 70 65 72 6d 69 73 73 69 6f 6e 73 0a 20 20 20 20  permissions.    
2d00: 24 3e 20 6d 73 67 3a 70 65 72 6d 73 20 3b 0a 7d  $> msg:perms ;.}
2d10: 73 63 6f 70 65 0a 0a 6d 73 67 2d 74 61 62 6c 65  scope..msg-table
2d20: 20 24 73 61 76 65 0a 0a 27 20 63 6f 6e 74 65 78   $save..' contex
2d30: 74 2d 74 61 62 6c 65 20 69 73 20 67 65 6e 2d 74  t-table is gen-t
2d40: 61 62 6c 65 0a 0a 5c 20 43 6f 64 65 20 66 6f 72  able..\ Code for
2d50: 20 64 69 73 70 6c 61 79 69 6e 67 20 6d 65 73 73   displaying mess
2d60: 61 67 65 73 0a 0a 44 65 66 65 72 20 2e 6c 6f 67  ages..Defer .log
2d70: 2d 6e 75 6d 0a 44 65 66 65 72 20 2e 6c 6f 67 2d  -num.Defer .log-
2d80: 64 61 74 65 0a 44 65 66 65 72 20 2e 6c 6f 67 2d  date.Defer .log-
2d90: 65 6e 64 0a 0a 3a 20 2e 6f 74 72 2d 69 6e 66 6f  end..: .otr-info
2da0: 20 28 20 2d 2d 20 29 0a 20 20 20 20 3c 69 6e 66   ( -- ).    <inf
2db0: 6f 3e 20 2e 22 20 5b 6f 74 72 5d 20 22 20 3c 64  o> ." [otr] " <d
2dc0: 65 66 61 75 6c 74 3e 20 22 5b 6f 74 72 5d 20 22  efault> "[otr] "
2dd0: 20 6e 6f 74 69 66 79 2b 20 6e 6f 74 69 66 79 2d   notify+ notify-
2de0: 6f 74 72 3f 20 6f 6e 20 3b 0a 3a 20 2e 6f 74 72  otr? on ;.: .otr
2df0: 2d 65 72 72 20 28 20 2d 2d 20 29 0a 20 20 20 20  -err ( -- ).    
2e00: 3c 65 72 72 3e 20 2e 22 20 5b 65 78 70 5d 20 22  <err> ." [exp] "
2e10: 20 3c 64 65 66 61 75 6c 74 3e 20 31 20 6e 6f 74   <default> 1 not
2e20: 69 66 79 2d 6f 74 72 3f 20 21 20 3b 0a 3a 20 2e  ify-otr? ! ;.: .
2e30: 6f 74 72 20 28 20 74 69 63 6b 20 2d 2d 20 29 0a  otr ( tick -- ).
2e40: 20 20 20 20 36 34 64 75 70 20 36 34 23 2d 31 20      64dup 64#-1 
2e50: 36 34 3d 20 49 46 20 20 36 34 64 72 6f 70 20 20  64= IF  64drop  
2e60: 6e 6f 74 69 66 79 2d 6f 74 72 3f 20 6f 66 66 20  notify-otr? off 
2e70: 20 45 58 49 54 20 20 54 48 45 4e 0a 20 20 20 20   EXIT  THEN.    
2e80: 74 69 63 6b 73 20 36 34 2d 20 36 34 64 75 70 20  ticks 64- 64dup 
2e90: 66 75 7a 7a 65 64 74 69 6d 65 23 20 36 34 6e 65  fuzzedtime# 64ne
2ea0: 67 61 74 65 20 36 34 3c 20 49 46 20 20 36 34 64  gate 64< IF  64d
2eb0: 72 6f 70 20 2e 6f 74 72 2d 65 72 72 20 20 45 58  rop .otr-err  EX
2ec0: 49 54 20 20 54 48 45 4e 0a 20 20 20 20 6f 74 72  IT  THEN.    otr
2ed0: 73 69 67 2d 64 65 6c 74 61 23 20 66 75 7a 7a 65  sig-delta# fuzze
2ee0: 64 74 69 6d 65 23 20 36 34 2b 20 36 34 3c 20 49  dtime# 64+ 64< I
2ef0: 46 20 20 2e 6f 74 72 2d 69 6e 66 6f 20 20 54 48  F  .otr-info  TH
2f00: 45 4e 20 3b 0a 3a 20 2e 67 72 6f 75 70 20 28 20  EN ;.: .group ( 
2f10: 61 64 64 72 20 75 20 2d 2d 20 29 0a 20 20 20 20  addr u -- ).    
2f20: 32 64 75 70 20 70 72 69 6e 74 61 62 6c 65 3f 20  2dup printable? 
2f30: 49 46 20 20 66 6f 72 74 68 3a 74 79 70 65 20 20  IF  forth:type  
2f40: 45 4c 53 45 20 20 2e 22 20 40 22 20 2e 6b 65 79  ELSE  ." @" .key
2f50: 2d 69 64 20 20 54 48 45 4e 20 3b 0a 0a 73 63 6f  -id  THEN ;..sco
2f60: 70 65 3a 20 6c 6f 67 73 74 79 6c 65 73 0a 3a 20  pe: logstyles.: 
2f70: 2b 6e 75 6d 20 5b 3a 20 27 23 27 20 65 6d 69 74  +num [: '#' emit
2f80: 20 6c 6f 67 23 20 75 2e 20 3b 5d 20 69 73 20 2e   log# u. ;] is .
2f90: 6c 6f 67 2d 6e 75 6d 20 3b 0a 3a 20 2d 6e 75 6d  log-num ;.: -num
2fa0: 20 5b 27 5d 20 6e 6f 6f 70 20 69 73 20 2e 6c 6f   ['] noop is .lo
2fb0: 67 2d 6e 75 6d 20 3b 0a 3a 20 2b 64 61 74 65 20  g-num ;.: +date 
2fc0: 5b 3a 20 2e 74 69 63 6b 73 20 73 70 61 63 65 20  [: .ticks space 
2fd0: 3b 5d 20 69 73 20 2e 6c 6f 67 2d 64 61 74 65 20  ;] is .log-date 
2fe0: 3b 0a 3a 20 2d 64 61 74 65 20 5b 27 5d 20 36 34  ;.: -date ['] 64
2ff0: 64 72 6f 70 20 69 73 20 2e 6c 6f 67 2d 64 61 74  drop is .log-dat
3000: 65 20 3b 0a 3a 20 2b 65 6e 64 20 5b 3a 20 36 34  e ;.: +end [: 64
3010: 64 75 70 20 2e 74 69 63 6b 73 20 73 70 61 63 65  dup .ticks space
3020: 20 2e 6f 74 72 20 3b 5d 20 69 73 20 2e 6c 6f 67   .otr ;] is .log
3030: 2d 65 6e 64 20 3b 0a 3a 20 2d 65 6e 64 20 5b 27  -end ;.: -end ['
3040: 5d 20 2e 6f 74 72 20 69 73 20 2e 6c 6f 67 2d 65  ] .otr is .log-e
3050: 6e 64 20 3b 0a 0a 2b 64 61 74 65 20 2d 6e 75 6d  nd ;..+date -num
3060: 20 2d 65 6e 64 0a 7d 73 63 6f 70 65 0a 0a 3a 6e   -end.}scope..:n
3070: 6f 6e 61 6d 65 20 28 20 61 64 64 72 20 75 20 2d  oname ( addr u -
3080: 2d 20 29 0a 20 20 20 20 6c 61 73 74 23 20 3e 72  - ).    last# >r
3090: 20 20 32 64 75 70 20 6b 65 79 7c 20 74 6f 20 6d    2dup key| to m
30a0: 73 67 3a 69 64 24 0a 20 20 20 20 5b 3a 20 2e 73  sg:id$.    [: .s
30b0: 69 6d 70 6c 65 2d 69 64 20 2e 22 20 3a 20 22 20  imple-id ." : " 
30c0: 3b 5d 20 24 74 6d 70 20 6e 6f 74 69 66 79 2d 6e  ;] $tmp notify-n
30d0: 69 63 6b 21 0a 20 20 20 20 72 3e 20 74 6f 20 6c  ick!.    r> to l
30e0: 61 73 74 23 20 3b 20 6d 73 67 2d 6e 6f 74 69 66  ast# ; msg-notif
30f0: 79 2d 63 6c 61 73 73 20 69 73 20 6d 73 67 3a 73  y-class is msg:s
3100: 74 61 72 74 0a 3a 6e 6f 6e 61 6d 65 20 28 20 61  tart.:noname ( a
3110: 64 64 72 20 75 20 2d 2d 20 29 20 22 23 22 20 6e  ddr u -- ) "#" n
3120: 6f 74 69 66 79 2b 20 24 75 74 66 38 3e 20 6e 6f  otify+ $utf8> no
3130: 74 69 66 79 2b 0a 3b 20 6d 73 67 2d 6e 6f 74 69  tify+.; msg-noti
3140: 66 79 2d 63 6c 61 73 73 20 69 73 20 6d 73 67 3a  fy-class is msg:
3150: 74 61 67 0a 3a 6e 6f 6e 61 6d 65 20 28 20 61 64  tag.:noname ( ad
3160: 64 72 20 75 20 2d 2d 20 29 0a 20 20 20 20 32 64  dr u -- ).    2d
3170: 75 70 20 5b 3a 20 2e 22 20 40 22 20 2e 73 69 6d  up [: ." @" .sim
3180: 70 6c 65 2d 69 64 20 3b 5d 20 24 74 6d 70 20 6e  ple-id ;] $tmp n
3190: 6f 74 69 66 79 2b 20 3b 20 6d 73 67 2d 6e 6f 74  otify+ ; msg-not
31a0: 69 66 79 2d 63 6c 61 73 73 20 69 73 20 6d 73 67  ify-class is msg
31b0: 3a 73 69 67 6e 61 6c 0a 3a 6e 6f 6e 61 6d 65 20  :signal.:noname 
31c0: 28 20 61 64 64 72 20 75 20 2d 2d 20 29 20 24 75  ( addr u -- ) $u
31d0: 74 66 38 3e 20 6e 6f 74 69 66 79 2b 20 3b 20 6d  tf8> notify+ ; m
31e0: 73 67 2d 6e 6f 74 69 66 79 2d 63 6c 61 73 73 20  sg-notify-class 
31f0: 69 73 20 6d 73 67 3a 74 65 78 74 0a 3a 6e 6f 6e  is msg:text.:non
3200: 61 6d 65 20 28 20 61 64 64 72 20 75 20 2d 2d 20  ame ( addr u -- 
3210: 29 20 24 75 74 66 38 3e 20 6e 6f 74 69 66 79 2b  ) $utf8> notify+
3220: 20 3b 20 6d 73 67 2d 6e 6f 74 69 66 79 2d 63 6c   ; msg-notify-cl
3230: 61 73 73 20 69 73 20 6d 73 67 3a 75 72 6c 0a 3a  ass is msg:url.:
3240: 6e 6f 6e 61 6d 65 20 28 20 61 64 64 72 20 75 20  noname ( addr u 
3250: 2d 2d 20 29 20 24 75 74 66 38 3e 20 6e 6f 74 69  -- ) $utf8> noti
3260: 66 79 2b 20 3b 20 6d 73 67 2d 6e 6f 74 69 66 79  fy+ ; msg-notify
3270: 2d 63 6c 61 73 73 20 69 73 20 6d 73 67 3a 61 63  -class is msg:ac
3280: 74 69 6f 6e 0a 27 20 64 72 6f 70 20 20 6d 73 67  tion.' drop  msg
3290: 2d 6e 6f 74 69 66 79 2d 63 6c 61 73 73 20 69 73  -notify-class is
32a0: 20 6d 73 67 3a 6c 69 6b 65 0a 27 20 32 64 72 6f   msg:like.' 2dro
32b0: 70 20 20 6d 73 67 2d 6e 6f 74 69 66 79 2d 63 6c  p  msg-notify-cl
32c0: 61 73 73 20 69 73 20 6d 73 67 3a 6c 6f 63 6b 0a  ass is msg:lock.
32d0: 27 20 6e 6f 6f 70 20 20 6d 73 67 2d 6e 6f 74 69  ' noop  msg-noti
32e0: 66 79 2d 63 6c 61 73 73 20 69 73 20 6d 73 67 3a  fy-class is msg:
32f0: 75 6e 6c 6f 63 6b 0a 3a 6e 6f 6e 61 6d 65 20 32  unlock.:noname 2
3300: 64 72 6f 70 20 36 34 64 72 6f 70 20 3b 20 6d 73  drop 64drop ; ms
3310: 67 2d 6e 6f 74 69 66 79 2d 63 6c 61 73 73 20 69  g-notify-class i
3320: 73 20 6d 73 67 3a 70 65 72 6d 73 0a 27 20 64 72  s msg:perms.' dr
3330: 6f 70 20 20 6d 73 67 2d 6e 6f 74 69 66 79 2d 63  op  msg-notify-c
3340: 6c 61 73 73 20 69 73 20 6d 73 67 3a 61 77 61 79  lass is msg:away
3350: 0a 27 20 32 64 72 6f 70 20 6d 73 67 2d 6e 6f 74  .' 2drop msg-not
3360: 69 66 79 2d 63 6c 61 73 73 20 69 73 20 6d 73 67  ify-class is msg
3370: 3a 63 6f 6f 72 64 0a 3a 6e 6f 6e 61 6d 65 20 32  :coord.:noname 2
3380: 64 72 6f 70 20 32 64 72 6f 70 20 3b 20 6d 73 67  drop 2drop ; msg
3390: 2d 6e 6f 74 69 66 79 2d 63 6c 61 73 73 20 69 73  -notify-class is
33a0: 20 6d 73 67 3a 6f 74 72 69 66 79 0a 3a 6e 6f 6e   msg:otrify.:non
33b0: 61 6d 65 20 28 20 2d 2d 20 29 20 6d 73 67 2d 6e  ame ( -- ) msg-n
33c0: 6f 74 69 66 79 20 3b 20 6d 73 67 2d 6e 6f 74 69  otify ; msg-noti
33d0: 66 79 2d 63 6c 61 73 73 20 69 73 20 6d 73 67 3a  fy-class is msg:
33e0: 65 6e 64 0a 3a 6e 6f 6e 61 6d 65 20 28 20 78 63  end.:noname ( xc
33f0: 68 61 72 20 2d 2d 20 29 20 5b 27 5d 20 78 65 6d  har -- ) ['] xem
3400: 69 74 20 24 74 6d 70 20 6e 6f 74 69 66 79 2b 20  it $tmp notify+ 
3410: 3b 20 6d 73 67 2d 6e 6f 74 69 66 79 2d 63 6c 61  ; msg-notify-cla
3420: 73 73 20 69 73 20 6d 73 67 3a 6c 69 6b 65 0a 0a  ss is msg:like..
3430: 3a 6e 6f 6e 61 6d 65 20 28 20 61 64 64 72 20 75  :noname ( addr u
3440: 20 2d 2d 20 29 0a 20 20 20 20 6c 61 73 74 23 20   -- ).    last# 
3450: 3e 72 20 20 32 64 75 70 20 6b 65 79 7c 20 74 6f  >r  2dup key| to
3460: 20 6d 73 67 3a 69 64 24 0a 20 20 20 20 2e 6c 6f   msg:id$.    .lo
3470: 67 2d 6e 75 6d 0a 20 20 20 20 32 64 75 70 20 73  g-num.    2dup s
3480: 74 61 72 74 64 61 74 65 40 20 2e 6c 6f 67 2d 64  tartdate@ .log-d
3490: 61 74 65 0a 20 20 20 20 32 64 75 70 20 65 6e 64  ate.    2dup end
34a0: 64 61 74 65 40 20 2e 6c 6f 67 2d 65 6e 64 0a 20  date@ .log-end. 
34b0: 20 20 20 2e 6b 65 79 2d 69 64 20 2e 22 20 3a 20     .key-id ." : 
34c0: 22 20 0a 20 20 20 20 72 3e 20 74 6f 20 6c 61 73  " .    r> to las
34d0: 74 23 20 3b 20 6d 73 67 2d 63 6c 61 73 73 20 69  t# ; msg-class i
34e0: 73 20 6d 73 67 3a 73 74 61 72 74 0a 3a 6e 6f 6e  s msg:start.:non
34f0: 61 6d 65 20 28 20 61 64 64 72 20 75 20 2d 2d 20  ame ( addr u -- 
3500: 29 20 24 75 74 66 38 3e 0a 20 20 20 20 3c 77 61  ) $utf8>.    <wa
3510: 72 6e 3e 20 27 23 27 20 66 6f 72 74 68 3a 65 6d  rn> '#' forth:em
3520: 69 74 20 2e 67 72 6f 75 70 20 3c 64 65 66 61 75  it .group <defau
3530: 6c 74 3e 20 3b 20 6d 73 67 2d 63 6c 61 73 73 20  lt> ; msg-class 
3540: 69 73 20 6d 73 67 3a 74 61 67 0a 3a 6e 6f 6e 61  is msg:tag.:nona
3550: 6d 65 20 28 20 61 64 64 72 20 75 20 2d 2d 20 29  me ( addr u -- )
3560: 20 6c 61 73 74 23 20 3e 72 0a 20 20 20 20 6b 65   last# >r.    ke
3570: 79 7c 20 32 64 75 70 20 30 20 2e 70 6b 40 20 6b  y| 2dup 0 .pk@ k
3580: 65 79 7c 20 73 74 72 3d 0a 20 20 20 20 49 46 20  ey| str=.    IF 
3590: 20 20 3c 65 72 72 3e 20 20 54 48 45 4e 20 2e 22    <err>  THEN ."
35a0: 20 40 22 20 2e 6b 65 79 2d 69 64 3f 20 3c 64 65   @" .key-id? <de
35b0: 66 61 75 6c 74 3e 0a 20 20 20 20 72 3e 20 74 6f  fault>.    r> to
35c0: 20 6c 61 73 74 23 20 3b 20 6d 73 67 2d 63 6c 61   last# ; msg-cla
35d0: 73 73 20 69 73 20 6d 73 67 3a 73 69 67 6e 61 6c  ss is msg:signal
35e0: 0a 3a 6e 6f 6e 61 6d 65 20 28 20 61 64 64 72 20  .:noname ( addr 
35f0: 75 20 2d 2d 20 29 0a 20 20 20 20 6c 61 73 74 23  u -- ).    last#
3600: 20 3e 72 20 6c 61 73 74 23 20 24 40 20 3e 67 72   >r last# $@ >gr
3610: 6f 75 70 0a 20 20 20 20 32 64 75 70 20 73 69 67  oup.    2dup sig
3620: 68 61 73 68 3f 20 49 46 20 20 3c 69 6e 66 6f 3e  hash? IF  <info>
3630: 20 20 45 4c 53 45 20 20 3c 65 72 72 3e 20 20 54    ELSE  <err>  T
3640: 48 45 4e 0a 20 20 20 20 2e 22 20 20 3c 22 20 6f  HEN.    ."  <" o
3650: 76 65 72 20 6c 65 2d 36 34 40 20 2e 74 69 63 6b  ver le-64@ .tick
3660: 73 0a 20 20 20 20 76 65 72 62 6f 73 65 28 20 64  s.    verbose( d
3670: 75 70 20 6b 65 79 73 69 7a 65 20 2d 20 2f 73 74  up keysize - /st
3680: 72 69 6e 67 20 2e 22 20 2c 22 20 38 35 74 79 70  ring ." ," 85typ
3690: 65 20 29 65 6c 73 65 28 20 32 64 72 6f 70 20 29  e )else( 2drop )
36a0: 20 3c 64 65 66 61 75 6c 74 3e 0a 20 20 20 20 72   <default>.    r
36b0: 3e 20 74 6f 20 6c 61 73 74 23 20 3b 20 6d 73 67  > to last# ; msg
36c0: 2d 63 6c 61 73 73 20 69 73 20 6d 73 67 3a 63 68  -class is msg:ch
36d0: 61 69 6e 0a 3a 6e 6f 6e 61 6d 65 20 28 20 61 64  ain.:noname ( ad
36e0: 64 72 20 75 20 2d 2d 20 29 0a 20 20 20 20 73 70  dr u -- ).    sp
36f0: 61 63 65 20 3c 77 61 72 6e 3e 20 2e 22 20 5b 22  ace <warn> ." ["
3700: 20 38 35 74 79 70 65 20 2e 22 20 5d 2d 3e 22 20   85type ." ]->" 
3710: 3c 64 65 66 61 75 6c 74 3e 20 3b 20 6d 73 67 2d  <default> ; msg-
3720: 63 6c 61 73 73 20 69 73 20 6d 73 67 3a 72 65 0a  class is msg:re.
3730: 3a 6e 6f 6e 61 6d 65 20 28 20 61 64 64 72 20 75  :noname ( addr u
3740: 20 2d 2d 20 29 0a 20 20 20 20 73 70 61 63 65 20   -- ).    space 
3750: 3c 77 61 72 6e 3e 20 2e 22 20 5b 22 20 38 35 74  <warn> ." [" 85t
3760: 79 70 65 20 2e 22 20 5d 3a 22 20 3c 64 65 66 61  ype ." ]:" <defa
3770: 75 6c 74 3e 20 3b 20 6d 73 67 2d 63 6c 61 73 73  ult> ; msg-class
3780: 20 69 73 20 6d 73 67 3a 69 64 0a 3a 6e 6f 6e 61   is msg:id.:nona
3790: 6d 65 20 28 20 61 64 64 72 20 75 20 2d 2d 20 29  me ( addr u -- )
37a0: 20 24 75 74 66 38 3e 20 66 6f 72 74 68 3a 74 79   $utf8> forth:ty
37b0: 70 65 20 3b 20 6d 73 67 2d 63 6c 61 73 73 20 69  pe ; msg-class i
37c0: 73 20 6d 73 67 3a 74 65 78 74 0a 3a 6e 6f 6e 61  s msg:text.:nona
37d0: 6d 65 20 28 20 61 64 64 72 20 75 20 2d 2d 20 29  me ( addr u -- )
37e0: 20 24 75 74 66 38 3e 0a 20 20 20 20 3c 77 61 72   $utf8>.    <war
37f0: 6e 3e 20 66 6f 72 74 68 3a 74 79 70 65 20 3c 64  n> forth:type <d
3800: 65 66 61 75 6c 74 3e 20 3b 20 6d 73 67 2d 63 6c  efault> ; msg-cl
3810: 61 73 73 20 69 73 20 6d 73 67 3a 75 72 6c 0a 3a  ass is msg:url.:
3820: 6e 6f 6e 61 6d 65 20 28 20 78 63 68 61 72 20 2d  noname ( xchar -
3830: 2d 20 29 0a 20 20 20 20 3c 69 6e 66 6f 3e 20 75  - ).    <info> u
3840: 74 66 38 65 6d 69 74 20 3c 64 65 66 61 75 6c 74  tf8emit <default
3850: 3e 20 3b 20 6d 73 67 2d 63 6c 61 73 73 20 69 73  > ; msg-class is
3860: 20 6d 73 67 3a 6c 69 6b 65 0a 3a 6e 6f 6e 61 6d   msg:like.:nonam
3870: 65 20 28 20 61 64 64 72 20 75 20 2d 2d 20 29 0a  e ( addr u -- ).
3880: 20 20 20 20 30 20 2e 76 2d 64 65 63 24 20 64 75      0 .v-dec$ du
3890: 70 20 49 46 0a 09 6d 73 67 2d 6b 65 79 21 20 20  p IF..msg-key!  
38a0: 6d 73 67 2d 67 72 6f 75 70 2d 6f 20 2e 6d 73 67  msg-group-o .msg
38b0: 3a 2b 6c 6f 63 6b 0a 09 3c 69 6e 66 6f 3e 20 2e  :+lock..<info> .
38c0: 22 20 63 68 61 74 20 69 73 20 6c 6f 63 6b 65 64  " chat is locked
38d0: 22 20 3c 64 65 66 61 75 6c 74 3e 0a 20 20 20 20  " <default>.    
38e0: 45 4c 53 45 20 20 32 64 72 6f 70 0a 09 3c 65 72  ELSE  2drop..<er
38f0: 72 3e 20 2e 22 20 6c 6f 63 6b 65 64 20 6f 75 74  r> ." locked out
3900: 20 6f 66 20 63 68 61 74 22 20 3c 64 65 66 61 75   of chat" <defau
3910: 6c 74 3e 0a 20 20 20 20 54 48 45 4e 20 3b 20 6d  lt>.    THEN ; m
3920: 73 67 2d 63 6c 61 73 73 20 69 73 20 6d 73 67 3a  sg-class is msg:
3930: 6c 6f 63 6b 0a 3a 6e 6f 6e 61 6d 65 20 28 20 2d  lock.:noname ( -
3940: 2d 20 29 20 20 6d 73 67 2d 67 72 6f 75 70 2d 6f  - )  msg-group-o
3950: 20 2e 6d 73 67 3a 2d 6c 6f 63 6b 0a 20 20 20 20   .msg:-lock.    
3960: 3c 69 6e 66 6f 3e 20 2e 22 20 63 68 61 74 20 69  <info> ." chat i
3970: 73 20 66 72 65 65 20 66 6f 72 20 61 6c 6c 22 20  s free for all" 
3980: 3c 64 65 66 61 75 6c 74 3e 20 3b 20 6d 73 67 2d  <default> ; msg-
3990: 63 6c 61 73 73 20 69 73 20 6d 73 67 3a 75 6e 6c  class is msg:unl
39a0: 6f 63 6b 0a 27 20 64 72 6f 70 20 6d 73 67 2d 63  ock.' drop msg-c
39b0: 6c 61 73 73 20 69 73 20 6d 73 67 3a 61 77 61 79  lass is msg:away
39c0: 0a 3a 20 2e 70 65 72 6d 73 20 28 20 6e 20 2d 2d  .: .perms ( n --
39d0: 20 29 0a 20 20 20 20 22 ef 94 85 ef 94 82 ef 94   ).    "ď”
39e0: 81 f0 9f 91 b9 22 20 62 6f 75 6e 64 73 20 55 2b  👹" bounds U+
39f0: 44 4f 0a 09 64 75 70 20 31 20 61 6e 64 20 49 46  DO..dup 1 and IF
3a00: 20 20 49 20 78 63 40 20 78 65 6d 69 74 20 20 54    I xc@ xemit  T
3a10: 48 45 4e 20 20 32 2f 0a 20 20 20 20 49 20 49 27  HEN  2/.    I I'
3a20: 20 6f 76 65 72 20 2d 20 78 2d 73 69 7a 65 20 20   over - x-size  
3a30: 2b 4c 4f 4f 50 20 20 64 72 6f 70 20 3b 0a 3a 6e  +LOOP  drop ;.:n
3a40: 6f 6e 61 6d 65 20 7b 20 36 34 5e 20 70 65 72 6d  oname { 64^ perm
3a50: 20 64 3a 20 70 6b 20 2d 2d 20 7d 0a 20 20 20 20   d: pk -- }.    
3a60: 70 65 72 6d 20 5b 20 31 20 36 34 73 20 5d 4c 20  perm [ 1 64s ]L 
3a70: 70 6b 20 6d 73 67 2d 67 72 6f 75 70 2d 6f 20 2e  pk msg-group-o .
3a80: 6d 73 67 3a 70 65 72 6d 73 23 20 23 21 0a 20 20  msg:perms# #!.  
3a90: 20 20 70 6b 20 2e 6b 65 79 2d 69 64 20 2e 22 20    pk .key-id ." 
3aa0: 3a 20 22 20 70 65 72 6d 20 36 34 40 20 36 34 3e  : " perm 64@ 64>
3ab0: 6e 20 2e 70 65 72 6d 73 20 73 70 61 63 65 0a 3b  n .perms space.;
3ac0: 20 6d 73 67 2d 63 6c 61 73 73 20 69 73 20 6d 73   msg-class is ms
3ad0: 67 3a 70 65 72 6d 73 0a 3a 6e 6f 6e 61 6d 65 20  g:perms.:noname 
3ae0: 28 20 61 64 64 72 20 75 20 74 79 70 65 20 2d 2d  ( addr u type --
3af0: 20 29 0a 20 20 20 20 73 70 61 63 65 20 3c 77 61   ).    space <wa
3b00: 72 6e 3e 20 63 61 73 65 0a 09 6d 73 67 3a 69 6d  rn> case..msg:im
3b10: 61 67 65 23 20 20 20 20 20 6f 66 20 20 2e 22 20  age#     of  ." 
3b20: 69 6d 67 5b 22 20 20 20 20 20 20 38 35 74 79 70  img["      85typ
3b30: 65 20 20 65 6e 64 6f 66 0a 09 6d 73 67 3a 74 68  e  endof..msg:th
3b40: 75 6d 62 6e 61 69 6c 23 20 6f 66 20 20 2e 22 20  umbnail# of  ." 
3b50: 74 68 75 6d 62 5b 22 20 20 20 20 38 35 74 79 70  thumb["    85typ
3b60: 65 20 20 65 6e 64 6f 66 0a 09 6d 73 67 3a 70 61  e  endof..msg:pa
3b70: 74 63 68 23 20 20 20 20 20 6f 66 20 20 2e 22 20  tch#     of  ." 
3b80: 70 61 74 63 68 5b 22 20 20 20 20 38 35 74 79 70  patch["    85typ
3b90: 65 20 20 65 6e 64 6f 66 0a 09 6d 73 67 3a 73 6e  e  endof..msg:sn
3ba0: 61 70 73 68 6f 74 23 20 20 6f 66 20 20 2e 22 20  apshot#  of  ." 
3bb0: 73 6e 61 70 73 68 6f 74 5b 22 20 38 35 74 79 70  snapshot[" 85typ
3bc0: 65 20 20 65 6e 64 6f 66 0a 09 6d 73 67 3a 6d 65  e  endof..msg:me
3bd0: 73 73 61 67 65 23 20 20 20 6f 66 20 20 2e 22 20  ssage#   of  ." 
3be0: 6d 65 73 73 61 67 65 5b 22 20 20 38 35 74 79 70  message["  85typ
3bf0: 65 20 20 65 6e 64 6f 66 0a 09 64 72 6f 70 0a 09  e  endof..drop..
3c00: 32 64 75 70 20 6b 65 79 73 69 7a 65 20 2f 73 74  2dup keysize /st
3c10: 72 69 6e 67 0a 09 32 64 75 70 20 70 72 69 6e 74  ring..2dup print
3c20: 61 62 6c 65 3f 20 49 46 20 20 27 5b 27 20 65 6d  able? IF  '[' em
3c30: 69 74 20 20 74 79 70 65 20 27 40 27 20 65 6d 69  it  type '@' emi
3c40: 74 0a 09 45 4c 53 45 20 20 2e 22 20 23 5b 22 20  t..ELSE  ." #[" 
3c50: 20 38 35 74 79 70 65 20 2e 22 20 2f 40 22 20 20   85type ." /@"  
3c60: 54 48 45 4e 0a 09 6b 65 79 7c 20 2e 6b 65 79 2d  THEN..key| .key-
3c70: 69 64 0a 09 30 0a 20 20 20 20 65 6e 64 63 61 73  id..0.    endcas
3c80: 65 20 2e 22 20 5d 22 20 3c 64 65 66 61 75 6c 74  e ." ]" <default
3c90: 3e 20 3b 0a 6d 73 67 2d 63 6c 61 73 73 20 69 73  > ;.msg-class is
3ca0: 20 6d 73 67 3a 6f 62 6a 65 63 74 0a 3a 6e 6f 6e   msg:object.:non
3cb0: 61 6d 65 20 28 20 61 64 64 72 20 75 20 2d 2d 20  ame ( addr u -- 
3cc0: 29 20 24 75 74 66 38 3e 0a 20 20 20 20 3c 77 61  ) $utf8>.    <wa
3cd0: 72 6e 3e 20 66 6f 72 74 68 3a 74 79 70 65 20 3c  rn> forth:type <
3ce0: 64 65 66 61 75 6c 74 3e 20 3b 20 6d 73 67 2d 63  default> ; msg-c
3cf0: 6c 61 73 73 20 69 73 20 6d 73 67 3a 61 63 74 69  lass is msg:acti
3d00: 6f 6e 0a 3a 6e 6f 6e 61 6d 65 20 28 20 61 64 64  on.:noname ( add
3d10: 72 20 75 20 2d 2d 20 29 0a 20 20 20 20 3c 77 61  r u -- ).    <wa
3d20: 72 6e 3e 20 2e 22 20 20 47 50 53 3a 20 22 20 2e  rn> ."  GPS: " .
3d30: 63 6f 6f 72 64 73 20 3c 64 65 66 61 75 6c 74 3e  coords <default>
3d40: 20 3b 20 6d 73 67 2d 63 6c 61 73 73 20 69 73 20   ; msg-class is 
3d50: 6d 73 67 3a 63 6f 6f 72 64 0a 0a 3a 20 77 61 69  msg:coord..: wai
3d60: 74 2d 32 73 2d 6b 65 79 20 28 20 2d 2d 20 29 0a  t-2s-key ( -- ).
3d70: 20 20 20 20 6e 74 69 6d 65 20 35 30 20 30 20 44      ntime 50 0 D
3d80: 4f 20 20 6b 65 79 3f 20 3f 4c 45 41 56 45 0a 20  O  key? ?LEAVE. 
3d90: 20 20 20 32 64 75 70 20 69 20 23 34 30 30 30 30     2dup i #40000
3da0: 30 30 30 20 75 6d 2a 20 64 2b 20 64 65 61 64 6c  000 um* d+ deadl
3db0: 69 6e 65 20 20 4c 4f 4f 50 20 20 32 64 72 6f 70  ine  LOOP  2drop
3dc0: 20 3b 0a 3a 20 78 63 6c 65 61 72 20 28 20 61 64   ;.: xclear ( ad
3dd0: 64 72 20 75 20 2d 2d 20 29 20 78 2d 77 69 64 74  dr u -- ) x-widt
3de0: 68 20 31 2b 20 78 2d 65 72 61 73 65 20 3b 0a 0a  h 1+ x-erase ;..
3df0: 3a 6e 6f 6e 61 6d 65 20 28 20 2d 2d 20 29 0a 20  :noname ( -- ). 
3e00: 20 20 20 3c 69 6e 66 6f 3e 0a 20 20 20 20 5b 3a     <info>.    [:
3e10: 20 2e 22 20 6e 6f 62 6f 64 79 27 73 20 6f 6e 6c   ." nobody's onl
3e20: 69 6e 65 22 20 6d 73 67 2d 67 72 6f 75 70 2d 6f  ine" msg-group-o
3e30: 20 2e 6d 73 67 3a 3f 6f 74 72 20 30 3d 20 49 46   .msg:?otr 0= IF
3e40: 20 2e 22 20 2c 20 73 61 76 69 6e 67 20 61 77 61   ." , saving awa
3e50: 79 22 20 20 54 48 45 4e 20 3b 5d 20 24 74 6d 70  y"  THEN ;] $tmp
3e60: 0a 20 20 20 20 32 64 75 70 20 74 79 70 65 20 3c  .    2dup type <
3e70: 64 65 66 61 75 6c 74 3e 0a 20 20 20 20 77 61 69  default>.    wai
3e80: 74 2d 32 73 2d 6b 65 79 20 78 63 6c 65 61 72 20  t-2s-key xclear 
3e90: 3b 20 6d 73 67 2d 63 6c 61 73 73 20 69 73 20 6d  ; msg-class is m
3ea0: 73 67 3a 2e 6e 6f 62 6f 64 79 0a 0a 5c 20 65 6e  sg:.nobody..\ en
3eb0: 63 72 79 70 74 2b 73 69 67 6e 0a 5c 20 66 65 61  crypt+sign.\ fea
3ec0: 74 75 72 65 73 3a 20 73 69 67 6e 61 74 75 72 65  tures: signature
3ed0: 20 76 65 72 69 66 69 63 61 74 69 6f 6e 20 6f 6e   verification on
3ee0: 6c 79 20 77 68 65 6e 20 6b 65 79 20 69 73 20 6b  ly when key is k
3ef0: 6e 6f 77 6e 0a 5c 20 20 20 20 20 20 20 20 20 20  nown.\          
3f00: 20 69 64 65 6e 74 69 74 79 20 6f 6e 6c 79 20 72   identity only r
3f10: 65 76 65 61 6c 65 64 20 77 68 65 6e 20 63 6f 72  evealed when cor
3f20: 72 65 63 74 6c 79 20 64 65 63 72 79 70 74 65 64  rectly decrypted
3f30: 0a 0a 3a 20 6d 73 67 2d 64 65 63 2d 73 69 67 3f  ..: msg-dec-sig?
3f40: 20 28 20 61 64 64 72 20 75 20 2d 2d 20 61 64 64   ( addr u -- add
3f50: 72 27 20 75 27 20 66 6c 61 67 20 29 0a 20 20 20  r' u' flag ).   
3f60: 20 73 69 67 70 6b 73 69 7a 65 23 20 2d 20 32 64   sigpksize# - 2d
3f70: 75 70 20 2b 20 7b 20 70 6b 73 69 67 20 7d 0a 20  up + { pksig }. 
3f80: 20 20 20 6d 73 67 2d 67 72 6f 75 70 2d 6f 20 2e     msg-group-o .
3f90: 6d 73 67 3a 6b 65 79 73 5b 5d 20 24 40 20 62 6f  msg:keys[] $@ bo
3fa0: 75 6e 64 73 20 55 2b 44 4f 0a 09 49 20 24 40 20  unds U+DO..I $@ 
3fb0: 32 6f 76 65 72 20 70 6b 73 69 67 20 64 65 63 72  2over pksig decr
3fc0: 79 70 74 2d 73 69 67 3f 0a 09 64 75 70 20 2d 35  ypt-sig?..dup -5
3fd0: 20 3c 3e 20 49 46 0a 09 20 20 20 20 3e 72 20 32   <> IF..    >r 2
3fe0: 6e 69 70 20 72 3e 20 75 6e 6c 6f 6f 70 20 20 45  nip r> unloop  E
3ff0: 58 49 54 0a 09 54 48 45 4e 20 20 64 72 6f 70 20  XIT..THEN  drop 
4000: 32 64 72 6f 70 0a 20 20 20 20 63 65 6c 6c 20 2b  2drop.    cell +
4010: 4c 4f 4f 50 0a 20 20 20 20 73 69 67 70 6b 73 69  LOOP.    sigpksi
4020: 7a 65 23 20 2b 20 20 2d 35 20 3b 0a 0a 3a 20 6d  ze# +  -5 ;..: m
4030: 73 67 2d 73 69 67 3f 20 28 20 61 64 64 72 20 75  sg-sig? ( addr u
4040: 20 2d 2d 20 61 64 64 72 20 75 27 20 66 6c 61 67   -- addr u' flag
4050: 20 29 0a 20 20 20 20 73 6b 69 70 2d 73 69 67 3f   ).    skip-sig?
4060: 20 40 20 49 46 20 20 20 71 75 69 63 6b 73 69 67   @ IF   quicksig
4070: 28 20 70 6b 2d 71 75 69 63 6b 2d 73 69 67 3f 20  ( pk-quick-sig? 
4080: 29 65 6c 73 65 28 20 70 6b 2d 64 61 74 65 3f 20  )else( pk-date? 
4090: 29 0a 20 20 20 20 45 4c 53 45 20 20 70 6b 2d 73  ).    ELSE  pk-s
40a0: 69 67 3f 20 20 54 48 45 4e 20 3b 0a 0a 3a 20 6d  ig?  THEN ;..: m
40b0: 73 67 2d 64 65 63 3f 2d 73 69 67 3f 20 28 20 61  sg-dec?-sig? ( a
40c0: 64 64 72 20 75 20 2d 2d 20 61 64 64 72 27 20 75  ddr u -- addr' u
40d0: 27 20 66 6c 61 67 20 29 0a 20 20 20 20 32 64 75  ' flag ).    2du
40e0: 70 20 32 20 2d 20 2b 20 63 40 20 24 38 30 20 61  p 2 - + c@ $80 a
40f0: 6e 64 20 49 46 20 20 6d 73 67 2d 64 65 63 2d 73  nd IF  msg-dec-s
4100: 69 67 3f 20 20 45 4c 53 45 20 20 6d 73 67 2d 73  ig?  ELSE  msg-s
4110: 69 67 3f 20 20 54 48 45 4e 20 3b 0a 0a 3a 20 72  ig?  THEN ;..: r
4120: 65 70 6c 61 63 65 2d 73 69 67 20 7b 20 61 64 64  eplace-sig { add
4130: 72 73 69 67 20 75 73 69 67 20 61 64 64 72 6d 73  rsig usig addrms
4140: 67 20 75 6d 73 67 20 2d 2d 20 7d 0a 20 20 20 20  g umsg -- }.    
4150: 61 64 64 72 73 69 67 20 75 73 69 67 20 61 64 64  addrsig usig add
4160: 72 6d 73 67 20 75 6d 73 67 20 75 73 69 67 20 2d  rmsg umsg usig -
4170: 20 5b 3a 20 74 79 70 65 20 74 79 70 65 20 3b 5d   [: type type ;]
4180: 20 24 74 6d 70 0a 20 20 20 20 32 64 75 70 20 6d   $tmp.    2dup m
4190: 73 67 2d 64 65 63 3f 2d 73 69 67 3f 20 21 21 73  sg-dec?-sig? !!s
41a0: 69 67 21 21 20 32 64 72 6f 70 20 61 64 64 72 6d  ig!! 2drop addrm
41b0: 73 67 20 75 6d 73 67 20 73 6d 6f 76 65 20 3b 0a  sg umsg smove ;.
41c0: 3a 20 6e 65 77 2d 6f 74 72 73 69 67 20 28 20 61  : new-otrsig ( a
41d0: 64 64 72 20 75 20 66 6c 61 67 20 2d 2d 20 61 64  ddr u flag -- ad
41e0: 64 72 73 69 67 20 75 73 69 67 20 29 0a 20 20 20  drsig usig ).   
41f0: 20 3e 72 20 32 64 75 70 20 73 74 61 72 74 64 61   >r 2dup startda
4200: 74 65 40 20 6f 6c 64 3e 6f 74 72 0a 20 20 20 20  te@ old>otr.    
4210: 70 72 65 64 61 74 65 2d 6b 65 79 20 6b 65 63 63  predate-key kecc
4220: 61 6b 23 20 63 3a 6b 65 79 40 20 63 3a 6b 65 79  ak# c:key@ c:key
4230: 23 20 73 6d 6f 76 65 0a 20 20 20 20 5b 3a 20 73  # smove.    [: s
4240: 6b 74 6d 70 20 70 6b 6d 6f 64 20 73 6b 40 20 64  ktmp pkmod sk@ d
4250: 72 6f 70 20 3e 6d 6f 64 6b 65 79 20 2e 65 6e 63  rop >modkey .enc
4260: 73 69 67 6e 2d 72 65 73 74 20 3b 5d 0a 20 20 20  sign-rest ;].   
4270: 20 5b 27 5d 20 2e 73 69 67 20 72 40 20 73 65 6c   ['] .sig r@ sel
4280: 65 63 74 20 24 74 6d 70 0a 20 20 20 20 32 64 75  ect $tmp.    2du
4290: 70 20 2b 20 32 20 2d 20 72 3e 20 73 77 61 70 20  p + 2 - r> swap 
42a0: 6f 72 63 21 0a 20 20 20 20 28 20 32 64 75 70 20  orc!.    ( 2dup 
42b0: 64 75 6d 70 20 29 20 31 20 36 34 73 20 2f 73 74  dump ) 1 64s /st
42c0: 72 69 6e 67 20 3b 0a 0a 3a 6e 6f 6e 61 6d 65 20  ring ;..:noname 
42d0: 7b 20 73 69 67 20 75 27 20 61 64 64 72 20 75 20  { sig u' addr u 
42e0: 2d 2d 20 7d 0a 20 20 20 20 75 27 20 36 34 27 2b  -- }.    u' 64'+
42f0: 20 75 20 3d 20 20 75 20 73 69 67 73 69 7a 65 23   u =  u sigsize#
4300: 20 3d 20 61 6e 64 20 49 46 0a 09 6c 61 73 74 23   = and IF..last#
4310: 20 3e 72 20 6c 61 73 74 23 20 24 40 20 3e 67 72   >r last# $@ >gr
4320: 6f 75 70 0a 09 61 64 64 72 20 75 20 73 74 61 72  oup..addr u star
4330: 74 64 61 74 65 40 20 36 34 64 75 70 20 64 61 74  tdate@ 64dup dat
4340: 65 3e 69 20 3e 72 20 36 34 23 31 20 36 34 2b 20  e>i >r 64#1 64+ 
4350: 64 61 74 65 3e 69 27 20 72 3e 0a 09 32 64 75 70  date>i' r>..2dup
4360: 20 3d 20 49 46 20 20 2e 22 20 20 5b 6f 74 72 69   = IF  ."  [otri
4370: 66 69 65 64 5d 20 22 20 20 61 64 64 72 20 75 20  fied] "  addr u 
4380: 73 74 61 72 74 64 61 74 65 40 20 2e 74 69 63 6b  startdate@ .tick
4390: 73 20 20 54 48 45 4e 0a 09 55 2b 44 4f 0a 09 20  s  THEN..U+DO.. 
43a0: 20 20 20 49 20 6d 73 67 2d 67 72 6f 75 70 2d 6f     I msg-group-o
43b0: 20 2e 6d 73 67 3a 6c 6f 67 5b 5d 20 24 5b 5d 40   .msg:log[] $[]@
43c0: 0a 09 20 20 20 20 32 64 75 70 20 2b 20 32 20 2d  ..    2dup + 2 -
43d0: 20 63 40 20 24 38 30 20 61 6e 64 20 49 46 20 20   c@ $80 and IF  
43e0: 6d 73 67 2d 64 65 63 2d 73 69 67 3f 20 64 72 6f  msg-dec-sig? dro
43f0: 70 20 20 54 48 45 4e 0a 09 20 20 20 20 32 64 75  p  THEN..    2du
4400: 70 20 64 75 70 20 73 69 67 70 6b 73 69 7a 65 23  p dup sigpksize#
4410: 20 2d 20 2f 73 74 72 69 6e 67 20 6b 65 79 7c 20   - /string key| 
4420: 6d 73 67 3a 69 64 24 20 73 74 72 3d 20 49 46 0a  msg:id$ str= IF.
4430: 09 09 64 75 70 20 75 20 2d 20 2f 73 74 72 69 6e  ..dup u - /strin
4440: 67 20 61 64 64 72 20 75 20 73 74 72 3d 20 49 46  g addr u str= IF
4450: 0a 09 09 20 20 20 20 2e 22 20 20 4f 54 52 69 66  ...    ."  OTRif
4460: 79 20 23 22 20 49 20 75 2e 0a 09 09 20 20 20 20  y #" I u....    
4470: 73 69 67 20 75 27 20 49 20 6d 73 67 2d 67 72 6f  sig u' I msg-gro
4480: 75 70 2d 6f 20 2e 6d 73 67 3a 6c 6f 67 5b 5d 20  up-o .msg:log[] 
4490: 24 5b 5d 40 20 72 65 70 6c 61 63 65 2d 73 69 67  $[]@ replace-sig
44a0: 0a 09 09 20 20 20 20 73 61 76 65 2d 6d 73 67 73  ...    save-msgs
44b0: 26 0a 09 09 45 4c 53 45 0a 09 09 20 20 20 20 2e  &...ELSE...    .
44c0: 22 20 20 5b 4f 54 52 69 66 69 65 64 5d 20 23 22  "  [OTRified] #"
44d0: 20 49 20 75 2e 0a 09 09 54 48 45 4e 0a 09 20 20   I u....THEN..  
44e0: 20 20 45 4c 53 45 0a 09 09 2e 22 20 20 49 44 20    ELSE...."  ID 
44f0: 6d 69 73 6d 61 74 63 68 3a 20 22 0a 09 09 32 64  mismatch: "...2d
4500: 75 70 20 64 75 70 20 73 69 67 70 6b 73 69 7a 65  up dup sigpksize
4510: 23 20 2d 20 2f 73 74 72 69 6e 67 20 6b 65 79 7c  # - /string key|
4520: 20 38 35 74 79 70 65 20 73 70 61 63 65 0a 09 09   85type space...
4530: 6d 73 67 3a 69 64 24 20 38 35 74 79 70 65 20 66  msg:id$ 85type f
4540: 6f 72 74 68 3a 63 72 0a 09 09 32 64 72 6f 70 0a  orth:cr...2drop.
4550: 09 20 20 20 20 54 48 45 4e 0a 09 4c 4f 4f 50 0a  .    THEN..LOOP.
4560: 09 72 3e 20 74 6f 20 6c 61 73 74 23 0a 20 20 20  .r> to last#.   
4570: 20 54 48 45 4e 20 3b 20 6d 73 67 2d 63 6c 61 73   THEN ; msg-clas
4580: 73 20 69 73 20 6d 73 67 3a 6f 74 72 69 66 79 0a  s is msg:otrify.
4590: 0a 3a 6e 6f 6e 61 6d 65 20 28 20 2d 2d 20 29 0a  .:noname ( -- ).
45a0: 20 20 20 20 66 6f 72 74 68 3a 63 72 20 3b 20 6d      forth:cr ; m
45b0: 73 67 2d 63 6c 61 73 73 20 69 73 20 6d 73 67 3a  sg-class is msg:
45c0: 65 6e 64 0a 0a 5c 67 20 0a 5c 67 20 23 23 23 20  end..\g .\g ### 
45d0: 67 72 6f 75 70 20 64 65 73 63 72 69 70 74 69 6f  group descriptio
45e0: 6e 20 63 6f 6d 6d 61 6e 64 73 20 23 23 23 0a 5c  n commands ###.\
45f0: 67 20 0a 0a 68 61 73 68 3a 20 67 72 6f 75 70 23  g ..hash: group#
4600: 0a 0a 73 74 61 74 69 63 2d 61 20 74 6f 20 61 6c  ..static-a to al
4610: 6c 6f 63 61 74 65 72 0a 61 6c 69 67 6e 20 68 65  locater.align he
4620: 72 65 0a 67 72 6f 75 70 73 2d 63 6c 61 73 73 20  re.groups-class 
4630: 6e 65 77 20 43 6f 6e 73 74 61 6e 74 20 67 72 6f  new Constant gro
4640: 75 70 2d 6f 0a 64 79 6e 61 6d 69 63 2d 61 20 74  up-o.dynamic-a t
4650: 6f 20 61 6c 6c 6f 63 61 74 65 72 0a 68 65 72 65  o allocater.here
4660: 20 6f 76 65 72 20 2d 20 32 43 6f 6e 73 74 61 6e   over - 2Constan
4670: 74 20 73 61 6d 70 6c 65 2d 67 72 6f 75 70 24 0a  t sample-group$.
4680: 0a 3a 20 6c 61 73 74 3e 6f 20 28 20 2d 2d 20 29  .: last>o ( -- )
4690: 0a 20 20 20 20 5c 47 20 75 73 65 20 6c 61 73 74  .    \G use last
46a0: 20 68 61 73 68 20 61 63 63 65 73 73 20 61 73 20   hash access as 
46b0: 6f 62 6a 65 63 74 0a 20 20 20 20 6c 61 73 74 23  object.    last#
46c0: 20 63 65 6c 6c 2b 20 24 40 20 64 72 6f 70 20 63   cell+ $@ drop c
46d0: 65 6c 6c 2b 20 3e 6f 20 72 64 72 6f 70 20 3b 0a  ell+ >o rdrop ;.
46e0: 0a 3a 20 6d 61 6b 65 2d 67 72 6f 75 70 20 28 20  .: make-group ( 
46f0: 61 64 64 72 20 75 20 2d 2d 20 6f 3a 67 72 6f 75  addr u -- o:grou
4700: 70 20 29 0a 20 20 20 20 73 61 6d 70 6c 65 2d 67  p ).    sample-g
4710: 72 6f 75 70 24 20 32 6f 76 65 72 20 67 72 6f 75  roup$ 2over grou
4720: 70 23 20 23 21 20 6c 61 73 74 3e 6f 20 74 6f 20  p# #! last>o to 
4730: 67 72 6f 75 70 73 3a 69 64 24 20 3b 0a 0a 63 6d  groups:id$ ;..cm
4740: 64 2d 74 61 62 6c 65 20 24 40 20 69 6e 68 65 72  d-table $@ inher
4750: 69 74 2d 74 61 62 6c 65 20 67 72 6f 75 70 2d 74  it-table group-t
4760: 61 62 6c 65 0a 0a 73 63 6f 70 65 7b 20 6e 65 74  able..scope{ net
4770: 32 6f 2d 62 61 73 65 0a 0a 24 32 30 20 6e 65 74  2o-base..$20 net
4780: 32 6f 3a 20 67 72 6f 75 70 2d 6e 61 6d 65 20 28  2o: group-name (
4790: 20 24 3a 6e 61 6d 65 20 2d 2d 20 29 20 5c 67 20   $:name -- ) \g 
47a0: 67 72 6f 75 70 20 73 79 6d 62 6f 6c 69 63 20 6e  group symbolic n
47b0: 61 6d 65 0a 20 20 20 20 24 3e 20 6d 61 6b 65 2d  ame.    $> make-
47c0: 67 72 6f 75 70 20 3b 0a 2b 6e 65 74 32 6f 3a 20  group ;.+net2o: 
47d0: 67 72 6f 75 70 2d 69 64 20 28 20 24 3a 67 72 6f  group-id ( $:gro
47e0: 75 70 20 2d 2d 20 29 20 5c 67 20 67 72 6f 75 70  up -- ) \g group
47f0: 20 69 64 2c 20 69 73 20 61 20 70 75 62 6b 65 79   id, is a pubkey
4800: 0a 20 20 20 20 67 72 6f 75 70 2d 6f 20 6f 20 3d  .    group-o o =
4810: 20 21 21 6e 6f 2d 67 72 6f 75 70 2d 6e 61 6d 65   !!no-group-name
4820: 21 21 20 24 3e 20 74 6f 20 67 72 6f 75 70 73 3a  !! $> to groups:
4830: 69 64 24 20 3b 0a 2b 6e 65 74 32 6f 3a 20 67 72  id$ ;.+net2o: gr
4840: 6f 75 70 2d 6d 65 6d 62 65 72 20 28 20 24 3a 6d  oup-member ( $:m
4850: 65 6d 62 65 72 6b 65 79 20 2d 2d 20 29 20 5c 67  emberkey -- ) \g
4860: 20 61 64 64 20 6d 65 6d 62 65 72 20 6b 65 79 0a   add member key.
4870: 20 20 20 20 67 72 6f 75 70 2d 6f 20 6f 20 3d 20      group-o o = 
4880: 21 21 6e 6f 2d 67 72 6f 75 70 2d 6e 61 6d 65 21  !!no-group-name!
4890: 21 20 24 3e 20 67 72 6f 75 70 73 3a 6d 65 6d 62  ! $> groups:memb
48a0: 65 72 5b 5d 20 24 2b 5b 5d 21 20 3b 0a 2b 6e 65  er[] $+[]! ;.+ne
48b0: 74 32 6f 3a 20 67 72 6f 75 70 2d 61 64 6d 69 6e  t2o: group-admin
48c0: 20 28 20 24 3a 61 64 6d 69 6e 6b 65 79 20 2d 2d   ( $:adminkey --
48d0: 20 29 20 5c 67 20 73 65 74 20 61 64 6d 69 6e 20   ) \g set admin 
48e0: 6b 65 79 0a 20 20 20 20 67 72 6f 75 70 2d 6f 20  key.    group-o 
48f0: 6f 20 3d 20 21 21 6e 6f 2d 67 72 6f 75 70 2d 6e  o = !!no-group-n
4900: 61 6d 65 21 21 20 24 3e 20 67 72 6f 75 70 73 3a  ame!! $> groups:
4910: 61 64 6d 69 6e 20 73 65 63 21 20 3b 0a 2b 6e 65  admin sec! ;.+ne
4920: 74 32 6f 3a 20 67 72 6f 75 70 2d 70 65 72 6d 73  t2o: group-perms
4930: 20 28 20 36 34 75 20 2d 2d 20 29 20 5c 67 20 70   ( 64u -- ) \g p
4940: 65 72 6d 69 73 73 69 6f 6e 2f 6d 6f 64 65 73 20  ermission/modes 
4950: 62 69 74 6d 61 73 6b 0a 20 20 20 20 67 72 6f 75  bitmask.    grou
4960: 70 2d 6f 20 6f 20 3d 20 21 21 6e 6f 2d 67 72 6f  p-o o = !!no-gro
4970: 75 70 2d 6e 61 6d 65 21 21 20 74 6f 20 67 72 6f  up-name!! to gro
4980: 75 70 73 3a 70 65 72 6d 73 23 20 3b 0a 0a 7d 73  ups:perms# ;..}s
4990: 63 6f 70 65 0a 0a 67 72 6f 75 70 2d 74 61 62 6c  cope..group-tabl
49a0: 65 20 24 73 61 76 65 0a 0a 67 72 6f 75 70 2d 74  e $save..group-t
49b0: 61 62 6c 65 20 40 20 67 72 6f 75 70 2d 6f 20 2e  able @ group-o .
49c0: 74 6f 6b 65 6e 2d 74 61 62 6c 65 20 21 0a 0a 27  token-table !..'
49d0: 20 63 6f 6e 74 65 78 74 2d 74 61 62 6c 65 20 69   context-table i
49e0: 73 20 67 65 6e 2d 74 61 62 6c 65 0a 0a 3a 20 2e  s gen-table..: .
49f0: 63 68 61 74 73 2f 67 72 6f 75 70 20 28 20 2d 2d  chats/group ( --
4a00: 20 61 64 64 72 20 75 20 29 0a 20 20 20 20 70 6b   addr u ).    pk
4a10: 40 20 70 6b 63 20 73 77 61 70 20 6d 6f 76 65 20  @ pkc swap move 
4a20: 20 73 6b 40 20 73 6b 63 20 73 77 61 70 20 6d 6f   sk@ skc swap mo
4a30: 76 65 20 5c 20 6e 6f 72 6d 61 6c 69 7a 65 20 70  ve \ normalize p
4a40: 6b 63 0a 20 20 20 20 70 6b 63 20 6b 65 79 73 69  kc.    pkc keysi
4a50: 7a 65 20 33 20 2a 20 5c 20 68 61 73 68 20 6f 66  ze 3 * \ hash of
4a60: 20 70 6b 63 2b 70 6b 31 2b 73 6b 63 20 6b 65 79   pkc+pk1+skc key
4a70: 65 64 20 77 69 74 68 20 22 67 72 6f 75 70 22 0a  ed with "group".
4a80: 20 20 20 20 22 67 72 6f 75 70 22 20 6b 65 79 65      "group" keye
4a90: 64 2d 68 61 73 68 23 31 32 38 20 2e 63 68 61 74  d-hash#128 .chat
4aa0: 73 2f 20 3b 0a 0a 3a 20 72 65 61 64 2d 63 68 61  s/ ;..: read-cha
4ab0: 74 67 72 6f 75 70 73 20 28 20 2d 2d 20 29 0a 20  tgroups ( -- ). 
4ac0: 20 20 20 30 20 2e 2e 63 68 61 74 73 2f 67 72 6f     0 ..chats/gro
4ad0: 75 70 20 5b 3a 20 74 79 70 65 20 2e 22 20 2e 76  up [: type ." .v
4ae0: 32 6f 22 20 3b 5d 20 24 74 6d 70 0a 20 20 20 20  2o" ;] $tmp.    
4af0: 32 64 75 70 20 66 69 6c 65 2d 73 74 61 74 75 73  2dup file-status
4b00: 20 6e 69 70 20 6e 6f 2d 66 69 6c 65 23 20 3d 20   nip no-file# = 
4b10: 49 46 20 20 32 64 72 6f 70 20 20 45 58 49 54 20  IF  2drop  EXIT 
4b20: 20 54 48 45 4e 0a 20 20 20 20 64 65 63 72 79 70   THEN.    decryp
4b30: 74 40 20 67 72 6f 75 70 2d 6f 20 2e 64 6f 2d 63  t@ group-o .do-c
4b40: 6d 64 2d 6c 6f 6f 70 20 20 65 6e 63 2d 66 69 6c  md-loop  enc-fil
4b50: 65 20 24 66 72 65 65 20 3b 0a 0a 61 6c 73 6f 20  e $free ;..also 
4b60: 6e 65 74 32 6f 2d 62 61 73 65 0a 0a 3a 20 73 65  net2o-base..: se
4b70: 72 69 61 6c 69 7a 65 2d 63 68 61 74 67 72 6f 75  rialize-chatgrou
4b80: 70 20 28 20 6c 61 73 74 23 20 2d 2d 20 29 0a 20  p ( last# -- ). 
4b90: 20 20 20 64 75 70 20 24 40 20 32 64 75 70 20 24     dup $@ 2dup $
4ba0: 2c 20 67 72 6f 75 70 2d 6e 61 6d 65 0a 20 20 20  , group-name.   
4bb0: 20 72 6f 74 20 63 65 6c 6c 2b 20 24 40 20 64 72   rot cell+ $@ dr
4bc0: 6f 70 20 63 65 6c 6c 2b 20 3e 6f 0a 20 20 20 20  op cell+ >o.    
4bd0: 67 72 6f 75 70 73 3a 69 64 24 20 64 75 70 20 49  groups:id$ dup I
4be0: 46 0a 09 32 74 75 63 6b 20 73 74 72 3d 20 30 3d  F..2tuck str= 0=
4bf0: 20 49 46 20 20 24 2c 20 67 72 6f 75 70 2d 69 64   IF  $, group-id
4c00: 20 20 45 4c 53 45 20 20 32 64 72 6f 70 20 20 54    ELSE  2drop  T
4c10: 48 45 4e 0a 20 20 20 20 45 4c 53 45 20 20 32 64  HEN.    ELSE  2d
4c20: 72 6f 70 20 32 64 72 6f 70 20 20 54 48 45 4e 0a  rop 2drop  THEN.
4c30: 20 20 20 20 67 72 6f 75 70 73 3a 6d 65 6d 62 65      groups:membe
4c40: 72 5b 5d 20 5b 3a 20 24 2c 20 67 72 6f 75 70 2d  r[] [: $, group-
4c50: 6d 65 6d 62 65 72 20 3b 5d 20 24 5b 5d 6d 61 70  member ;] $[]map
4c60: 0a 20 20 20 20 67 72 6f 75 70 73 3a 61 64 6d 69  .    groups:admi
4c70: 6e 20 73 65 63 40 20 64 75 70 20 49 46 20 20 73  n sec@ dup IF  s
4c80: 65 63 24 2c 20 67 72 6f 75 70 2d 61 64 6d 69 6e  ec$, group-admin
4c90: 20 20 45 4c 53 45 20 20 32 64 72 6f 70 20 20 54    ELSE  2drop  T
4ca0: 48 45 4e 0a 20 20 20 20 67 72 6f 75 70 73 3a 70  HEN.    groups:p
4cb0: 65 72 6d 73 23 20 36 34 64 75 70 20 36 34 2d 30  erms# 64dup 64-0
4cc0: 3c 3e 20 49 46 20 20 6c 69 74 2c 20 67 72 6f 75  <> IF  lit, grou
4cd0: 70 2d 70 65 72 6d 73 20 20 45 4c 53 45 20 20 36  p-perms  ELSE  6
4ce0: 34 64 72 6f 70 20 20 54 48 45 4e 0a 20 20 20 20  4drop  THEN.    
4cf0: 6f 3e 20 3b 0a 0a 70 72 65 76 69 6f 75 73 0a 0a  o> ;..previous..
4d00: 3a 20 61 64 6d 69 6e 3e 70 6b 20 28 20 2d 2d 20  : admin>pk ( -- 
4d10: 29 0a 20 20 20 20 67 72 6f 75 70 73 3a 61 64 6d  ).    groups:adm
4d20: 69 6e 20 73 65 63 40 20 64 72 6f 70 20 64 75 70  in sec@ drop dup
4d30: 20 73 6b 2d 6d 61 73 6b 0a 20 20 20 20 6b 65 79   sk-mask.    key
4d40: 73 69 7a 65 20 61 64 64 72 20 67 72 6f 75 70 73  size addr groups
4d50: 3a 69 64 24 20 24 21 6c 65 6e 0a 20 20 20 20 67  :id$ $!len.    g
4d60: 72 6f 75 70 73 3a 69 64 24 20 64 72 6f 70 20 73  roups:id$ drop s
4d70: 6b 3e 70 6b 20 3b 0a 0a 3a 20 67 65 6e 2d 61 64  k>pk ;..: gen-ad
4d80: 6d 69 6e 2d 6b 65 79 20 28 20 2d 2d 20 29 0a 20  min-key ( -- ). 
4d90: 20 20 20 24 32 30 20 72 6e 67 24 20 67 72 6f 75     $20 rng$ grou
4da0: 70 73 3a 61 64 6d 69 6e 20 73 65 63 21 20 61 64  ps:admin sec! ad
4db0: 6d 69 6e 3e 70 6b 20 3b 0a 0a 3a 20 73 61 76 65  min>pk ;..: save
4dc0: 2d 63 68 61 74 67 72 6f 75 70 73 20 28 20 2d 2d  -chatgroups ( --
4dd0: 20 29 0a 20 20 20 20 30 20 2e 2e 63 68 61 74 73   ).    0 ..chats
4de0: 2f 67 72 6f 75 70 20 65 6e 63 2d 66 69 6c 65 6e  /group enc-filen
4df0: 61 6d 65 20 24 21 0a 20 20 20 20 5b 3a 20 67 72  ame $!.    [: gr
4e00: 6f 75 70 23 20 5b 27 5d 20 73 65 72 69 61 6c 69  oup# ['] seriali
4e10: 7a 65 2d 63 68 61 74 67 72 6f 75 70 20 23 6d 61  ze-chatgroup #ma
4e20: 70 20 3b 5d 20 67 65 6e 2d 63 6d 64 20 65 6e 63  p ;] gen-cmd enc
4e30: 2d 66 69 6c 65 20 24 21 62 75 66 0a 20 20 20 20  -file $!buf.    
4e40: 70 6b 2d 6f 66 66 20 20 6b 65 79 2d 6c 69 73 74  pk-off  key-list
4e50: 20 65 6e 63 66 69 6c 65 2d 72 65 73 74 20 3b 0a   encfile-rest ;.
4e60: 0a 56 61 72 69 61 62 6c 65 20 67 72 6f 75 70 2d  .Variable group-
4e70: 6c 69 73 74 5b 5d 0a 3a 20 24 69 6e 73 5b 5d 67  list[].: $ins[]g
4e80: 72 6f 75 70 20 28 20 6f 3a 67 72 6f 75 70 20 24  roup ( o:group $
4e90: 61 72 72 61 79 20 2d 2d 20 70 6f 73 20 29 0a 20  array -- pos ). 
4ea0: 20 20 20 5c 47 20 69 6e 73 65 72 74 20 4f 28 6c     \G insert O(l
4eb0: 6f 67 28 6e 29 29 20 69 6e 74 6f 20 70 72 65 2d  og(n)) into pre-
4ec0: 73 6f 72 74 65 64 20 61 72 72 61 79 0a 20 20 20  sorted array.   
4ed0: 20 5c 47 20 40 76 61 72 7b 70 6f 73 7d 20 69 73   \G @var{pos} is
4ee0: 20 74 68 65 20 69 6e 73 65 72 74 69 6f 6e 20 6f   the insertion o
4ef0: 66 66 73 65 74 20 6f 72 20 2d 31 20 69 66 20 6e  ffset or -1 if n
4f00: 6f 74 20 69 6e 73 65 72 74 65 64 0a 20 20 20 20  ot inserted.    
4f10: 7b 20 61 5b 5d 20 7d 20 30 20 61 5b 5d 20 24 5b  { a[] } 0 a[] $[
4f20: 5d 23 0a 20 20 20 20 42 45 47 49 4e 20 20 32 64  ]#.    BEGIN  2d
4f30: 75 70 20 75 3c 20 20 57 48 49 4c 45 20 20 32 64  up u<  WHILE  2d
4f40: 75 70 20 2b 20 32 2f 20 7b 20 6c 65 66 74 20 72  up + 2/ { left r
4f50: 69 67 68 74 20 24 23 20 7d 0a 09 20 20 20 20 6f  ight $# }..    o
4f60: 20 24 40 20 24 23 20 61 5b 5d 20 24 5b 5d 20 40   $@ $# a[] $[] @
4f70: 20 24 40 20 63 6f 6d 70 61 72 65 20 64 75 70 20   $@ compare dup 
4f80: 30 3d 20 49 46 0a 09 09 64 72 6f 70 20 6f 20 63  0= IF...drop o c
4f90: 65 6c 6c 2b 20 24 40 20 64 72 6f 70 20 63 65 6c  ell+ $@ drop cel
4fa0: 6c 2b 20 2e 67 72 6f 75 70 73 3a 69 64 24 0a 09  l+ .groups:id$..
4fb0: 09 24 23 20 61 5b 5d 20 24 5b 5d 20 40 20 63 65  .$# a[] $[] @ ce
4fc0: 6c 6c 2b 20 24 40 20 64 72 6f 70 20 63 65 6c 6c  ll+ $@ drop cell
4fd0: 2b 20 2e 67 72 6f 75 70 73 3a 69 64 24 20 63 6f  + .groups:id$ co
4fe0: 6d 70 61 72 65 20 20 54 48 45 4e 0a 09 20 20 20  mpare  THEN..   
4ff0: 20 30 3c 20 49 46 20 20 6c 65 66 74 20 24 23 20   0< IF  left $# 
5000: 20 45 4c 53 45 20 20 24 23 20 31 2b 20 72 69 67   ELSE  $# 1+ rig
5010: 68 74 20 20 54 48 45 4e 0a 20 20 20 20 52 45 50  ht  THEN.    REP
5020: 45 41 54 20 20 64 72 6f 70 20 3e 72 0a 20 20 20  EAT  drop >r.   
5030: 20 6f 20 7b 20 77 5e 20 69 6e 73 24 30 20 7d 20   o { w^ ins$0 } 
5040: 69 6e 73 24 30 20 63 65 6c 6c 20 61 5b 5d 20 72  ins$0 cell a[] r
5050: 40 20 63 65 6c 6c 73 20 24 69 6e 73 20 72 3e 20  @ cells $ins r> 
5060: 3b 0a 3a 20 67 72 6f 75 70 73 3e 73 6f 72 74 5b  ;.: groups>sort[
5070: 5d 20 28 20 2d 2d 20 29 20 20 67 72 6f 75 70 2d  ] ( -- )  group-
5080: 6c 69 73 74 5b 5d 20 24 66 72 65 65 0a 20 20 20  list[] $free.   
5090: 20 67 72 6f 75 70 23 20 5b 3a 20 3e 6f 20 67 72   group# [: >o gr
50a0: 6f 75 70 2d 6c 69 73 74 5b 5d 20 24 69 6e 73 5b  oup-list[] $ins[
50b0: 5d 67 72 6f 75 70 20 6f 3e 20 64 72 6f 70 20 3b  ]group o> drop ;
50c0: 5d 20 23 6d 61 70 20 3b 0a 0a 3a 20 2e 63 68 61  ] #map ;..: .cha
50d0: 74 67 72 6f 75 70 20 28 20 6c 61 73 74 23 20 2d  tgroup ( last# -
50e0: 2d 20 29 0a 20 20 20 20 64 75 70 20 24 2e 20 73  - ).    dup $. s
50f0: 70 61 63 65 20 64 75 70 20 24 40 20 72 6f 74 20  pace dup $@ rot 
5100: 63 65 6c 6c 2b 20 24 40 20 64 72 6f 70 20 63 65  cell+ $@ drop ce
5110: 6c 6c 2b 20 3e 6f 0a 20 20 20 20 67 72 6f 75 70  ll+ >o.    group
5120: 73 3a 69 64 24 20 32 74 75 63 6b 20 73 74 72 3d  s:id$ 2tuck str=
5130: 0a 20 20 20 20 49 46 20 20 2e 22 20 3d 22 20 32  .    IF  ." =" 2
5140: 64 72 6f 70 0a 20 20 20 20 45 4c 53 45 20 20 27  drop.    ELSE  '
5150: 27 27 20 65 6d 69 74 20 3c 69 6e 66 6f 3e 20 38  '' emit <info> 8
5160: 35 74 79 70 65 20 3c 64 65 66 61 75 6c 74 3e 20  5type <default> 
5170: 27 27 27 20 65 6d 69 74 20 54 48 45 4e 20 73 70  ''' emit THEN sp
5180: 61 63 65 0a 20 20 20 20 67 72 6f 75 70 73 3a 6d  ace.    groups:m
5190: 65 6d 62 65 72 5b 5d 20 5b 3a 20 27 40 27 20 65  ember[] [: '@' e
51a0: 6d 69 74 20 2e 73 69 6d 70 6c 65 2d 69 64 20 73  mit .simple-id s
51b0: 70 61 63 65 20 3b 5d 20 24 5b 5d 6d 61 70 0a 5c  pace ;] $[]map.\
51c0: 20 20 20 20 2e 22 20 61 64 6d 69 6e 20 22 20 67      ." admin " g
51d0: 72 6f 75 70 73 3a 61 64 6d 69 6e 5b 5d 20 5b 3a  roups:admin[] [:
51e0: 20 27 40 27 20 65 6d 69 74 20 2e 73 69 6d 70 6c   '@' emit .simpl
51f0: 65 2d 69 64 20 73 70 61 63 65 20 3b 5d 20 24 5b  e-id space ;] $[
5200: 5d 6d 61 70 0a 20 20 20 20 2e 22 20 2b 22 20 67  ]map.    ." +" g
5210: 72 6f 75 70 73 3a 70 65 72 6d 73 23 20 78 36 34  roups:perms# x64
5220: 2e 0a 20 20 20 20 6f 3e 20 63 72 20 3b 0a 3a 20  ..    o> cr ;.: 
5230: 2e 63 68 61 74 67 72 6f 75 70 73 20 28 20 2d 2d  .chatgroups ( --
5240: 20 29 0a 20 20 20 20 67 72 6f 75 70 73 3e 73 6f   ).    groups>so
5250: 72 74 5b 5d 0a 20 20 20 20 67 72 6f 75 70 2d 6c  rt[].    group-l
5260: 69 73 74 5b 5d 20 24 40 20 62 6f 75 6e 64 73 20  ist[] $@ bounds 
5270: 3f 44 4f 20 20 49 20 40 20 2e 63 68 61 74 67 72  ?DO  I @ .chatgr
5280: 6f 75 70 20 20 63 65 6c 6c 20 2b 4c 4f 4f 50 20  oup  cell +LOOP 
5290: 3b 0a 0a 3a 20 3f 70 6b 67 72 6f 75 70 20 28 20  ;..: ?pkgroup ( 
52a0: 61 64 64 72 20 75 20 2d 2d 20 61 64 64 72 20 75  addr u -- addr u
52b0: 20 29 0a 20 20 20 20 5c 20 69 66 20 6e 6f 20 67   ).    \ if no g
52c0: 72 6f 75 70 20 68 61 73 20 62 65 65 6e 20 73 65  roup has been se
52d0: 6c 65 63 74 65 64 2c 20 75 73 65 20 74 68 65 20  lected, use the 
52e0: 70 75 62 6b 65 79 20 61 73 20 67 72 6f 75 70 0a  pubkey as group.
52f0: 20 20 20 20 6c 61 73 74 23 20 30 3d 20 49 46 20      last# 0= IF 
5300: 20 32 64 75 70 20 2b 20 73 69 67 70 6b 73 69 7a   2dup + sigpksiz
5310: 65 23 20 2d 20 6b 65 79 73 69 7a 65 20 3e 67 72  e# - keysize >gr
5320: 6f 75 70 20 20 54 48 45 4e 20 3b 0a 0a 3a 20 68  oup  THEN ;..: h
5330: 61 6e 64 6c 65 2d 6d 73 67 20 28 20 61 64 64 72  andle-msg ( addr
5340: 2d 6f 20 75 2d 6f 20 61 64 64 72 2d 64 65 63 20  -o u-o addr-dec 
5350: 75 2d 64 65 63 20 2d 2d 20 29 0a 20 20 20 20 3f  u-dec -- ).    ?
5360: 70 6b 67 72 6f 75 70 20 32 73 77 61 70 20 3e 6d  pkgroup 2swap >m
5370: 73 67 2d 6c 6f 67 0a 20 20 20 20 32 64 75 70 20  sg-log.    2dup 
5380: 64 30 3c 3e 20 72 65 70 6c 61 79 2d 6d 6f 64 65  d0<> replay-mode
5390: 20 40 20 30 3d 20 61 6e 64 20 5c 20 64 6f 20 73   @ 0= and \ do s
53a0: 6f 6d 65 74 68 69 6e 67 20 69 66 20 69 74 20 69  omething if it i
53b0: 73 20 6e 65 77 0a 20 20 20 20 49 46 0a 09 32 6f  s new.    IF..2o
53c0: 76 65 72 20 73 68 6f 77 2d 6d 73 67 0a 09 32 64  ver show-msg..2d
53d0: 75 70 20 70 61 72 65 6e 74 20 2e 70 75 73 68 2d  up parent .push-
53e0: 6d 73 67 0a 20 20 20 20 54 48 45 4e 20 20 32 64  msg.    THEN  2d
53f0: 72 6f 70 20 32 64 72 6f 70 20 3b 0a 0a 5c 67 20  rop 2drop ;..\g 
5400: 0a 5c 67 20 23 23 23 20 6d 65 73 73 61 67 69 6e  .\g ### messagin
5410: 67 20 63 6f 6d 6d 61 6e 64 73 20 23 23 23 0a 5c  g commands ###.\
5420: 67 20 0a 0a 73 63 6f 70 65 7b 20 6e 65 74 32 6f  g ..scope{ net2o
5430: 2d 62 61 73 65 0a 0a 24 33 34 20 6e 65 74 32 6f  -base..$34 net2o
5440: 3a 20 6d 65 73 73 61 67 65 20 28 20 2d 2d 20 6f  : message ( -- o
5450: 3a 6d 73 67 20 29 20 5c 67 20 70 75 73 68 20 61  :msg ) \g push a
5460: 20 6d 65 73 73 61 67 65 20 6f 62 6a 65 63 74 0a   message object.
5470: 20 20 20 20 70 65 72 6d 2d 6d 61 73 6b 20 40 20      perm-mask @ 
5480: 70 65 72 6d 25 6d 73 67 20 61 6e 64 20 30 3d 20  perm%msg and 0= 
5490: 21 21 6d 73 67 2d 70 65 72 6d 21 21 0a 20 20 20  !!msg-perm!!.   
54a0: 20 3f 6d 73 67 2d 63 6f 6e 74 65 78 74 20 6e 3a   ?msg-context n:
54b0: 3e 6f 20 63 2d 73 74 61 74 65 20 6f 66 66 20 20  >o c-state off  
54c0: 30 20 74 6f 20 6c 61 73 74 23 20 3b 0a 0a 6d 73  0 to last# ;..ms
54d0: 67 69 6e 67 2d 74 61 62 6c 65 20 3e 74 61 62 6c  ging-table >tabl
54e0: 65 0a 0a 72 65 70 6c 79 2d 74 61 62 6c 65 20 24  e..reply-table $
54f0: 40 20 69 6e 68 65 72 69 74 2d 74 61 62 6c 65 20  @ inherit-table 
5500: 6d 73 67 69 6e 67 2d 74 61 62 6c 65 0a 0a 24 32  msging-table..$2
5510: 31 20 6e 65 74 32 6f 3a 20 6d 73 67 2d 67 72 6f  1 net2o: msg-gro
5520: 75 70 20 28 20 24 3a 67 72 6f 75 70 20 2d 2d 20  up ( $:group -- 
5530: 29 20 5c 67 20 73 65 74 20 67 72 6f 75 70 0a 20  ) \g set group. 
5540: 20 20 20 24 3e 20 3e 67 72 6f 75 70 20 3b 0a 2b     $> >group ;.+
5550: 6e 65 74 32 6f 3a 20 6d 73 67 2d 6a 6f 69 6e 20  net2o: msg-join 
5560: 28 20 24 3a 67 72 6f 75 70 20 2d 2d 20 29 20 5c  ( $:group -- ) \
5570: 67 20 6a 6f 69 6e 20 61 20 63 68 61 74 20 67 72  g join a chat gr
5580: 6f 75 70 0a 20 20 20 20 24 3e 20 3e 6c 6f 61 64  oup.    $> >load
5590: 2d 67 72 6f 75 70 20 70 61 72 65 6e 74 20 3e 6f  -group parent >o
55a0: 0a 20 20 20 20 2b 75 6e 69 71 75 65 2d 63 6f 6e  .    +unique-con
55b0: 20 2b 63 68 61 74 2d 63 6f 6e 74 72 6f 6c 0a 20   +chat-control. 
55c0: 20 20 20 77 61 69 74 2d 74 61 73 6b 20 40 20 3f     wait-task @ ?
55d0: 64 75 70 2d 49 46 20 20 3c 68 69 64 65 3e 20 20  dup-IF  <hide>  
55e0: 54 48 45 4e 0a 20 20 20 20 6f 3e 20 3b 0a 2b 6e  THEN.    o> ;.+n
55f0: 65 74 32 6f 3a 20 6d 73 67 2d 6c 65 61 76 65 20  et2o: msg-leave 
5600: 28 20 24 3a 67 72 6f 75 70 20 2d 2d 20 29 20 5c  ( $:group -- ) \
5610: 67 20 6c 65 61 76 65 20 61 20 63 68 61 74 20 67  g leave a chat g
5620: 72 6f 75 70 0a 20 20 20 20 24 3e 20 3e 67 72 6f  roup.    $> >gro
5630: 75 70 20 70 61 72 65 6e 74 20 6d 73 67 2d 67 72  up parent msg-gr
5640: 6f 75 70 2d 6f 20 2e 6d 73 67 3a 70 65 65 72 73  oup-o .msg:peers
5650: 5b 5d 20 64 65 6c 24 63 65 6c 6c 20 3b 0a 2b 6e  [] del$cell ;.+n
5660: 65 74 32 6f 3a 20 6d 73 67 2d 72 65 63 6f 6e 6e  et2o: msg-reconn
5670: 65 63 74 20 28 20 24 3a 70 75 62 6b 65 79 2b 61  ect ( $:pubkey+a
5680: 64 64 72 20 2d 2d 20 29 20 5c 67 20 72 65 77 69  ddr -- ) \g rewi
5690: 72 65 20 64 69 73 74 72 69 62 75 74 69 6f 6e 20  re distribution 
56a0: 74 72 65 65 0a 20 20 20 20 24 3e 20 24 6d 61 6b  tree.    $> $mak
56b0: 65 0a 20 20 20 20 3c 65 76 65 6e 74 20 6c 61 73  e.    <event las
56c0: 74 2d 6d 73 67 20 32 40 20 65 24 2c 20 65 6c 69  t-msg 2@ e$, eli
56d0: 74 2c 20 6f 20 65 6c 69 74 2c 20 6d 73 67 2d 67  t, o elit, msg-g
56e0: 72 6f 75 70 2d 6f 20 65 6c 69 74 2c 20 3a 3e 63  roup-o elit, :>c
56f0: 68 61 74 2d 72 65 63 6f 6e 6e 65 63 74 0a 20 20  hat-reconnect.  
5700: 20 20 70 61 72 65 6e 74 20 2e 77 61 69 74 2d 74    parent .wait-t
5710: 61 73 6b 20 40 20 3f 71 75 65 72 79 2d 74 61 73  ask @ ?query-tas
5720: 6b 20 6f 76 65 72 20 73 65 6c 65 63 74 20 65 76  k over select ev
5730: 65 6e 74 3e 20 3b 0a 2b 6e 65 74 32 6f 3a 20 6d  ent> ;.+net2o: m
5740: 73 67 2d 6c 61 73 74 3f 20 28 20 73 74 61 72 74  sg-last? ( start
5750: 20 65 6e 64 20 6e 20 2d 2d 20 29 20 36 34 3e 6e   end n -- ) 64>n
5760: 20 6d 73 67 3a 6c 61 73 74 3f 20 3b 0a 2b 6e 65   msg:last? ;.+ne
5770: 74 32 6f 3a 20 6d 73 67 2d 6c 61 73 74 20 28 20  t2o: msg-last ( 
5780: 24 3a 5b 74 69 63 6b 30 2c 6d 73 67 73 2c 2e 2e  $:[tick0,msgs,..
5790: 74 69 63 6b 6e 5d 20 6e 20 2d 2d 20 29 20 36 34  tickn] n -- ) 64
57a0: 3e 6e 20 6d 73 67 3a 6c 61 73 74 20 3b 0a 0a 6e  >n msg:last ;..n
57b0: 65 74 32 6f 27 20 6e 65 73 74 73 69 67 20 6e 65  et2o' nestsig ne
57c0: 74 32 6f 3a 20 6d 73 67 2d 6e 65 73 74 73 69 67  t2o: msg-nestsig
57d0: 20 28 20 24 3a 63 6d 64 2b 73 69 67 20 2d 2d 20   ( $:cmd+sig -- 
57e0: 29 20 5c 67 20 63 68 65 63 6b 20 73 69 67 2b 6e  ) \g check sig+n
57f0: 65 73 74 0a 20 20 20 20 24 3e 20 6e 65 73 74 2d  est.    $> nest-
5800: 73 69 67 20 3f 64 75 70 2d 30 3d 2d 49 46 0a 09  sig ?dup-0=-IF..
5810: 68 61 6e 64 6c 65 2d 6d 73 67 0a 20 20 20 20 45  handle-msg.    E
5820: 4c 53 45 20 20 72 65 70 6c 61 79 2d 6d 6f 64 65  LSE  replay-mode
5830: 20 40 20 49 46 20 20 64 72 6f 70 20 20 45 4c 53   @ IF  drop  ELS
5840: 45 20 20 21 21 73 69 67 21 21 20 20 54 48 45 4e  E  !!sig!!  THEN
5850: 0a 09 32 64 72 6f 70 20 32 64 72 6f 70 20 5c 20  ..2drop 2drop \ 
5860: 62 61 6c 6b 20 6f 6e 20 61 6c 6c 20 77 72 6f 6e  balk on all wron
5870: 67 20 73 69 67 6e 61 74 75 72 65 73 0a 20 20 20  g signatures.   
5880: 20 54 48 45 4e 20 3b 0a 0a 5c 20 67 65 6e 65 72   THEN ;..\ gener
5890: 61 74 65 20 61 6e 20 65 6e 63 72 79 74 2b 73 69  ate an encryt+si
58a0: 67 6e 20 70 61 63 6b 65 74 0a 0a 3a 20 5d 65 6e  gn packet..: ]en
58b0: 63 70 6b 73 69 67 6e 20 28 20 2d 2d 20 29 0a 20  cpksign ( -- ). 
58c0: 20 20 20 2b 7a 65 72 6f 31 36 20 6e 65 73 74 24     +zero16 nest$
58d0: 0a 20 20 20 20 30 20 6d 73 67 2d 67 72 6f 75 70  .    0 msg-group
58e0: 2d 6f 20 2e 6d 73 67 3a 6b 65 79 73 5b 5d 20 24  -o .msg:keys[] $
58f0: 5b 5d 40 20 65 6e 63 72 79 70 74 24 0a 20 20 20  []@ encrypt$.   
5900: 20 5b 27 5d 20 2e 65 6e 63 73 69 67 6e 20 27 5d   ['] .encsign ']
5910: 6e 65 73 74 73 69 67 20 3b 0a 0a 5c 20 6e 65 73  nestsig ;..\ nes
5920: 74 2d 73 69 67 20 66 6f 72 20 6d 73 67 2f 6d 73  t-sig for msg/ms
5930: 67 69 6e 67 20 63 6c 61 73 73 65 73 0a 0a 27 20  ging classes..' 
5940: 6d 65 73 73 61 67 65 20 6d 73 67 69 6e 67 2d 63  message msging-c
5950: 6c 61 73 73 20 69 73 20 73 74 61 72 74 2d 72 65  lass is start-re
5960: 71 0a 3a 6e 6f 6e 61 6d 65 20 63 68 65 63 6b 2d  q.:noname check-
5970: 64 61 74 65 20 3e 72 20 32 64 75 70 20 72 3e 20  date >r 2dup r> 
5980: 3b 20 6d 73 67 69 6e 67 2d 63 6c 61 73 73 20 69  ; msging-class i
5990: 73 20 6e 65 73 74 2d 73 69 67 0a 27 20 6d 65 73  s nest-sig.' mes
59a0: 73 61 67 65 20 6d 73 67 2d 63 6c 61 73 73 20 69  sage msg-class i
59b0: 73 20 73 74 61 72 74 2d 72 65 71 0a 3a 6e 6f 6e  s start-req.:non
59c0: 61 6d 65 20 32 64 75 70 20 6d 73 67 2d 64 65 63  ame 2dup msg-dec
59d0: 3f 2d 73 69 67 3f 20 3b 20 6d 73 67 2d 63 6c 61  ?-sig? ; msg-cla
59e0: 73 73 20 69 73 20 6e 65 73 74 2d 73 69 67 0a 0a  ss is nest-sig..
59f0: 27 20 63 6f 6e 74 65 78 74 2d 74 61 62 6c 65 20  ' context-table 
5a00: 69 73 20 67 65 6e 2d 74 61 62 6c 65 0a 0a 61 6c  is gen-table..al
5a10: 73 6f 20 7d 73 63 6f 70 65 0a 0a 6d 73 67 69 6e  so }scope..msgin
5a20: 67 2d 74 61 62 6c 65 20 24 73 61 76 65 0a 0a 3a  g-table $save..:
5a30: 20 6d 73 67 2d 72 65 70 6c 79 20 28 20 74 61 67   msg-reply ( tag
5a40: 20 2d 2d 20 29 0a 20 20 20 20 2e 22 20 67 6f 74   -- ).    ." got
5a50: 20 72 65 70 6c 79 20 22 20 68 65 78 2e 20 70 75   reply " hex. pu
5a60: 62 6b 65 79 20 24 40 20 6b 65 79 3e 6e 69 63 6b  bkey $@ key>nick
5a70: 20 66 6f 72 74 68 3a 74 79 70 65 20 66 6f 72 74   forth:type fort
5a80: 68 3a 63 72 20 3b 0a 3a 20 65 78 70 65 63 74 2d  h:cr ;.: expect-
5a90: 6d 73 67 20 28 20 6f 3a 63 6f 6e 6e 65 63 74 69  msg ( o:connecti
5aa0: 6f 6e 20 2d 2d 20 29 0a 20 20 20 20 72 65 70 6c  on -- ).    repl
5ab0: 79 28 20 5b 27 5d 20 6d 73 67 2d 72 65 70 6c 79  y( ['] msg-reply
5ac0: 20 29 65 6c 73 65 28 20 5b 27 5d 20 64 72 6f 70   )else( ['] drop
5ad0: 20 29 20 65 78 70 65 63 74 2d 72 65 70 6c 79 2d   ) expect-reply-
5ae0: 78 74 20 2b 63 68 61 74 2d 63 6f 6e 74 72 6f 6c  xt +chat-control
5af0: 20 3b 0a 0a 55 73 65 72 20 68 61 73 68 74 6d 70   ;..User hashtmp
5b00: 24 20 20 68 61 73 68 74 6d 70 24 20 6f 66 66 0a  $  hashtmp$ off.
5b10: 0a 3a 20 6c 61 73 74 2d 6d 73 67 40 20 28 20 2d  .: last-msg@ ( -
5b20: 2d 20 74 69 63 6b 73 20 29 0a 20 20 20 20 6c 61  - ticks ).    la
5b30: 73 74 23 20 3e 72 0a 20 20 20 20 6c 61 73 74 23  st# >r.    last#
5b40: 20 24 40 20 3e 67 72 6f 75 70 20 6d 73 67 2d 67   $@ >group msg-g
5b50: 72 6f 75 70 2d 6f 20 2e 6d 73 67 3a 6c 6f 67 5b  roup-o .msg:log[
5b60: 5d 20 24 5b 5d 23 20 3f 64 75 70 2d 49 46 0a 09  ] $[]# ?dup-IF..
5b70: 31 2d 20 6d 73 67 2d 67 72 6f 75 70 2d 6f 20 2e  1- msg-group-o .
5b80: 6d 73 67 3a 6c 6f 67 5b 5d 20 24 5b 5d 40 20 73  msg:log[] $[]@ s
5b90: 74 61 72 74 64 61 74 65 40 0a 20 20 20 20 45 4c  tartdate@.    EL
5ba0: 53 45 20 20 36 34 23 30 20 20 54 48 45 4e 20 20  SE  64#0  THEN  
5bb0: 20 72 3e 20 74 6f 20 6c 61 73 74 23 20 3b 0a 3a   r> to last# ;.:
5bc0: 20 6c 2e 68 61 73 68 73 20 28 20 65 6e 64 20 73   l.hashs ( end s
5bd0: 74 61 72 74 20 2d 2d 20 68 61 73 68 61 64 64 72  tart -- hashaddr
5be0: 20 75 20 29 0a 20 20 20 20 68 61 73 68 74 6d 70   u ).    hashtmp
5bf0: 24 20 24 6f 66 66 0a 20 20 20 20 6d 73 67 2d 67  $ $off.    msg-g
5c00: 72 6f 75 70 2d 6f 20 2e 6d 73 67 3a 6c 6f 67 5b  roup-o .msg:log[
5c10: 5d 20 24 5b 5d 23 20 49 46 0a 09 5b 3a 20 55 2b  ] $[]# IF..[: U+
5c20: 44 4f 20 20 49 20 6d 73 67 2d 67 72 6f 75 70 2d  DO  I msg-group-
5c30: 6f 20 2e 6d 73 67 3a 6c 6f 67 5b 5d 20 24 5b 5d  o .msg:log[] $[]
5c40: 40 20 31 2d 20 64 75 70 20 31 20 36 34 73 20 2d  @ 1- dup 1 64s -
5c50: 20 73 61 66 65 2f 73 74 72 69 6e 67 20 66 6f 72   safe/string for
5c60: 74 68 3a 74 79 70 65 0a 09 20 20 4c 4f 4f 50 20  th:type..  LOOP 
5c70: 3b 5d 20 68 61 73 68 74 6d 70 24 20 24 65 78 65  ;] hashtmp$ $exe
5c80: 63 20 68 61 73 68 74 6d 70 24 20 24 40 0a 09 5c  c hashtmp$ $@..\
5c90: 20 5b 3a 20 32 64 75 70 20 64 75 6d 70 20 3b 5d   [: 2dup dump ;]
5ca0: 20 73 74 64 65 72 72 20 6f 75 74 66 69 6c 65 2d   stderr outfile-
5cb0: 65 78 65 63 75 74 65 20 5c 20 64 75 6d 70 20 68  execute \ dump h
5cc0: 61 73 68 20 69 6e 70 75 74 73 0a 20 20 20 20 45  ash inputs.    E
5cd0: 4c 53 45 20 20 32 64 72 6f 70 20 73 22 20 22 20  LSE  2drop s" " 
5ce0: 20 54 48 45 4e 20 5c 20 77 65 20 68 61 76 65 20   THEN \ we have 
5cf0: 6e 6f 74 68 69 6e 67 20 79 65 74 0a 20 20 20 20  nothing yet.    
5d00: 3e 66 69 6c 65 2d 68 61 73 68 20 31 20 36 34 73  >file-hash 1 64s
5d10: 20 75 6d 69 6e 20 3b 0a 3a 20 69 2e 64 61 74 65   umin ;.: i.date
5d20: 20 28 20 69 20 2d 2d 20 29 0a 20 20 20 20 6d 73   ( i -- ).    ms
5d30: 67 2d 67 72 6f 75 70 2d 6f 20 2e 6d 73 67 3a 6c  g-group-o .msg:l
5d40: 6f 67 5b 5d 20 24 5b 5d 40 20 73 74 61 72 74 64  og[] $[]@ startd
5d50: 61 74 65 40 20 36 34 23 30 20 7b 20 36 34 5e 20  ate@ 64#0 { 64^ 
5d60: 78 20 7d 0a 20 20 20 20 78 20 6c 65 2d 36 34 21  x }.    x le-64!
5d70: 20 78 20 31 20 36 34 73 20 66 6f 72 74 68 3a 74   x 1 64s forth:t
5d80: 79 70 65 20 3b 0a 3a 20 69 2e 64 61 74 65 2b 31  ype ;.: i.date+1
5d90: 20 28 20 69 20 2d 2d 20 29 0a 20 20 20 20 6d 73   ( i -- ).    ms
5da0: 67 2d 67 72 6f 75 70 2d 6f 20 2e 6d 73 67 3a 6c  g-group-o .msg:l
5db0: 6f 67 5b 5d 20 24 5b 5d 40 20 73 74 61 72 74 64  og[] $[]@ startd
5dc0: 61 74 65 40 20 36 34 23 30 20 7b 20 36 34 5e 20  ate@ 64#0 { 64^ 
5dd0: 78 20 7d 0a 20 20 20 20 36 34 23 31 20 36 34 2b  x }.    64#1 64+
5de0: 20 78 20 6c 65 2d 36 34 21 20 78 20 31 20 36 34   x le-64! x 1 64
5df0: 73 20 66 6f 72 74 68 3a 74 79 70 65 20 3b 0a 3a  s forth:type ;.:
5e00: 20 6c 61 73 74 2d 6d 73 67 73 40 20 28 20 73 74   last-msgs@ ( st
5e10: 61 72 74 64 61 74 65 20 65 6e 64 64 61 74 65 20  artdate enddate 
5e20: 6e 20 2d 2d 20 61 64 64 72 20 75 20 6e 27 20 29  n -- addr u n' )
5e30: 0a 20 20 20 20 5c 47 20 70 72 69 6e 74 20 6e 20  .    \G print n 
5e40: 69 6e 74 65 72 76 61 6c 73 20 66 6f 72 20 6d 65  intervals for me
5e50: 73 73 61 67 65 73 20 66 72 6f 6d 20 73 74 61 72  ssages from star
5e60: 74 64 61 74 65 20 74 6f 20 65 6e 64 64 61 74 65  tdate to enddate
5e70: 0a 20 20 20 20 5c 47 20 54 68 65 20 69 6e 74 65  .    \G The inte
5e80: 72 76 61 6c 73 20 63 6f 6e 74 61 69 6e 20 74 68  rvals contain th
5e90: 65 20 73 61 6d 65 20 73 69 7a 65 20 6f 66 20 6d  e same size of m
5ea0: 65 73 73 61 67 65 73 20 65 78 63 65 70 74 20 74  essages except t
5eb0: 68 65 0a 20 20 20 20 5c 47 20 6c 61 73 74 20 6f  he.    \G last o
5ec0: 6e 65 2c 20 77 68 69 63 68 20 6d 61 79 20 63 6f  ne, which may co
5ed0: 6e 74 61 69 6e 20 6c 65 73 73 20 28 72 6f 75 6e  ntain less (roun
5ee0: 64 69 6e 67 20 64 6f 77 6e 29 2e 0a 20 20 20 20  ding down)..    
5ef0: 5c 47 20 45 61 63 68 20 69 6e 74 65 72 76 61 6c  \G Each interval
5f00: 20 63 6f 6e 74 61 69 6e 73 20 61 20 36 34 20 62   contains a 64 b
5f10: 69 74 20 68 61 73 68 20 6f 66 20 74 68 65 20 6c  it hash of the l
5f20: 61 73 74 20 36 34 20 62 69 74 20 6f 66 0a 20 20  ast 64 bit of.  
5f30: 20 20 5c 47 20 65 61 63 68 20 6d 65 73 73 61 67    \G each messag
5f40: 65 20 77 69 74 68 69 6e 20 74 68 65 20 69 6e 74  e within the int
5f50: 65 72 76 61 6c 0a 20 20 20 20 6c 61 73 74 23 20  erval.    last# 
5f60: 3e 72 20 3e 72 20 6c 61 73 74 23 20 24 40 20 3e  >r >r last# $@ >
5f70: 67 72 6f 75 70 20 70 75 72 67 65 2d 6c 6f 67 0a  group purge-log.
5f80: 20 20 20 20 6d 73 67 2d 67 72 6f 75 70 2d 6f 20      msg-group-o 
5f90: 2e 6d 73 67 3a 6c 6f 67 5b 5d 20 24 5b 5d 23 0a  .msg:log[] $[]#.
5fa0: 20 20 20 20 49 46 0a 09 64 61 74 65 3e 69 27 20      IF..date>i' 
5fb0: 3e 72 20 64 61 74 65 3e 69 27 20 72 3e 20 73 77  >r date>i' r> sw
5fc0: 61 70 0a 09 32 64 75 70 20 2d 20 72 3e 20 6f 76  ap..2dup - r> ov
5fd0: 65 72 20 3e 72 20 31 2d 20 31 20 6d 61 78 20 2f  er >r 1- 1 max /
5fe0: 20 30 20 6d 61 78 20 31 2b 20 2d 72 6f 74 0a 09   0 max 1+ -rot..
5ff0: 5b 3a 20 6f 76 65 72 20 3e 72 20 55 2b 44 4f 20  [: over >r U+DO 
6000: 20 49 20 69 2e 64 61 74 65 0a 09 20 20 20 20 20   I i.date..     
6010: 20 64 75 70 20 49 20 2b 20 49 27 20 75 6d 69 6e   dup I + I' umin
6020: 20 49 20 6c 2e 68 61 73 68 73 20 66 6f 72 74 68   I l.hashs forth
6030: 3a 74 79 70 65 0a 09 20 20 64 75 70 20 2b 4c 4f  :type..  dup +LO
6040: 4f 50 0a 09 20 20 72 3e 20 64 75 70 20 6d 73 67  OP..  r> dup msg
6050: 2d 67 72 6f 75 70 2d 6f 20 2e 6d 73 67 3a 6c 6f  -group-o .msg:lo
6060: 67 5b 5d 20 24 5b 5d 23 20 75 3c 20 49 46 20 20  g[] $[]# u< IF  
6070: 69 2e 64 61 74 65 0a 09 20 20 45 4c 53 45 20 20  i.date..  ELSE  
6080: 31 2d 20 69 2e 64 61 74 65 2b 31 20 20 54 48 45  1- i.date+1  THE
6090: 4e 0a 09 20 20 64 72 6f 70 20 3b 5d 20 24 74 6d  N..  drop ;] $tm
60a0: 70 20 72 3e 20 5c 20 6f 76 65 72 20 31 20 36 34  p r> \ over 1 64
60b0: 73 20 75 3e 20 2d 0a 20 20 20 20 45 4c 53 45 20  s u> -.    ELSE 
60c0: 20 72 64 72 6f 70 20 36 34 64 72 6f 70 20 36 34   rdrop 64drop 64
60d0: 64 72 6f 70 20 73 22 20 22 20 20 30 20 54 48 45  drop s" "  0 THE
60e0: 4e 20 20 20 72 3e 20 74 6f 20 6c 61 73 74 23 20  N   r> to last# 
60f0: 3b 0a 0a 5c 20 73 79 6e 63 20 63 68 61 74 6c 6f  ;..\ sync chatlo
6100: 67 20 74 68 72 6f 75 67 68 20 76 69 72 74 75 61  g through virtua
6110: 6c 20 66 69 6c 65 20 61 63 63 65 73 73 0a 0a 74  l file access..t
6120: 65 72 6d 73 65 72 76 65 72 2d 63 6c 61 73 73 20  ermserver-class 
6130: 63 6c 61 73 73 0a 65 6e 64 2d 63 6c 61 73 73 20  class.end-class 
6140: 6d 73 67 66 73 2d 63 6c 61 73 73 0a 0a 66 69 6c  msgfs-class..fil
6150: 65 2d 63 6c 61 73 73 65 73 23 20 43 6f 6e 73 74  e-classes# Const
6160: 61 6e 74 20 6d 73 67 66 73 2d 63 6c 61 73 73 23  ant msgfs-class#
6170: 0a 6d 73 67 66 73 2d 63 6c 61 73 73 20 2b 66 69  .msgfs-class +fi
6180: 6c 65 2d 63 6c 61 73 73 65 73 0a 0a 3a 20 73 61  le-classes..: sa
6190: 76 65 2d 74 6f 2d 6d 73 67 20 28 20 61 64 64 72  ve-to-msg ( addr
61a0: 20 75 20 6e 20 2d 2d 20 29 0a 20 20 20 20 73 74   u n -- ).    st
61b0: 61 74 65 2d 61 64 64 72 20 3e 6f 20 20 6d 73 67  ate-addr >o  msg
61c0: 66 73 2d 63 6c 61 73 73 23 20 66 73 2d 63 6c 61  fs-class# fs-cla
61d0: 73 73 21 20 77 2f 6f 20 66 73 2d 63 72 65 61 74  ss! w/o fs-creat
61e0: 65 20 6f 3e 20 3b 0a 3a 20 2e 63 68 61 74 2d 66  e o> ;.: .chat-f
61f0: 69 6c 65 20 28 20 61 64 64 72 20 75 20 2d 2d 20  ile ( addr u -- 
6200: 29 0a 20 20 20 20 6f 76 65 72 20 6c 65 2d 36 34  ).    over le-64
6210: 40 20 2e 74 69 63 6b 73 20 31 20 36 34 73 20 2f  @ .ticks 1 64s /
6220: 73 74 72 69 6e 67 20 20 2e 22 20 2d 3e 22 0a 20  string  ." ->". 
6230: 20 20 20 6f 76 65 72 20 6c 65 2d 36 34 40 20 2e     over le-64@ .
6240: 74 69 63 6b 73 20 31 20 36 34 73 20 2f 73 74 72  ticks 1 64s /str
6250: 69 6e 67 20 20 2e 22 20 40 22 0a 20 20 20 20 2e  ing  ." @".    .
6260: 67 72 6f 75 70 20 3b 0a 69 6e 20 6e 65 74 32 6f  group ;.in net2o
6270: 20 3a 20 63 6f 70 79 2d 6d 73 67 20 28 20 66 69   : copy-msg ( fi
6280: 6c 65 6e 61 6d 65 20 75 20 2d 2d 20 29 0a 20 20  lename u -- ).  
6290: 20 20 2e 22 20 63 6f 70 79 20 6d 73 67 3a 20 22    ." copy msg: "
62a0: 20 32 64 75 70 20 2e 63 68 61 74 2d 66 69 6c 65   2dup .chat-file
62b0: 20 66 6f 72 74 68 3a 63 72 0a 20 20 20 20 5b 3a   forth:cr.    [:
62c0: 20 6d 73 67 66 73 2d 63 6c 61 73 73 23 20 75 6c   msgfs-class# ul
62d0: 69 74 2c 20 66 69 6c 65 2d 74 79 70 65 20 32 64  it, file-type 2d
62e0: 75 70 20 24 2c 20 72 2f 6f 20 75 6c 69 74 2c 20  up $, r/o ulit, 
62f0: 6f 70 65 6e 2d 73 69 7a 65 64 2d 66 69 6c 65 0a  open-sized-file.
6300: 20 20 20 20 20 20 66 69 6c 65 2d 72 65 67 23 20        file-reg# 
6310: 40 20 73 61 76 65 2d 74 6f 2d 6d 73 67 20 3b 5d  @ save-to-msg ;]
6320: 20 6e 32 6f 3e 66 69 6c 65 0a 20 20 20 20 31 20   n2o>file.    1 
6330: 66 69 6c 65 2d 63 6f 75 6e 74 20 2b 21 20 3b 0a  file-count +! ;.
6340: 0a 24 32 30 20 56 61 6c 75 65 20 6d 61 78 2d 6c  .$20 Value max-l
6350: 61 73 74 23 0a 24 32 30 20 56 61 6c 75 65 20 61  ast#.$20 Value a
6360: 73 6b 2d 6c 61 73 74 23 0a 0a 56 61 72 69 61 62  sk-last#..Variab
6370: 6c 65 20 61 73 6b 2d 6d 73 67 2d 66 69 6c 65 73  le ask-msg-files
6380: 5b 5d 0a 0a 3a 20 6d 73 67 3a 6c 61 73 74 3f 20  []..: msg:last? 
6390: 28 20 73 74 61 72 74 20 65 6e 64 20 6e 20 2d 2d  ( start end n --
63a0: 20 29 0a 20 20 20 20 6c 61 73 74 23 20 24 40 20   ).    last# $@ 
63b0: 24 2c 20 6d 73 67 2d 67 72 6f 75 70 0a 20 20 20  $, msg-group.   
63c0: 20 6d 61 78 2d 6c 61 73 74 23 20 75 6d 69 6e 0a   max-last# umin.
63d0: 20 20 20 20 6c 61 73 74 2d 6d 73 67 73 40 20 3e      last-msgs@ >
63e0: 72 20 24 2c 20 72 3e 20 75 6c 69 74 2c 20 6d 73  r $, r> ulit, ms
63f0: 67 2d 6c 61 73 74 20 3b 0a 3a 20 3f 61 73 6b 2d  g-last ;.: ?ask-
6400: 6d 73 67 2d 66 69 6c 65 73 20 28 20 61 64 64 72  msg-files ( addr
6410: 20 75 20 2d 2d 20 29 0a 20 20 20 20 36 34 23 2d   u -- ).    64#-
6420: 31 20 36 34 23 30 20 7b 20 36 34 5e 20 73 74 61  1 64#0 { 64^ sta
6430: 72 74 64 20 36 34 5e 20 65 6e 64 64 20 7d 20 5c  rtd 64^ endd } \
6440: 20 62 79 74 65 20 6f 72 64 65 72 20 6f 66 20 30   byte order of 0
6450: 20 61 6e 64 20 2d 31 20 64 6f 6e 27 74 20 6d 61   and -1 don't ma
6460: 74 74 65 72 0a 20 20 20 20 6c 61 73 74 23 20 24  tter.    last# $
6470: 40 20 3e 67 72 6f 75 70 0a 20 20 20 20 24 3e 20  @ >group.    $> 
6480: 62 6f 75 6e 64 73 20 3f 44 4f 0a 09 49 27 20 49  bounds ?DO..I' I
6490: 20 36 34 27 2b 20 75 3e 20 49 46 0a 09 20 20 20   64'+ u> IF..   
64a0: 20 49 20 6c 65 2d 36 34 40 20 64 61 74 65 3e 69   I le-64@ date>i
64b0: 27 0a 09 20 20 20 20 49 20 36 34 27 2b 20 36 34  '..    I 64'+ 64
64c0: 27 2b 20 6c 65 2d 36 34 40 20 64 61 74 65 3e 69  '+ le-64@ date>i
64d0: 27 20 73 77 61 70 0a 09 20 20 20 20 6c 2e 68 61  ' swap..    l.ha
64e0: 73 68 73 20 64 72 6f 70 20 6c 65 2d 36 34 40 0a  shs drop le-64@.
64f0: 09 20 20 20 20 49 20 36 34 27 2b 20 6c 65 2d 36  .    I 64'+ le-6
6500: 34 40 20 36 34 3c 3e 20 49 46 0a 09 09 49 20 36  4@ 64<> IF...I 6
6510: 34 40 20 73 74 61 72 74 64 20 6c 65 2d 36 34 40  4@ startd le-64@
6520: 20 36 34 75 6d 69 6e 0a 09 09 49 20 36 34 27 2b   64umin...I 64'+
6530: 20 36 34 27 2b 20 36 34 40 20 65 6e 64 64 20 6c   64'+ 64@ endd l
6540: 65 2d 36 34 40 20 36 34 75 6d 61 78 0a 09 20 20  e-64@ 64umax..  
6550: 20 20 45 4c 53 45 0a 09 09 73 74 61 72 74 64 20    ELSE...startd 
6560: 6c 65 2d 36 34 40 20 36 34 23 2d 31 20 36 34 3c  le-64@ 64#-1 64<
6570: 3e 20 49 46 0a 09 09 20 20 20 20 65 6e 64 64 20  > IF...    endd 
6580: 73 74 61 72 74 64 20 5b 3a 20 31 20 36 34 73 20  startd [: 1 64s 
6590: 66 6f 72 74 68 3a 74 79 70 65 20 31 20 36 34 73  forth:type 1 64s
65a0: 20 66 6f 72 74 68 3a 74 79 70 65 20 6c 61 73 74   forth:type last
65b0: 23 20 24 2e 20 3b 5d 0a 09 09 20 20 20 20 61 73  # $. ;]...    as
65c0: 6b 2d 6d 73 67 2d 66 69 6c 65 73 5b 5d 20 64 75  k-msg-files[] du
65d0: 70 20 24 5b 5d 23 20 73 77 61 70 20 24 5b 5d 20  p $[]# swap $[] 
65e0: 24 65 78 65 63 0a 09 09 54 48 45 4e 0a 09 09 36  $exec...THEN...6
65f0: 34 23 2d 31 20 36 34 23 30 0a 09 20 20 20 20 54  4#-1 64#0..    T
6600: 48 45 4e 20 20 65 6e 64 64 20 6c 65 2d 36 34 21  HEN  endd le-64!
6610: 20 73 74 61 72 74 64 20 6c 65 2d 36 34 21 0a 09   startd le-64!..
6620: 54 48 45 4e 0a 20 20 20 20 32 20 36 34 73 20 2b  THEN.    2 64s +
6630: 4c 4f 4f 50 0a 20 20 20 20 73 74 61 72 74 64 20  LOOP.    startd 
6640: 6c 65 2d 36 34 40 20 36 34 23 2d 31 20 36 34 3c  le-64@ 64#-1 64<
6650: 3e 20 49 46 0a 09 65 6e 64 64 20 73 74 61 72 74  > IF..endd start
6660: 64 20 5b 3a 20 31 20 36 34 73 20 66 6f 72 74 68  d [: 1 64s forth
6670: 3a 74 79 70 65 20 31 20 36 34 73 20 66 6f 72 74  :type 1 64s fort
6680: 68 3a 74 79 70 65 20 6c 61 73 74 23 20 24 2e 20  h:type last# $. 
6690: 3b 5d 0a 09 61 73 6b 2d 6d 73 67 2d 66 69 6c 65  ;]..ask-msg-file
66a0: 73 5b 5d 20 64 75 70 20 24 5b 5d 23 20 73 77 61  s[] dup $[]# swa
66b0: 70 20 24 5b 5d 20 24 65 78 65 63 0a 20 20 20 20  p $[] $exec.    
66c0: 54 48 45 4e 20 3b 0a 3a 20 6d 73 67 3a 6c 61 73  THEN ;.: msg:las
66d0: 74 20 28 20 24 3a 5b 74 69 63 6b 30 2c 74 69 63  t ( $:[tick0,tic
66e0: 6b 31 2c 2e 2e 2e 2c 74 69 63 6b 6e 5d 20 6e 20  k1,...,tickn] n 
66f0: 2d 2d 20 29 0a 20 20 20 20 6c 61 73 74 23 20 3e  -- ).    last# >
6700: 72 20 20 61 73 6b 2d 6d 73 67 2d 66 69 6c 65 73  r  ask-msg-files
6710: 5b 5d 20 24 5b 5d 6f 66 66 0a 20 20 20 20 66 6f  [] $[]off.    fo
6720: 72 74 68 3a 2e 20 2e 22 20 4d 65 73 73 61 67 65  rth:. ." Message
6730: 73 3a 22 20 66 6f 72 74 68 3a 63 72 0a 20 20 20  s:" forth:cr.   
6740: 20 3f 61 73 6b 2d 6d 73 67 2d 66 69 6c 65 73 20   ?ask-msg-files 
6750: 61 73 6b 2d 6d 73 67 2d 66 69 6c 65 73 5b 5d 20  ask-msg-files[] 
6760: 24 5b 5d 23 20 49 46 0a 09 70 61 72 65 6e 74 20  $[]# IF..parent 
6770: 3e 6f 20 20 65 78 70 65 63 74 2b 73 6c 75 72 70  >o  expect+slurp
6780: 0a 09 63 6d 64 62 75 66 23 20 40 20 30 3d 20 49  ..cmdbuf# @ 0= I
6790: 46 20 20 24 31 30 20 62 6c 6f 63 6b 73 69 7a 65  F  $10 blocksize
67a0: 21 20 24 31 20 62 6c 6f 63 6b 61 6c 69 67 6e 21  ! $1 blockalign!
67b0: 20 20 54 48 45 4e 0a 09 61 73 6b 2d 6d 73 67 2d    THEN..ask-msg-
67c0: 66 69 6c 65 73 5b 5d 20 5b 27 5d 20 6e 65 74 32  files[] ['] net2
67d0: 6f 3a 63 6f 70 79 2d 6d 73 67 20 24 5b 5d 6d 61  o:copy-msg $[]ma
67e0: 70 20 6f 3e 0a 20 20 20 20 45 4c 53 45 0a 09 2e  p o>.    ELSE...
67f0: 22 20 3d 3d 3d 20 6e 6f 74 68 69 6e 67 20 74 6f  " === nothing to
6800: 20 73 79 6e 63 20 3d 3d 3d 22 20 66 6f 72 74 68   sync ===" forth
6810: 3a 63 72 0a 09 70 61 72 65 6e 74 20 2e 73 79 6e  :cr..parent .syn
6820: 63 2d 6e 6f 6e 65 2d 78 74 20 5c 20 73 79 6e 63  c-none-xt \ sync
6830: 2d 6e 6f 74 68 69 6e 67 2d 78 74 3f 3f 3f 0a 20  -nothing-xt???. 
6840: 20 20 20 54 48 45 4e 0a 20 20 20 20 72 3e 20 74     THEN.    r> t
6850: 6f 20 6c 61 73 74 23 20 3b 0a 0a 3a 6e 6f 6e 61  o last# ;..:nona
6860: 6d 65 20 28 20 2d 2d 20 36 34 6c 65 6e 20 29 0a  me ( -- 64len ).
6870: 20 20 20 20 5c 20 70 6f 6c 6c 20 73 65 72 69 61      \ poll seria
6880: 6c 69 7a 65 73 20 74 68 65 20 0a 20 20 20 20 66  lizes the .    f
6890: 73 2d 6f 75 74 62 75 66 20 24 6f 66 66 0a 20 20  s-outbuf $off.  
68a0: 20 20 66 73 2d 70 61 74 68 20 24 40 20 32 20 36    fs-path $@ 2 6
68b0: 34 73 20 2f 73 74 72 69 6e 67 20 3e 67 72 6f 75  4s /string >grou
68c0: 70 0a 20 20 20 20 6d 73 67 2d 6c 6f 67 40 20 6f  p.    msg-log@ o
68d0: 76 65 72 20 3e 72 0a 20 20 20 20 66 73 2d 70 61  ver >r.    fs-pa
68e0: 74 68 20 24 40 20 64 72 6f 70 20 6c 65 2d 36 34  th $@ drop le-64
68f0: 40 20 64 61 74 65 3e 69 20 5c 20 73 74 61 72 74  @ date>i \ start
6900: 20 69 6e 64 65 78 0a 20 20 20 20 66 73 2d 70 61   index.    fs-pa
6910: 74 68 20 24 40 20 64 72 6f 70 20 36 34 27 2b 20  th $@ drop 64'+ 
6920: 6c 65 2d 36 34 40 20 36 34 23 31 20 36 34 2b 20  le-64@ 64#1 64+ 
6930: 64 61 74 65 3e 69 27 20 5c 20 65 6e 64 20 69 6e  date>i' \ end in
6940: 64 65 78 0a 20 20 20 20 6f 76 65 72 20 2d 20 3e  dex.    over - >
6950: 72 0a 20 20 20 20 63 65 6c 6c 73 20 73 61 66 65  r.    cells safe
6960: 2f 73 74 72 69 6e 67 20 72 3e 20 63 65 6c 6c 73  /string r> cells
6970: 20 75 6d 69 6e 0a 20 20 20 20 72 65 71 3f 20 40   umin.    req? @
6980: 20 3e 72 20 72 65 71 3f 20 6f 66 66 20 20 73 65   >r req? off  se
6990: 72 69 61 6c 69 7a 65 2d 6c 6f 67 20 20 20 72 3e  rialize-log   r>
69a0: 20 72 65 71 3f 20 21 20 20 66 73 2d 6f 75 74 62   req? !  fs-outb
69b0: 75 66 20 24 21 62 75 66 0a 20 20 20 20 72 3e 20  uf $!buf.    r> 
69c0: 66 72 65 65 20 74 68 72 6f 77 0a 20 20 20 20 66  free throw.    f
69d0: 73 2d 6f 75 74 62 75 66 20 24 40 6c 65 6e 20 75  s-outbuf $@len u
69e0: 3e 36 34 20 3b 20 6d 73 67 66 73 2d 63 6c 61 73  >64 ; msgfs-clas
69f0: 73 20 69 73 20 66 73 2d 70 6f 6c 6c 0a 3a 6e 6f  s is fs-poll.:no
6a00: 6e 61 6d 65 20 28 20 61 64 64 72 20 75 20 6d 6f  name ( addr u mo
6a10: 64 65 20 2d 2d 20 29 0a 20 20 20 20 5c 47 20 61  de -- ).    \G a
6a20: 64 64 72 20 75 20 69 73 20 73 74 61 72 74 74 69  ddr u is startti
6a30: 63 6b 20 65 6e 64 74 69 63 6b 20 6e 61 6d 65 20  ck endtick name 
6a40: 63 6f 6e 63 61 74 65 6e 61 74 65 64 20 74 6f 67  concatenated tog
6a50: 65 74 68 65 72 0a 20 20 20 20 66 73 2d 63 6c 6f  ether.    fs-clo
6a60: 73 65 20 64 72 6f 70 20 66 73 2d 70 61 74 68 20  se drop fs-path 
6a70: 24 21 20 20 66 73 2d 70 6f 6c 6c 20 66 73 2d 73  $!  fs-poll fs-s
6a80: 69 7a 65 21 0a 20 20 20 20 5b 27 5d 20 6e 6f 6f  ize!.    ['] noo
6a90: 70 20 69 73 20 66 69 6c 65 2d 78 74 0a 3b 20 6d  p is file-xt.; m
6aa0: 73 67 66 73 2d 63 6c 61 73 73 20 69 73 20 66 73  sgfs-class is fs
6ab0: 2d 6f 70 65 6e 0a 0a 5c 20 73 79 6e 63 69 6e 67  -open..\ syncing
6ac0: 20 64 6f 6e 65 0a 3a 20 63 68 61 74 2d 73 79 6e   done.: chat-syn
6ad0: 63 2d 64 6f 6e 65 20 28 20 67 72 6f 75 70 2d 61  c-done ( group-a
6ae0: 64 64 72 20 75 20 2d 2d 20 29 0a 20 20 20 20 6d  ddr u -- ).    m
6af0: 73 67 28 20 2e 22 20 63 68 61 74 2d 73 79 6e 63  sg( ." chat-sync
6b00: 2d 64 6f 6e 65 20 22 20 32 64 75 70 20 66 6f 72  -done " 2dup for
6b10: 74 68 3a 74 79 70 65 20 66 6f 72 74 68 3a 63 72  th:type forth:cr
6b20: 20 29 0a 20 20 20 20 3e 67 72 6f 75 70 20 64 69   ).    >group di
6b30: 73 70 6c 61 79 2d 73 79 6e 63 2d 64 6f 6e 65 20  splay-sync-done 
6b40: 21 73 61 76 65 2d 61 6c 6c 2d 6d 73 67 73 0a 20  !save-all-msgs. 
6b50: 20 20 20 6e 65 74 32 6f 2d 63 6f 64 65 20 65 78     net2o-code ex
6b60: 70 65 63 74 2d 6d 73 67 20 63 6c 6f 73 65 2d 61  pect-msg close-a
6b70: 6c 6c 20 6e 65 74 32 6f 3a 67 65 6e 2d 72 65 73  ll net2o:gen-res
6b80: 65 74 20 65 6e 64 2d 63 6f 64 65 0a 20 20 20 20  et end-code.    
6b90: 6e 65 74 32 6f 3a 63 6c 6f 73 65 2d 61 6c 6c 0a  net2o:close-all.
6ba0: 20 20 20 20 2e 22 20 3d 3d 3d 20 73 79 6e 63 20      ." === sync 
6bb0: 64 6f 6e 65 20 3d 3d 3d 22 20 66 6f 72 74 68 3a  done ===" forth:
6bc0: 63 72 20 73 79 6e 63 2d 64 6f 6e 65 2d 78 74 20  cr sync-done-xt 
6bd0: 3b 0a 65 76 65 6e 74 3a 20 3a 3e 6d 73 67 2d 65  ;.event: :>msg-e
6be0: 76 61 6c 20 28 20 70 61 72 65 6e 74 20 24 70 61  val ( parent $pa
6bf0: 63 6b 20 24 61 64 64 72 20 2d 2d 20 29 0a 20 20  ck $addr -- ).  
6c00: 20 20 7b 20 77 5e 20 62 75 66 20 77 5e 20 67 72    { w^ buf w^ gr
6c10: 6f 75 70 20 7d 0a 20 20 20 20 67 72 6f 75 70 20  oup }.    group 
6c20: 24 40 20 32 20 36 34 73 20 2f 73 74 72 69 6e 67  $@ 2 64s /string
6c30: 20 7b 20 64 3a 20 67 6e 61 6d 65 20 7d 0a 20 20   { d: gname }.  
6c40: 20 20 67 6e 61 6d 65 20 3e 67 72 6f 75 70 0a 20    gname >group. 
6c50: 20 20 20 6d 73 67 2d 67 72 6f 75 70 2d 6f 20 2e     msg-group-o .
6c60: 6d 73 67 3a 6c 6f 67 5b 5d 20 24 5b 5d 23 20 75  msg:log[] $[]# u
6c70: 2e 0a 20 20 20 20 62 75 66 20 24 40 20 74 72 75  ..    buf $@ tru
6c80: 65 20 72 65 70 6c 61 79 2d 6d 6f 64 65 20 5b 27  e replay-mode ['
6c90: 5d 20 6d 73 67 2d 65 76 61 6c 20 21 77 72 61 70  ] msg-eval !wrap
6ca0: 70 65 72 0a 20 20 20 20 62 75 66 20 24 66 72 65  per.    buf $fre
6cb0: 65 20 3f 73 61 76 65 2d 6d 73 67 0a 20 20 20 20  e ?save-msg.    
6cc0: 67 72 6f 75 70 20 24 40 20 2e 63 68 61 74 2d 66  group $@ .chat-f
6cd0: 69 6c 65 20 2e 22 20 20 73 61 76 65 64 20 22 0a  ile ."  saved ".
6ce0: 20 20 20 20 6d 73 67 2d 67 72 6f 75 70 2d 6f 20      msg-group-o 
6cf0: 2e 6d 73 67 3a 6c 6f 67 5b 5d 20 24 5b 5d 23 20  .msg:log[] $[]# 
6d00: 75 2e 20 66 6f 72 74 68 3a 63 72 0a 20 20 20 20  u. forth:cr.    
6d10: 3e 6f 20 2d 31 20 66 69 6c 65 2d 63 6f 75 6e 74  >o -1 file-count
6d20: 20 2b 21 40 20 31 20 3d 0a 20 20 20 20 49 46 20   +!@ 1 =.    IF 
6d30: 20 67 6e 61 6d 65 20 63 68 61 74 2d 73 79 6e 63   gname chat-sync
6d40: 2d 64 6f 6e 65 20 20 54 48 45 4e 20 20 67 72 6f  -done  THEN  gro
6d50: 75 70 20 24 66 72 65 65 0a 20 20 20 20 6f 3e 20  up $free.    o> 
6d60: 3b 0a 3a 20 6d 73 67 2d 66 69 6c 65 2d 64 6f 6e  ;.: msg-file-don
6d70: 65 20 28 20 2d 2d 20 29 0a 20 20 20 20 66 73 2d  e ( -- ).    fs-
6d80: 70 61 74 68 20 24 40 6c 65 6e 20 49 46 0a 09 6d  path $@len IF..m
6d90: 73 67 28 20 2e 22 20 6d 73 67 20 66 69 6c 65 20  sg( ." msg file 
6da0: 64 6f 6e 65 3a 20 22 20 66 73 2d 70 61 74 68 20  done: " fs-path 
6db0: 24 40 20 2e 63 68 61 74 2d 66 69 6c 65 20 66 6f  $@ .chat-file fo
6dc0: 72 74 68 3a 63 72 20 29 0a 09 5b 27 5d 20 66 73  rth:cr )..['] fs
6dd0: 2d 66 6c 75 73 68 20 66 69 6c 65 2d 73 65 6d 61  -flush file-sema
6de0: 20 63 2d 73 65 63 74 69 6f 6e 0a 20 20 20 20 54   c-section.    T
6df0: 48 45 4e 20 3b 0a 3a 6e 6f 6e 61 6d 65 20 28 20  HEN ;.:noname ( 
6e00: 61 64 64 72 20 75 20 6d 6f 64 65 20 2d 2d 20 29  addr u mode -- )
6e10: 0a 20 20 20 20 66 73 2d 63 6c 6f 73 65 20 64 72  .    fs-close dr
6e20: 6f 70 20 66 73 2d 70 61 74 68 20 24 21 0a 20 20  op fs-path $!.  
6e30: 20 20 5b 27 5d 20 6d 73 67 2d 66 69 6c 65 2d 64    ['] msg-file-d
6e40: 6f 6e 65 20 69 73 20 66 69 6c 65 2d 78 74 0a 3b  one is file-xt.;
6e50: 20 6d 73 67 66 73 2d 63 6c 61 73 73 20 69 73 20   msgfs-class is 
6e60: 66 73 2d 63 72 65 61 74 65 0a 3a 6e 6f 6e 61 6d  fs-create.:nonam
6e70: 65 20 28 20 61 64 64 72 20 75 20 2d 2d 20 75 20  e ( addr u -- u 
6e80: 29 0a 20 20 20 20 5b 20 74 65 72 6d 73 65 72 76  ).    [ termserv
6e90: 65 72 2d 63 6c 61 73 73 20 3a 3a 20 66 73 2d 72  er-class :: fs-r
6ea0: 65 61 64 20 5d 0a 3b 20 6d 73 67 66 73 2d 63 6c  ead ].; msgfs-cl
6eb0: 61 73 73 20 69 73 20 66 73 2d 72 65 61 64 0a 3a  ass is fs-read.:
6ec0: 6e 6f 6e 61 6d 65 20 28 20 2d 2d 20 29 0a 09 3c  noname ( -- )..<
6ed0: 65 76 65 6e 74 20 70 61 72 65 6e 74 20 65 6c 69  event parent eli
6ee0: 74 2c 20 30 20 66 73 2d 69 6e 62 75 66 20 21 40  t, 0 fs-inbuf !@
6ef0: 20 65 6c 69 74 2c 20 20 30 20 66 73 2d 70 61 74   elit,  0 fs-pat
6f00: 68 20 21 40 20 65 6c 69 74 2c 20 3a 3e 6d 73 67  h !@ elit, :>msg
6f10: 2d 65 76 61 6c 0a 09 70 61 72 65 6e 74 20 2e 77  -eval..parent .w
6f20: 61 69 74 2d 74 61 73 6b 20 40 20 65 76 65 6e 74  ait-task @ event
6f30: 3e 0a 09 66 73 3a 66 73 2d 63 6c 65 61 72 0a 3b  >..fs:fs-clear.;
6f40: 20 6d 73 67 66 73 2d 63 6c 61 73 73 20 69 73 20   msgfs-class is 
6f50: 66 73 2d 66 6c 75 73 68 20 20 20 20 0a 3a 6e 6f  fs-flush    .:no
6f60: 6e 61 6d 65 20 28 20 2d 2d 20 29 0a 20 20 20 20  name ( -- ).    
6f70: 66 73 2d 70 61 74 68 20 40 20 30 3d 20 3f 45 58  fs-path @ 0= ?EX
6f80: 49 54 0a 20 20 20 20 66 73 2d 69 6e 62 75 66 20  IT.    fs-inbuf 
6f90: 24 40 6c 65 6e 20 49 46 0a 09 6d 73 67 28 20 2e  $@len IF..msg( .
6fa0: 22 20 43 6c 6f 73 69 6e 67 20 66 69 6c 65 20 22  " Closing file "
6fb0: 20 66 73 2d 70 61 74 68 20 24 40 20 2e 63 68 61   fs-path $@ .cha
6fc0: 74 2d 66 69 6c 65 20 66 6f 72 74 68 3a 63 72 20  t-file forth:cr 
6fd0: 29 0a 09 66 73 2d 66 6c 75 73 68 0a 20 20 20 20  )..fs-flush.    
6fe0: 54 48 45 4e 0a 3b 20 6d 73 67 66 73 2d 63 6c 61  THEN.; msgfs-cla
6ff0: 73 73 20 69 73 20 66 73 2d 63 6c 6f 73 65 0a 3a  ss is fs-close.:
7000: 6e 6f 6e 61 6d 65 20 28 20 70 65 72 6d 20 2d 2d  noname ( perm --
7010: 20 29 0a 20 20 20 20 70 65 72 6d 25 6d 73 67 20   ).    perm%msg 
7020: 61 6e 64 20 30 3d 20 21 21 6d 73 67 2d 70 65 72  and 0= !!msg-per
7030: 6d 21 21 0a 3b 20 6d 73 67 66 73 2d 63 6c 61 73  m!!.; msgfs-clas
7040: 73 20 69 73 20 66 73 2d 70 65 72 6d 3f 0a 3a 6e  s is fs-perm?.:n
7050: 6f 6e 61 6d 65 20 28 20 2d 2d 20 64 61 74 65 20  oname ( -- date 
7060: 70 65 72 6d 20 29 0a 20 20 20 20 36 34 23 30 20  perm ).    64#0 
7070: 30 20 3b 20 6d 73 67 66 73 2d 63 6c 61 73 73 20  0 ; msgfs-class 
7080: 69 73 20 66 73 2d 67 65 74 2d 73 74 61 74 0a 3a  is fs-get-stat.:
7090: 6e 6f 6e 61 6d 65 20 28 20 64 61 74 65 20 70 65  noname ( date pe
70a0: 72 6d 20 2d 2d 20 29 0a 20 20 20 20 64 72 6f 70  rm -- ).    drop
70b0: 20 36 34 64 72 6f 70 20 3b 20 6d 73 67 66 73 2d   64drop ; msgfs-
70c0: 63 6c 61 73 73 20 69 73 20 66 73 2d 73 65 74 2d  class is fs-set-
70d0: 73 74 61 74 0a 27 20 66 69 6c 65 2d 73 74 61 72  stat.' file-star
70e0: 74 2d 72 65 71 20 6d 73 67 66 73 2d 63 6c 61 73  t-req msgfs-clas
70f0: 73 20 69 73 20 73 74 61 72 74 2d 72 65 71 0a 0a  s is start-req..
7100: 5c 20 6d 65 73 73 61 67 65 20 63 6f 6d 70 6f 73  \ message compos
7110: 65 72 0a 0a 3a 20 67 72 6f 75 70 2c 20 28 20 61  er..: group, ( a
7120: 64 64 72 20 75 20 2d 2d 20 29 0a 20 20 20 20 24  ddr u -- ).    $
7130: 2c 20 6d 73 67 2d 67 72 6f 75 70 20 3b 0a 3a 20  , msg-group ;.: 
7140: 3c 6d 73 67 20 28 20 2d 2d 20 29 0a 20 20 20 20  <msg ( -- ).    
7150: 73 69 67 6e 5b 20 6d 73 67 2d 67 72 6f 75 70 2d  sign[ msg-group-
7160: 6f 20 2e 6d 73 67 3a 3f 6c 6f 63 6b 20 49 46 20  o .msg:?lock IF 
7170: 20 2b 7a 65 72 6f 31 36 20 20 54 48 45 4e 20 3b   +zero16  THEN ;
7180: 0a 0a 3a 20 6d 73 67 3e 20 28 20 2d 2d 20 29 0a  ..: msg> ( -- ).
7190: 20 20 20 20 5c 47 20 65 6e 64 20 61 20 6d 65 73      \G end a mes
71a0: 73 61 67 65 20 62 6c 6f 63 6b 20 62 79 20 61 64  sage block by ad
71b0: 64 69 6e 67 20 61 20 73 69 67 6e 61 74 75 72 65  ding a signature
71c0: 0a 20 20 20 20 6d 73 67 2d 67 72 6f 75 70 2d 6f  .    msg-group-o
71d0: 20 2e 6d 73 67 3a 3f 6c 6f 63 6b 20 49 46 20 20   .msg:?lock IF  
71e0: 5d 65 6e 63 70 6b 73 69 67 6e 20 20 45 4c 53 45  ]encpksign  ELSE
71f0: 20 20 5d 70 6b 73 69 67 6e 20 20 54 48 45 4e 20    ]pksign  THEN 
7200: 3b 0a 3a 20 6d 73 67 2d 6f 74 72 3e 20 28 20 2d  ;.: msg-otr> ( -
7210: 2d 20 29 0a 20 20 20 20 5c 47 20 65 6e 64 20 61  - ).    \G end a
7220: 20 6d 65 73 73 61 67 65 20 62 6c 6f 63 6b 20 62   message block b
7230: 79 20 61 64 64 69 6e 67 20 61 20 73 68 6f 72 74  y adding a short
7240: 2d 74 69 6d 65 20 73 69 67 6e 61 74 75 72 65 0a  -time signature.
7250: 20 20 20 20 6e 6f 77 3e 6f 74 72 20 6d 73 67 3e      now>otr msg>
7260: 20 3b 0a 3a 20 6d 73 67 2d 6c 6f 67 2c 20 28 20   ;.: msg-log, ( 
7270: 2d 2d 20 61 64 64 72 20 75 20 29 0a 20 20 20 20  -- addr u ).    
7280: 6c 61 73 74 2d 73 69 67 6e 65 64 20 32 40 20 3e  last-signed 2@ >
7290: 6d 73 67 2d 6c 6f 67 20 3b 0a 0a 70 72 65 76 69  msg-log ;..previ
72a0: 6f 75 73 0a 0a 3a 20 3f 64 65 73 74 70 6b 20 28  ous..: ?destpk (
72b0: 20 61 64 64 72 20 75 20 2d 2d 20 61 64 64 72 27   addr u -- addr'
72c0: 20 75 27 20 29 0a 20 20 20 20 32 64 75 70 20 63   u' ).    2dup c
72d0: 6f 6e 6e 65 63 74 69 6f 6e 20 2e 70 75 62 6b 65  onnection .pubke
72e0: 79 20 24 40 20 6b 65 79 7c 20 73 74 72 3d 20 49  y $@ key| str= I
72f0: 46 20 20 32 64 72 6f 70 20 70 6b 40 20 6b 65 79  F  2drop pk@ key
7300: 7c 20 20 54 48 45 4e 20 3b 0a 0a 3a 20 6c 61 73  |  THEN ;..: las
7310: 74 2d 73 69 67 6e 64 61 74 65 40 20 28 20 2d 2d  t-signdate@ ( --
7320: 20 36 34 64 61 74 65 20 29 0a 20 20 20 20 6d 73   64date ).    ms
7330: 67 2d 67 72 6f 75 70 2d 6f 20 2e 6d 73 67 3a 6c  g-group-o .msg:l
7340: 6f 67 5b 5d 20 24 40 20 64 75 70 20 49 46 0a 09  og[] $@ dup IF..
7350: 2b 20 63 65 6c 6c 2d 20 24 40 20 73 74 61 72 74  + cell- $@ start
7360: 64 61 74 65 40 20 36 34 23 31 20 36 34 2b 0a 20  date@ 64#1 64+. 
7370: 20 20 20 45 4c 53 45 20 20 32 64 72 6f 70 20 36     ELSE  2drop 6
7380: 34 23 2d 31 20 20 54 48 45 4e 20 3b 0a 0a 61 6c  4#-1  THEN ;..al
7390: 73 6f 20 6e 65 74 32 6f 2d 62 61 73 65 0a 3a 20  so net2o-base.: 
73a0: 5b 6d 73 67 2c 5d 20 28 20 78 74 20 2d 2d 20 29  [msg,] ( xt -- )
73b0: 20 20 6c 61 73 74 23 20 3e 72 0a 20 20 20 20 6d    last# >r.    m
73c0: 73 67 2d 67 72 6f 75 70 24 20 24 40 20 64 75 70  sg-group$ $@ dup
73d0: 20 49 46 20 20 6d 65 73 73 61 67 65 20 3f 64 65   IF  message ?de
73e0: 73 74 70 6b 20 32 64 75 70 20 3e 67 72 6f 75 70  stpk 2dup >group
73f0: 20 24 2c 0a 09 65 78 65 63 75 74 65 20 20 65 6e   $,..execute  en
7400: 64 2d 77 69 74 68 0a 20 20 20 20 45 4c 53 45 20  d-with.    ELSE 
7410: 20 32 64 72 6f 70 20 64 72 6f 70 20 20 54 48 45   2drop drop  THE
7420: 4e 20 20 72 3e 20 74 6f 20 6c 61 73 74 23 20 3b  N  r> to last# ;
7430: 0a 0a 3a 20 6c 61 73 74 2c 20 28 20 2d 2d 20 29  ..: last, ( -- )
7440: 0a 20 20 20 20 36 34 23 30 20 36 34 23 2d 31 20  .    64#0 64#-1 
7450: 61 73 6b 2d 6c 61 73 74 23 20 6c 61 73 74 2d 6d  ask-last# last-m
7460: 73 67 73 40 20 3e 72 20 24 2c 20 72 3e 20 75 6c  sgs@ >r $, r> ul
7470: 69 74 2c 20 6d 73 67 2d 6c 61 73 74 20 3b 0a 0a  it, msg-last ;..
7480: 3a 20 6c 61 73 74 3f 2c 20 28 20 2d 2d 20 29 0a  : last?, ( -- ).
7490: 20 20 20 20 6c 61 73 74 2d 73 69 67 6e 64 61 74      last-signdat
74a0: 65 40 20 7b 20 36 34 3a 20 64 61 74 65 20 7d 0a  e@ { 64: date }.
74b0: 20 20 20 20 36 34 23 30 20 6c 69 74 2c 20 64 61      64#0 lit, da
74c0: 74 65 20 6c 69 74 2c 20 61 73 6b 2d 6c 61 73 74  te lit, ask-last
74d0: 23 20 75 6c 69 74 2c 20 6d 73 67 2d 6c 61 73 74  # ulit, msg-last
74e0: 3f 0a 20 20 20 20 64 61 74 65 20 36 34 23 2d 31  ?.    date 64#-1
74f0: 20 36 34 3c 3e 20 49 46 0a 09 64 61 74 65 20 6c   64<> IF..date l
7500: 69 74 2c 20 36 34 23 2d 31 20 6c 69 74 2c 20 31  it, 64#-1 lit, 1
7510: 20 75 6c 69 74 2c 20 6d 73 67 2d 6c 61 73 74 3f   ulit, msg-last?
7520: 0a 20 20 20 20 54 48 45 4e 20 3b 0a 0a 3a 20 73  .    THEN ;..: s
7530: 79 6e 63 2d 61 68 65 61 64 3f 2c 20 28 20 2d 2d  ync-ahead?, ( --
7540: 20 29 0a 20 20 20 20 6c 61 73 74 2d 73 69 67 6e   ).    last-sign
7550: 64 61 74 65 40 20 36 34 23 31 20 36 34 2b 20 6c  date@ 64#1 64+ l
7560: 69 74 2c 20 36 34 23 2d 31 20 6c 69 74 2c 20 61  it, 64#-1 lit, a
7570: 73 6b 2d 6c 61 73 74 23 20 75 6c 69 74 2c 20 6d  sk-last# ulit, m
7580: 73 67 2d 6c 61 73 74 3f 20 3b 0a 0a 3a 20 6a 6f  sg-last? ;..: jo
7590: 69 6e 2c 20 28 20 2d 2d 20 29 0a 20 20 20 20 5b  in, ( -- ).    [
75a0: 3a 20 6d 73 67 2d 6a 6f 69 6e 20 73 79 6e 63 2d  : msg-join sync-
75b0: 61 68 65 61 64 3f 2c 0a 20 20 20 20 20 20 3c 6d  ahead?,.      <m
75c0: 73 67 20 6d 73 67 2d 73 74 61 72 74 20 22 6a 6f  sg msg-start "jo
75d0: 69 6e 65 64 22 20 24 2c 20 6d 73 67 2d 61 63 74  ined" $, msg-act
75e0: 69 6f 6e 20 6d 73 67 2d 6f 74 72 3e 20 3b 5d 20  ion msg-otr> ;] 
75f0: 5b 6d 73 67 2c 5d 20 3b 0a 0a 3a 20 73 69 6c 65  [msg,] ;..: sile
7600: 6e 74 2d 6a 6f 69 6e 2c 20 28 20 2d 2d 20 29 0a  nt-join, ( -- ).
7610: 20 20 20 20 6d 73 67 2d 67 72 6f 75 70 24 20 24      msg-group$ $
7620: 40 20 64 75 70 20 49 46 20 20 6d 65 73 73 61 67  @ dup IF  messag
7630: 65 20 24 2c 20 6d 73 67 2d 6a 6f 69 6e 20 20 65  e $, msg-join  e
7640: 6e 64 2d 77 69 74 68 0a 20 20 20 20 45 4c 53 45  nd-with.    ELSE
7650: 20 20 32 64 72 6f 70 20 20 54 48 45 4e 20 3b 0a    2drop  THEN ;.
7660: 0a 3a 20 6c 65 61 76 65 2c 20 28 20 2d 2d 20 29  .: leave, ( -- )
7670: 0a 20 20 20 20 5b 3a 20 6d 73 67 2d 6c 65 61 76  .    [: msg-leav
7680: 65 0a 20 20 20 20 20 20 3c 6d 73 67 20 6d 73 67  e.      <msg msg
7690: 2d 73 74 61 72 74 20 22 6c 65 66 74 22 20 24 2c  -start "left" $,
76a0: 20 6d 73 67 2d 61 63 74 69 6f 6e 20 6d 73 67 2d   msg-action msg-
76b0: 6f 74 72 3e 20 3b 5d 20 5b 6d 73 67 2c 5d 20 3b  otr> ;] [msg,] ;
76c0: 0a 0a 3a 20 73 69 6c 65 6e 74 2d 6c 65 61 76 65  ..: silent-leave
76d0: 2c 20 28 20 2d 2d 20 29 0a 20 20 20 20 5b 27 5d  , ( -- ).    [']
76e0: 20 6d 73 67 2d 6c 65 61 76 65 20 5b 6d 73 67 2c   msg-leave [msg,
76f0: 5d 20 3b 0a 0a 3a 20 6c 65 66 74 2c 20 28 20 61  ] ;..: left, ( a
7700: 64 64 72 20 75 20 2d 2d 20 29 0a 20 20 20 20 6b  ddr u -- ).    k
7710: 65 79 7c 20 24 2c 20 6d 73 67 2d 73 69 67 6e 61  ey| $, msg-signa
7720: 6c 20 22 6c 65 66 74 20 28 74 69 6d 65 6f 75 74  l "left (timeout
7730: 29 22 20 24 2c 20 6d 73 67 2d 61 63 74 69 6f 6e  )" $, msg-action
7740: 20 3b 0a 70 72 65 76 69 6f 75 73 0a 0a 3a 20 73   ;.previous..: s
7750: 65 6e 64 2d 6a 6f 69 6e 20 28 20 2d 2d 20 29 0a  end-join ( -- ).
7760: 20 20 20 20 6e 65 74 32 6f 2d 63 6f 64 65 20 65      net2o-code e
7770: 78 70 65 63 74 2d 6d 73 67 20 6a 6f 69 6e 2c 0a  xpect-msg join,.
7780: 20 20 20 20 28 20 63 6f 6f 6b 69 65 2b 72 65 71      ( cookie+req
7790: 75 65 73 74 20 29 20 65 6e 64 2d 63 6f 64 65 7c  uest ) end-code|
77a0: 20 3b 0a 0a 3a 20 73 69 6c 65 6e 74 2d 6a 6f 69   ;..: silent-joi
77b0: 6e 20 28 20 2d 2d 20 29 0a 20 20 20 20 6e 65 74  n ( -- ).    net
77c0: 32 6f 2d 63 6f 64 65 20 65 78 70 65 63 74 2d 6d  2o-code expect-m
77d0: 73 67 20 73 69 6c 65 6e 74 2d 6a 6f 69 6e 2c 0a  sg silent-join,.
77e0: 20 20 20 20 65 6e 64 2d 63 6f 64 65 20 3b 0a 0a      end-code ;..
77f0: 3a 20 73 65 6e 64 2d 6c 65 61 76 65 20 28 20 2d  : send-leave ( -
7800: 2d 20 29 0a 20 20 20 20 63 6f 6e 6e 65 63 74 69  - ).    connecti
7810: 6f 6e 20 2e 64 61 74 61 2d 72 6d 61 70 20 49 46  on .data-rmap IF
7820: 20 20 6e 65 74 32 6f 2d 63 6f 64 65 20 65 78 70    net2o-code exp
7830: 65 63 74 2d 6d 73 67 20 6c 65 61 76 65 2c 20 65  ect-msg leave, e
7840: 6e 64 2d 63 6f 64 65 7c 20 20 54 48 45 4e 20 3b  nd-code|  THEN ;
7850: 0a 3a 20 73 65 6e 64 2d 73 69 6c 65 6e 74 2d 6c  .: send-silent-l
7860: 65 61 76 65 20 28 20 2d 2d 20 29 0a 20 20 20 20  eave ( -- ).    
7870: 63 6f 6e 6e 65 63 74 69 6f 6e 20 2e 64 61 74 61  connection .data
7880: 2d 72 6d 61 70 20 49 46 20 20 6e 65 74 32 6f 2d  -rmap IF  net2o-
7890: 63 6f 64 65 20 65 78 70 65 63 74 2d 6d 73 67 20  code expect-msg 
78a0: 73 69 6c 65 6e 74 2d 6c 65 61 76 65 2c 20 65 6e  silent-leave, en
78b0: 64 2d 63 6f 64 65 7c 20 20 54 48 45 4e 20 3b 0a  d-code|  THEN ;.
78c0: 0a 3a 20 5b 67 72 6f 75 70 5d 20 28 20 78 74 20  .: [group] ( xt 
78d0: 2d 2d 20 66 6c 61 67 20 29 0a 20 20 20 20 6d 73  -- flag ).    ms
78e0: 67 2d 67 72 6f 75 70 2d 6f 20 2e 6d 73 67 3a 70  g-group-o .msg:p
78f0: 65 65 72 73 5b 5d 20 24 40 6c 65 6e 20 49 46 0a  eers[] $@len IF.
7900: 09 6d 73 67 2d 67 72 6f 75 70 2d 6f 20 2e 65 78  .msg-group-o .ex
7910: 65 63 75 74 65 20 74 72 75 65 0a 20 20 20 20 45  ecute true.    E
7920: 4c 53 45 0a 09 30 20 2e 65 78 65 63 75 74 65 20  LSE..0 .execute 
7930: 66 61 6c 73 65 0a 20 20 20 20 54 48 45 4e 20 3b  false.    THEN ;
7940: 0a 3a 20 2e 63 68 61 74 20 28 20 61 64 64 72 20  .: .chat ( addr 
7950: 75 20 2d 2d 20 29 0a 20 20 20 20 5b 3a 20 6c 61  u -- ).    [: la
7960: 73 74 23 20 3e 72 20 6f 20 49 46 20 20 32 64 75  st# >r o IF  2du
7970: 70 20 64 6f 2d 6d 73 67 2d 6e 65 73 74 73 69 67  p do-msg-nestsig
7980: 0a 20 20 20 20 20 20 45 4c 53 45 20 20 32 64 75  .      ELSE  2du
7990: 70 20 64 69 73 70 6c 61 79 2d 6f 6e 65 2d 6d 73  p display-one-ms
79a0: 67 20 20 54 48 45 4e 20 20 72 3e 20 74 6f 20 6c  g  THEN  r> to l
79b0: 61 73 74 23 0a 20 20 20 20 20 20 30 20 2e 61 76  ast#.      0 .av
79c0: 61 6c 61 6e 63 68 65 2d 6d 73 67 20 3b 5d 20 5b  alanche-msg ;] [
79d0: 67 72 6f 75 70 5d 20 64 72 6f 70 20 6e 6f 74 69  group] drop noti
79e0: 66 79 2d 20 3b 0a 0a 5c 20 63 68 61 74 20 6d 65  fy- ;..\ chat me
79f0: 73 73 61 67 65 2c 20 74 65 78 74 20 6f 6e 6c 79  ssage, text only
7a00: 0a 0a 3a 20 6d 73 67 2d 74 64 69 73 70 6c 61 79  ..: msg-tdisplay
7a10: 20 28 20 61 64 64 72 20 75 20 2d 2d 20 29 0a 20   ( addr u -- ). 
7a20: 20 20 20 32 64 75 70 20 32 20 2d 20 2b 20 63 40     2dup 2 - + c@
7a30: 20 24 38 30 20 61 6e 64 20 49 46 20 20 6d 73 67   $80 and IF  msg
7a40: 2d 64 65 63 2d 73 69 67 3f 20 49 46 0a 09 20 20  -dec-sig? IF..  
7a50: 20 20 32 64 72 6f 70 20 3c 65 72 72 3e 20 2e 22    2drop <err> ."
7a60: 20 55 6e 64 65 63 72 79 70 74 61 62 6c 65 20 6d   Undecryptable m
7a70: 65 73 73 61 67 65 22 20 3c 64 65 66 61 75 6c 74  essage" <default
7a80: 3e 20 63 72 20 20 45 58 49 54 0a 09 54 48 45 4e  > cr  EXIT..THEN
7a90: 20 20 3c 69 6e 66 6f 3e 20 20 54 48 45 4e 0a 20    <info>  THEN. 
7aa0: 20 20 20 73 69 67 70 6b 73 69 7a 65 23 20 2d 20     sigpksize# - 
7ab0: 32 64 75 70 20 2b 20 73 69 67 70 6b 73 69 7a 65  2dup + sigpksize
7ac0: 23 20 3e 24 20 20 63 2d 73 74 61 74 65 20 6f 66  # >$  c-state of
7ad0: 66 0a 20 20 20 20 6e 65 73 74 2d 63 6d 64 2d 6c  f.    nest-cmd-l
7ae0: 6f 6f 70 20 6d 73 67 3a 65 6e 64 20 3c 64 65 66  oop msg:end <def
7af0: 61 75 6c 74 3e 20 3b 0a 27 20 6d 73 67 2d 74 64  ault> ;.' msg-td
7b00: 69 73 70 6c 61 79 20 6d 73 67 2d 63 6c 61 73 73  isplay msg-class
7b10: 20 69 73 20 6d 73 67 3a 64 69 73 70 6c 61 79 0a   is msg:display.
7b20: 27 20 6d 73 67 2d 74 64 69 73 70 6c 61 79 20 6d  ' msg-tdisplay m
7b30: 73 67 2d 6e 6f 74 69 66 79 2d 63 6c 61 73 73 20  sg-notify-class 
7b40: 69 73 20 6d 73 67 3a 64 69 73 70 6c 61 79 0a 3a  is msg:display.:
7b50: 20 3f 73 65 61 72 63 68 2d 6c 6f 63 6b 20 28 20   ?search-lock ( 
7b60: 61 64 64 72 20 75 20 2d 2d 20 29 0a 20 20 20 20  addr u -- ).    
7b70: 42 45 47 49 4e 20 20 64 75 70 20 20 57 48 49 4c  BEGIN  dup  WHIL
7b80: 45 20 20 63 65 6c 6c 2d 20 32 64 75 70 20 2b 20  E  cell- 2dup + 
7b90: 24 40 20 73 69 67 70 6b 73 69 7a 65 23 20 2d 20  $@ sigpksize# - 
7ba0: 31 2d 20 2b 20 63 40 20 24 32 45 20 3d 20 49 46  1- + c@ $2E = IF
7bb0: 0a 09 09 32 64 75 70 20 2b 20 24 40 20 5b 27 5d  ...2dup + $@ [']
7bc0: 20 6d 73 67 3a 64 69 73 70 6c 61 79 20 63 61 74   msg:display cat
7bd0: 63 68 20 49 46 20 20 32 64 72 6f 70 20 20 54 48  ch IF  2drop  TH
7be0: 45 4e 0a 09 09 6d 73 67 2d 67 72 6f 75 70 2d 6f  EN...msg-group-o
7bf0: 20 2e 6d 73 67 3a 6b 65 79 73 5b 5d 20 24 5b 5d   .msg:keys[] $[]
7c00: 23 20 49 46 20 20 64 72 6f 70 20 30 20 20 54 48  # IF  drop 0  TH
7c10: 45 4e 0a 09 20 20 20 20 54 48 45 4e 0a 20 20 20  EN..    THEN.   
7c20: 20 52 45 50 45 41 54 20 20 32 64 72 6f 70 20 3b   REPEAT  2drop ;
7c30: 0a 3a 20 6d 73 67 2d 74 72 65 64 69 73 70 6c 61  .: msg-tredispla
7c40: 79 20 28 20 6e 20 2d 2d 20 29 0a 20 20 20 20 72  y ( n -- ).    r
7c50: 65 73 65 74 2d 74 69 6d 65 0a 20 20 20 20 6d 73  eset-time.    ms
7c60: 67 2d 67 72 6f 75 70 2d 6f 20 3e 6f 20 6d 73 67  g-group-o >o msg
7c70: 3a 3f 6f 74 72 20 6d 73 67 3a 2d 6f 74 72 20 6f  :?otr msg:-otr o
7c80: 3e 20 3e 72 0a 20 20 20 20 5b 3a 20 20 63 65 6c  > >r.    [:  cel
7c90: 6c 73 20 3e 72 20 6d 73 67 2d 6c 6f 67 40 0a 09  ls >r msg-log@..
7ca0: 7b 20 6c 6f 67 20 75 20 7d 20 75 20 72 3e 20 2d  { log u } u r> -
7cb0: 20 30 20 6d 61 78 20 7b 20 75 27 20 7d 20 20 6c   0 max { u' }  l
7cc0: 6f 67 20 75 27 20 3f 73 65 61 72 63 68 2d 6c 6f  og u' ?search-lo
7cd0: 63 6b 0a 09 6c 6f 67 20 75 20 75 27 20 2f 73 74  ck..log u u' /st
7ce0: 72 69 6e 67 20 62 6f 75 6e 64 73 20 3f 44 4f 0a  ring bounds ?DO.
7cf0: 09 20 20 20 20 49 20 6c 6f 67 20 2d 20 63 65 6c  .    I log - cel
7d00: 6c 2f 20 74 6f 20 6c 6f 67 23 0a 09 20 20 20 20  l/ to log#..    
7d10: 49 20 24 40 20 7b 20 64 3a 20 6d 73 67 74 20 7d  I $@ { d: msgt }
7d20: 0a 09 20 20 20 20 6d 73 67 74 20 5b 27 5d 20 6d  ..    msgt ['] m
7d30: 73 67 3a 64 69 73 70 6c 61 79 20 63 61 74 63 68  sg:display catch
7d40: 20 49 46 20 20 2e 22 20 69 6e 76 61 6c 69 64 20   IF  ." invalid 
7d50: 65 6e 74 72 79 22 20 63 72 0a 09 09 32 64 72 6f  entry" cr...2dro
7d60: 70 20 20 54 48 45 4e 0a 09 63 65 6c 6c 20 2b 4c  p  THEN..cell +L
7d70: 4f 4f 50 0a 09 6c 6f 67 20 66 72 65 65 20 74 68  OOP..log free th
7d80: 72 6f 77 20 3b 5d 20 63 61 74 63 68 0a 20 20 20  row ;] catch.   
7d90: 20 72 3e 20 49 46 20 20 6d 73 67 2d 67 72 6f 75   r> IF  msg-grou
7da0: 70 2d 6f 20 2e 6d 73 67 3a 2b 6f 74 72 20 20 54  p-o .msg:+otr  T
7db0: 48 45 4e 20 20 74 68 72 6f 77 20 3b 0a 27 20 6d  HEN  throw ;.' m
7dc0: 73 67 2d 74 72 65 64 69 73 70 6c 61 79 20 6d 73  sg-tredisplay ms
7dd0: 67 2d 63 6c 61 73 73 20 69 73 20 6d 73 67 3a 72  g-class is msg:r
7de0: 65 64 69 73 70 6c 61 79 0a 0a 6d 73 67 2d 63 6c  edisplay..msg-cl
7df0: 61 73 73 20 63 6c 61 73 73 0a 65 6e 64 2d 63 6c  ass class.end-cl
7e00: 61 73 73 20 74 65 78 74 6d 73 67 2d 63 6c 61 73  ass textmsg-clas
7e10: 73 0a 0a 27 20 32 64 72 6f 70 20 74 65 78 74 6d  s..' 2drop textm
7e20: 73 67 2d 63 6c 61 73 73 20 69 73 20 6d 73 67 3a  sg-class is msg:
7e30: 73 74 61 72 74 0a 3a 6e 6f 6e 61 6d 65 20 27 23  start.:noname '#
7e40: 27 20 65 6d 69 74 20 74 79 70 65 20 3b 20 74 65  ' emit type ; te
7e50: 78 74 6d 73 67 2d 63 6c 61 73 73 20 69 73 20 6d  xtmsg-class is m
7e60: 73 67 3a 74 61 67 0a 3a 6e 6f 6e 61 6d 65 20 27  sg:tag.:noname '
7e70: 40 27 20 65 6d 69 74 20 2e 73 69 6d 70 6c 65 2d  @' emit .simple-
7e80: 69 64 20 3b 20 74 65 78 74 6d 73 67 2d 63 6c 61  id ; textmsg-cla
7e90: 73 73 20 69 73 20 6d 73 67 3a 73 69 67 6e 61 6c  ss is msg:signal
7ea0: 0a 27 20 32 64 72 6f 70 20 74 65 78 74 6d 73 67  .' 2drop textmsg
7eb0: 2d 63 6c 61 73 73 20 69 73 20 6d 73 67 3a 72 65  -class is msg:re
7ec0: 0a 27 20 32 64 72 6f 70 20 74 65 78 74 6d 73 67  .' 2drop textmsg
7ed0: 2d 63 6c 61 73 73 20 69 73 20 6d 73 67 3a 63 68  -class is msg:ch
7ee0: 61 69 6e 0a 27 20 74 79 70 65 20 74 65 78 74 6d  ain.' type textm
7ef0: 73 67 2d 63 6c 61 73 73 20 69 73 20 6d 73 67 3a  sg-class is msg:
7f00: 74 65 78 74 0a 3a 6e 6f 6e 61 6d 65 20 64 72 6f  text.:noname dro
7f10: 70 20 32 64 72 6f 70 20 3b 20 74 65 78 74 6d 73  p 2drop ; textms
7f20: 67 2d 63 6c 61 73 73 20 69 73 20 6d 73 67 3a 6f  g-class is msg:o
7f30: 62 6a 65 63 74 0a 3a 6e 6f 6e 61 6d 65 20 2e 22  bject.:noname ."
7f40: 20 2f 6d 65 20 22 20 74 79 70 65 20 3b 20 74 65   /me " type ; te
7f50: 78 74 6d 73 67 2d 63 6c 61 73 73 20 69 73 20 6d  xtmsg-class is m
7f60: 73 67 3a 61 63 74 69 6f 6e 0a 3a 6e 6f 6e 61 6d  sg:action.:nonam
7f70: 65 20 2e 22 20 2f 68 65 72 65 20 22 20 32 64 72  e ." /here " 2dr
7f80: 6f 70 20 3b 20 74 65 78 74 6d 73 67 2d 63 6c 61  op ; textmsg-cla
7f90: 73 73 20 69 73 20 6d 73 67 3a 63 6f 6f 72 64 0a  ss is msg:coord.
7fa0: 27 20 6e 6f 6f 70 20 74 65 78 74 6d 73 67 2d 63  ' noop textmsg-c
7fb0: 6c 61 73 73 20 69 73 20 6d 73 67 3a 65 6e 64 0a  lass is msg:end.
7fc0: 0a 74 65 78 74 6d 73 67 2d 63 6c 61 73 73 20 27  .textmsg-class '
7fd0: 20 6e 65 77 20 73 74 61 74 69 63 2d 61 20 77 69   new static-a wi
7fe0: 74 68 2d 61 6c 6c 6f 63 61 74 65 72 20 43 6f 6e  th-allocater Con
7ff0: 73 74 61 6e 74 20 74 65 78 74 6d 73 67 2d 6f 0a  stant textmsg-o.
8000: 6d 73 67 2d 6e 6f 74 69 66 79 2d 6f 20 3e 6f 20  msg-notify-o >o 
8010: 6d 73 67 2d 74 61 62 6c 65 20 40 20 74 6f 6b 65  msg-table @ toke
8020: 6e 2d 74 61 62 6c 65 20 21 20 6f 3e 0a 74 65 78  n-table ! o>.tex
8030: 74 6d 73 67 2d 6f 20 3e 6f 20 6d 73 67 2d 74 61  tmsg-o >o msg-ta
8040: 62 6c 65 20 40 20 74 6f 6b 65 6e 2d 74 61 62 6c  ble @ token-tabl
8050: 65 20 21 20 6f 3e 0a 0a 5c 20 63 68 61 74 20 68  e ! o>..\ chat h
8060: 69 73 74 6f 72 79 20 62 72 6f 77 73 69 6e 67 0a  istory browsing.
8070: 0a 36 34 56 61 72 69 61 62 6c 65 20 6c 69 6e 65  .64Variable line
8080: 2d 64 61 74 65 20 36 34 23 2d 31 20 6c 69 6e 65  -date 64#-1 line
8090: 2d 64 61 74 65 20 36 34 21 0a 56 61 72 69 61 62  -date 64!.Variab
80a0: 6c 65 20 24 6c 61 73 74 6c 69 6e 65 0a 0a 3a 20  le $lastline..: 
80b0: 21 64 61 74 65 20 28 20 61 64 64 72 20 75 20 2d  !date ( addr u -
80c0: 2d 20 61 64 64 72 20 75 20 29 0a 20 20 20 20 32  - addr u ).    2
80d0: 64 75 70 20 2b 20 73 69 67 73 69 7a 65 23 20 2d  dup + sigsize# -
80e0: 20 6c 65 2d 36 34 40 20 6c 69 6e 65 2d 64 61 74   le-64@ line-dat
80f0: 65 20 36 34 21 20 3b 0a 3a 20 66 69 6e 64 2d 70  e 64! ;.: find-p
8100: 72 65 76 2d 63 68 61 74 6c 69 6e 65 20 7b 20 6d  rev-chatline { m
8110: 61 78 6c 65 6e 20 61 64 64 72 20 2d 2d 20 6d 61  axlen addr -- ma
8120: 78 20 73 70 61 6e 20 61 64 64 72 20 73 70 61 6e  x span addr span
8130: 20 7d 0a 20 20 20 20 6d 73 67 2d 67 72 6f 75 70   }.    msg-group
8140: 24 20 24 40 20 3e 67 72 6f 75 70 0a 20 20 20 20  $ $@ >group.    
8150: 6d 73 67 2d 67 72 6f 75 70 2d 6f 20 2e 6d 73 67  msg-group-o .msg
8160: 3a 6c 6f 67 5b 5d 20 24 5b 5d 23 20 30 3d 20 49  :log[] $[]# 0= I
8170: 46 20 20 6d 61 78 6c 65 6e 20 30 20 61 64 64 72  F  maxlen 0 addr
8180: 20 6f 76 65 72 20 20 45 58 49 54 20 20 54 48 45   over  EXIT  THE
8190: 4e 0a 20 20 20 20 6c 69 6e 65 2d 64 61 74 65 20  N.    line-date 
81a0: 36 34 40 20 64 61 74 65 3e 69 27 0a 20 20 20 20  64@ date>i'.    
81b0: 42 45 47 49 4e 20 20 31 2d 20 64 75 70 20 30 3e  BEGIN  1- dup 0>
81c0: 3d 20 57 48 49 4c 45 20 20 64 75 70 20 6d 73 67  = WHILE  dup msg
81d0: 2d 67 72 6f 75 70 2d 6f 20 2e 6d 73 67 3a 6c 6f  -group-o .msg:lo
81e0: 67 5b 5d 20 24 5b 5d 40 0a 09 64 75 70 20 73 69  g[] $[]@..dup si
81f0: 67 70 6b 73 69 7a 65 23 20 2d 20 2f 73 74 72 69  gpksize# - /stri
8200: 6e 67 20 6b 65 79 7c 20 70 6b 40 20 6b 65 79 7c  ng key| pk@ key|
8210: 20 73 74 72 3d 20 20 55 4e 54 49 4c 20 20 54 48   str=  UNTIL  TH
8220: 45 4e 0a 20 20 20 20 6d 73 67 2d 67 72 6f 75 70  EN.    msg-group
8230: 2d 6f 20 2e 6d 73 67 3a 6c 6f 67 5b 5d 20 24 5b  -o .msg:log[] $[
8240: 5d 40 20 64 75 70 20 30 3d 20 49 46 20 20 6e 69  ]@ dup 0= IF  ni
8250: 70 0a 20 20 20 20 45 4c 53 45 20 20 21 64 61 74  p.    ELSE  !dat
8260: 65 20 5b 27 5d 20 6d 73 67 3a 64 69 73 70 6c 61  e ['] msg:displa
8270: 79 20 74 65 78 74 6d 73 67 2d 6f 20 2e 24 74 6d  y textmsg-o .$tm
8280: 70 20 0a 09 64 75 70 20 6d 61 78 6c 65 6e 20 75  p ..dup maxlen u
8290: 3e 20 49 46 20 20 64 75 70 20 3e 72 20 6d 61 78  > IF  dup >r max
82a0: 6c 65 6e 20 30 20 61 64 64 72 20 6f 76 65 72 20  len 0 addr over 
82b0: 72 3e 20 67 72 6f 77 2d 74 69 62 0a 09 20 20 20  r> grow-tib..   
82c0: 20 32 64 72 6f 70 20 74 6f 20 61 64 64 72 20 64   2drop to addr d
82d0: 72 6f 70 20 74 6f 20 6d 61 78 6c 65 6e 20 20 54  rop to maxlen  T
82e0: 48 45 4e 0a 09 74 75 63 6b 20 61 64 64 72 20 6d  HEN..tuck addr m
82f0: 61 78 6c 65 6e 20 73 6d 6f 76 65 0a 20 20 20 20  axlen smove.    
8300: 54 48 45 4e 0a 20 20 20 20 6d 61 78 6c 65 6e 20  THEN.    maxlen 
8310: 73 77 61 70 20 61 64 64 72 20 6f 76 65 72 20 3b  swap addr over ;
8320: 0a 3a 20 66 69 6e 64 2d 6e 65 78 74 2d 63 68 61  .: find-next-cha
8330: 74 6c 69 6e 65 20 7b 20 6d 61 78 6c 65 6e 20 61  tline { maxlen a
8340: 64 64 72 20 2d 2d 20 6d 61 78 20 73 70 61 6e 20  ddr -- max span 
8350: 61 64 64 72 20 73 70 61 6e 20 7d 0a 20 20 20 20  addr span }.    
8360: 6d 73 67 2d 67 72 6f 75 70 24 20 24 40 20 3e 67  msg-group$ $@ >g
8370: 72 6f 75 70 0a 20 20 20 20 6c 69 6e 65 2d 64 61  roup.    line-da
8380: 74 65 20 36 34 40 20 64 61 74 65 3e 69 0a 20 20  te 64@ date>i.  
8390: 20 20 42 45 47 49 4e 20 20 31 2b 20 64 75 70 20    BEGIN  1+ dup 
83a0: 6d 73 67 2d 67 72 6f 75 70 2d 6f 20 2e 6d 73 67  msg-group-o .msg
83b0: 3a 6c 6f 67 5b 5d 20 24 5b 5d 23 20 75 3c 20 57  :log[] $[]# u< W
83c0: 48 49 4c 45 20 20 64 75 70 20 6d 73 67 2d 67 72  HILE  dup msg-gr
83d0: 6f 75 70 2d 6f 20 2e 6d 73 67 3a 6c 6f 67 5b 5d  oup-o .msg:log[]
83e0: 20 24 5b 5d 40 0a 09 64 75 70 20 73 69 67 70 6b   $[]@..dup sigpk
83f0: 73 69 7a 65 23 20 2d 20 2f 73 74 72 69 6e 67 20  size# - /string 
8400: 6b 65 79 7c 20 70 6b 40 20 6b 65 79 7c 20 73 74  key| pk@ key| st
8410: 72 3d 20 20 55 4e 54 49 4c 20 20 54 48 45 4e 0a  r=  UNTIL  THEN.
8420: 20 20 20 20 64 75 70 20 6d 73 67 2d 67 72 6f 75      dup msg-grou
8430: 70 2d 6f 20 2e 6d 73 67 3a 6c 6f 67 5b 5d 20 24  p-o .msg:log[] $
8440: 5b 5d 23 20 75 3e 3d 0a 20 20 20 20 49 46 20 20  []# u>=.    IF  
8450: 20 20 64 72 6f 70 20 24 6c 61 73 74 6c 69 6e 65    drop $lastline
8460: 20 24 40 20 20 36 34 23 2d 31 20 6c 69 6e 65 2d   $@  64#-1 line-
8470: 64 61 74 65 20 36 34 21 0a 20 20 20 20 45 4c 53  date 64!.    ELS
8480: 45 20 20 6d 73 67 2d 67 72 6f 75 70 2d 6f 20 2e  E  msg-group-o .
8490: 6d 73 67 3a 6c 6f 67 5b 5d 20 24 5b 5d 40 20 21  msg:log[] $[]@ !
84a0: 64 61 74 65 20 5b 27 5d 20 6d 73 67 3a 64 69 73  date ['] msg:dis
84b0: 70 6c 61 79 20 74 65 78 74 6d 73 67 2d 6f 20 2e  play textmsg-o .
84c0: 24 74 6d 70 20 20 54 48 45 4e 0a 20 20 20 20 64  $tmp  THEN.    d
84d0: 75 70 20 6d 61 78 6c 65 6e 20 75 3e 20 49 46 20  up maxlen u> IF 
84e0: 20 64 75 70 20 3e 72 20 6d 61 78 6c 65 6e 20 30   dup >r maxlen 0
84f0: 20 61 64 64 72 20 6f 76 65 72 20 72 3e 20 67 72   addr over r> gr
8500: 6f 77 2d 74 69 62 0a 09 32 64 72 6f 70 20 74 6f  ow-tib..2drop to
8510: 20 61 64 64 72 20 64 72 6f 70 20 74 6f 20 6d 61   addr drop to ma
8520: 78 6c 65 6e 20 20 54 48 45 4e 0a 20 20 20 20 74  xlen  THEN.    t
8530: 75 63 6b 20 61 64 64 72 20 6d 61 78 6c 65 6e 20  uck addr maxlen 
8540: 73 6d 6f 76 65 0a 20 20 20 20 6d 61 78 6c 65 6e  smove.    maxlen
8550: 20 73 77 61 70 20 61 64 64 72 20 6f 76 65 72 20   swap addr over 
8560: 3b 0a 0a 3a 20 63 68 61 74 2d 70 72 65 76 2d 6c  ;..: chat-prev-l
8570: 69 6e 65 20 20 28 20 6d 61 78 20 73 70 61 6e 20  ine  ( max span 
8580: 61 64 64 72 20 70 6f 73 31 20 2d 2d 20 6d 61 78  addr pos1 -- max
8590: 20 73 70 61 6e 20 61 64 64 72 20 70 6f 73 32 20   span addr pos2 
85a0: 66 61 6c 73 65 20 29 0a 20 20 20 20 6c 69 6e 65  false ).    line
85b0: 2d 64 61 74 65 20 36 34 40 20 36 34 23 2d 31 20  -date 64@ 64#-1 
85c0: 36 34 3d 20 49 46 0a 09 3e 72 20 32 64 75 70 20  64= IF..>r 2dup 
85d0: 73 77 61 70 20 24 6c 61 73 74 6c 69 6e 65 20 24  swap $lastline $
85e0: 21 20 72 3e 20 20 54 48 45 4e 0a 20 20 20 20 63  ! r>  THEN.    c
85f0: 6c 65 61 72 2d 6c 69 6e 65 20 66 69 6e 64 2d 70  lear-line find-p
8600: 72 65 76 2d 63 68 61 74 6c 69 6e 65 0a 20 20 20  rev-chatline.   
8610: 20 65 64 69 74 2d 75 70 64 61 74 65 20 66 61 6c   edit-update fal
8620: 73 65 20 3b 0a 3a 20 63 68 61 74 2d 6e 65 78 74  se ;.: chat-next
8630: 2d 6c 69 6e 65 20 20 28 20 6d 61 78 20 73 70 61  -line  ( max spa
8640: 6e 20 61 64 64 72 20 70 6f 73 31 20 2d 2d 20 6d  n addr pos1 -- m
8650: 61 78 20 73 70 61 6e 20 61 64 64 72 20 70 6f 73  ax span addr pos
8660: 32 20 66 61 6c 73 65 20 29 0a 20 20 20 20 6c 69  2 false ).    li
8670: 6e 65 2d 64 61 74 65 20 36 34 40 20 36 34 23 2d  ne-date 64@ 64#-
8680: 31 20 36 34 3d 20 49 46 20 20 66 61 6c 73 65 20  1 64= IF  false 
8690: 20 45 58 49 54 20 20 54 48 45 4e 0a 20 20 20 20   EXIT  THEN.    
86a0: 63 6c 65 61 72 2d 6c 69 6e 65 20 66 69 6e 64 2d  clear-line find-
86b0: 6e 65 78 74 2d 63 68 61 74 6c 69 6e 65 0a 20 20  next-chatline.  
86c0: 20 20 65 64 69 74 2d 75 70 64 61 74 65 20 66 61    edit-update fa
86d0: 6c 73 65 20 3b 0a 3a 20 63 68 61 74 2d 65 6e 74  lse ;.: chat-ent
86e0: 65 72 20 28 20 6d 61 78 20 73 70 61 6e 20 61 64  er ( max span ad
86f0: 64 72 20 70 6f 73 31 20 2d 2d 20 6d 61 78 20 73  dr pos1 -- max s
8700: 70 61 6e 20 61 64 64 72 20 70 6f 73 32 20 74 72  pan addr pos2 tr
8710: 75 65 20 29 0a 20 20 20 20 64 72 6f 70 20 6f 76  ue ).    drop ov
8720: 65 72 20 65 64 69 74 2d 75 70 64 61 74 65 20 74  er edit-update t
8730: 72 75 65 20 36 34 23 2d 31 20 6c 69 6e 65 2d 64  rue 64#-1 line-d
8740: 61 74 65 20 36 34 21 20 3b 0a 0a 65 64 69 74 2d  ate 64! ;..edit-
8750: 74 65 72 6d 69 6e 61 6c 2d 63 20 63 6c 61 73 73  terminal-c class
8760: 0a 65 6e 64 2d 63 6c 61 73 73 20 63 68 61 74 2d  .end-class chat-
8770: 74 65 72 6d 69 6e 61 6c 2d 63 0a 63 68 61 74 2d  terminal-c.chat-
8780: 74 65 72 6d 69 6e 61 6c 2d 63 20 27 20 6e 65 77  terminal-c ' new
8790: 20 73 74 61 74 69 63 2d 61 20 77 69 74 68 2d 61   static-a with-a
87a0: 6c 6c 6f 63 61 74 65 72 20 43 6f 6e 73 74 61 6e  llocater Constan
87b0: 74 20 63 68 61 74 2d 74 65 72 6d 69 6e 61 6c 0a  t chat-terminal.
87c0: 0a 62 6c 20 63 65 6c 6c 73 20 62 75 66 66 65 72  .bl cells buffer
87d0: 3a 20 63 68 61 74 2d 63 74 72 6c 6b 65 79 73 0a  : chat-ctrlkeys.
87e0: 78 63 68 61 72 2d 63 74 72 6c 6b 65 79 73 20 63  xchar-ctrlkeys c
87f0: 68 61 74 2d 63 74 72 6c 6b 65 79 73 20 62 6c 20  hat-ctrlkeys bl 
8800: 63 65 6c 6c 73 20 6d 6f 76 65 0a 0a 63 68 61 74  cells move..chat
8810: 2d 74 65 72 6d 69 6e 61 6c 20 65 64 69 74 2d 6f  -terminal edit-o
8820: 75 74 20 21 0a 0a 27 20 63 68 61 74 2d 63 74 72  ut !..' chat-ctr
8830: 6c 6b 65 79 73 20 69 73 20 63 74 72 6c 6b 65 79  lkeys is ctrlkey
8840: 73 0a 0a 27 20 63 68 61 74 2d 6e 65 78 74 2d 6c  s..' chat-next-l
8850: 69 6e 65 20 63 74 72 6c 20 4e 20 62 69 6e 64 6b  ine ctrl N bindk
8860: 65 79 0a 27 20 63 68 61 74 2d 70 72 65 76 2d 6c  ey.' chat-prev-l
8870: 69 6e 65 20 63 74 72 6c 20 50 20 62 69 6e 64 6b  ine ctrl P bindk
8880: 65 79 0a 27 20 63 68 61 74 2d 65 6e 74 65 72 20  ey.' chat-enter 
8890: 20 20 20 20 23 6c 66 20 20 20 20 62 69 6e 64 6b      #lf    bindk
88a0: 65 79 0a 27 20 63 68 61 74 2d 65 6e 74 65 72 20  ey.' chat-enter 
88b0: 20 20 20 20 23 63 72 20 20 20 20 62 69 6e 64 6b      #cr    bindk
88c0: 65 79 0a 5c 20 3a 6e 6f 6e 61 6d 65 20 23 74 61  ey.\ :noname #ta
88d0: 62 20 28 78 69 6e 73 29 20 30 20 3b 20 23 74 61  b (xins) 0 ; #ta
88e0: 62 20 20 20 62 69 6e 64 6b 65 79 0a 5b 49 46 44  b   bindkey.[IFD
88f0: 45 46 5d 20 65 62 69 6e 64 6b 65 79 0a 20 20 20  EF] ebindkey.   
8900: 20 6b 65 79 63 6f 64 65 2d 6c 69 6d 69 74 20 6b   keycode-limit k
8910: 65 79 63 6f 64 65 2d 73 74 61 72 74 20 2d 20 63  eycode-start - c
8920: 65 6c 6c 73 20 62 75 66 66 65 72 3a 20 63 68 61  ells buffer: cha
8930: 74 2d 65 6b 65 79 73 0a 20 20 20 20 73 74 64 2d  t-ekeys.    std-
8940: 65 6b 65 79 73 20 63 68 61 74 2d 65 6b 65 79 73  ekeys chat-ekeys
8950: 20 6b 65 79 63 6f 64 65 2d 6c 69 6d 69 74 20 6b   keycode-limit k
8960: 65 79 63 6f 64 65 2d 73 74 61 72 74 20 2d 20 63  eycode-start - c
8970: 65 6c 6c 73 20 6d 6f 76 65 0a 20 20 20 20 0a 20  ells move.    . 
8980: 20 20 20 27 20 63 68 61 74 2d 65 6b 65 79 73 20     ' chat-ekeys 
8990: 69 73 20 65 6b 65 79 73 0a 20 20 20 20 0a 20 20  is ekeys.    .  
89a0: 20 20 27 20 63 68 61 74 2d 6e 65 78 74 2d 6c 69    ' chat-next-li
89b0: 6e 65 20 6b 2d 64 6f 77 6e 20 20 65 62 69 6e 64  ne k-down  ebind
89c0: 6b 65 79 0a 20 20 20 20 27 20 63 68 61 74 2d 70  key.    ' chat-p
89d0: 72 65 76 2d 6c 69 6e 65 20 6b 2d 75 70 20 20 20  rev-line k-up   
89e0: 20 65 62 69 6e 64 6b 65 79 0a 20 20 20 20 27 20   ebindkey.    ' 
89f0: 63 68 61 74 2d 6e 65 78 74 2d 6c 69 6e 65 20 6b  chat-next-line k
8a00: 2d 6e 65 78 74 20 20 65 62 69 6e 64 6b 65 79 0a  -next  ebindkey.
8a10: 20 20 20 20 27 20 63 68 61 74 2d 70 72 65 76 2d      ' chat-prev-
8a20: 6c 69 6e 65 20 6b 2d 70 72 69 6f 72 20 65 62 69  line k-prior ebi
8a30: 6e 64 6b 65 79 0a 5b 54 48 45 4e 5d 0a 0a 65 64  ndkey.[THEN]..ed
8a40: 69 74 2d 74 65 72 6d 69 6e 61 6c 20 65 64 69 74  it-terminal edit
8a50: 2d 6f 75 74 20 21 0a 0a 3a 20 63 68 61 74 2d 68  -out !..: chat-h
8a60: 69 73 74 6f 72 79 20 28 20 2d 2d 20 29 0a 20 20  istory ( -- ).  
8a70: 20 20 63 68 61 74 2d 74 65 72 6d 69 6e 61 6c 20    chat-terminal 
8a80: 65 64 69 74 2d 6f 75 74 20 21 20 3b 0a 0a 5c 20  edit-out ! ;..\ 
8a90: 63 68 61 74 20 6c 69 6e 65 20 65 64 69 74 6f 72  chat line editor
8aa0: 0a 0a 24 32 30 30 20 43 6f 6e 73 74 61 6e 74 20  ..$200 Constant 
8ab0: 6d 61 78 6d 73 67 23 0a 0a 3a 20 67 65 74 2d 69  maxmsg#..: get-i
8ac0: 6e 70 75 74 2d 6c 69 6e 65 20 28 20 2d 2d 20 61  nput-line ( -- a
8ad0: 64 64 72 20 75 20 29 0a 20 20 20 20 42 45 47 49  ddr u ).    BEGI
8ae0: 4e 20 20 70 61 64 20 6d 61 78 6d 73 67 23 20 5b  N  pad maxmsg# [
8af0: 27 5d 20 61 63 63 65 70 74 20 63 61 74 63 68 0a  '] accept catch.
8b00: 09 64 75 70 20 64 75 70 20 2d 35 36 20 3d 20 73  .dup dup -56 = s
8b10: 77 61 70 20 2d 32 38 20 3d 20 6f 72 20 5c 20 71  wap -28 = or \ q
8b20: 75 69 74 20 6f 72 20 5e 63 20 74 6f 20 6c 65 61  uit or ^c to lea
8b30: 76 65 0a 09 49 46 20 20 20 20 64 72 6f 70 20 32  ve..IF    drop 2
8b40: 64 72 6f 70 20 22 2f 62 79 65 22 0a 09 45 4c 53  drop "/bye"..ELS
8b50: 45 0a 09 20 20 20 20 64 75 70 20 30 3d 20 49 46  E..    dup 0= IF
8b60: 0a 09 09 64 72 6f 70 20 70 61 64 20 73 77 61 70  ...drop pad swap
8b70: 20 32 64 75 70 20 78 63 6c 65 61 72 0a 09 20 20   2dup xclear..  
8b80: 20 20 45 4c 53 45 0a 09 09 44 6f 45 72 72 6f 72    ELSE...DoError
8b90: 20 64 72 6f 70 20 30 20 20 54 48 45 4e 0a 09 54   drop 0  THEN..T
8ba0: 48 45 4e 0a 09 64 75 70 20 30 3d 20 57 48 49 4c  HEN..dup 0= WHIL
8bb0: 45 20 20 32 64 72 6f 70 20 20 52 45 50 45 41 54  E  2drop  REPEAT
8bc0: 20 3b 0a 0a 5c 20 6a 6f 69 6e 69 6e 67 20 61 6e   ;..\ joining an
8bd0: 64 20 6c 65 61 76 69 6e 67 0a 0a 3a 20 67 3f 6a  d leaving..: g?j
8be0: 6f 69 6e 20 28 20 2d 2d 20 29 0a 20 20 20 20 6d  oin ( -- ).    m
8bf0: 73 67 2d 67 72 6f 75 70 24 20 24 40 6c 65 6e 20  sg-group$ $@len 
8c00: 49 46 20 20 73 65 6e 64 2d 6a 6f 69 6e 20 2d 74  IF  send-join -t
8c10: 69 6d 65 6f 75 74 20 20 54 48 45 4e 20 3b 0a 0a  imeout  THEN ;..
8c20: 3a 20 67 3f 6c 65 61 76 65 20 28 20 2d 2d 20 29  : g?leave ( -- )
8c30: 0a 20 20 20 20 6d 73 67 2d 67 72 6f 75 70 24 20  .    msg-group$ 
8c40: 24 40 6c 65 6e 20 49 46 20 20 73 65 6e 64 2d 6c  $@len IF  send-l
8c50: 65 61 76 65 20 2d 74 69 6d 65 6f 75 74 20 20 54  eave -timeout  T
8c60: 48 45 4e 20 3b 0a 0a 3a 20 67 72 65 65 74 20 28  HEN ;..: greet (
8c70: 20 2d 2d 20 29 0a 20 20 20 20 63 6f 6e 6e 65 63   -- ).    connec
8c80: 74 69 6f 6e 20 2e 64 61 74 61 2d 72 6d 61 70 20  tion .data-rmap 
8c90: 30 3d 20 3f 45 58 49 54 0a 20 20 20 20 6e 65 74  0= ?EXIT.    net
8ca0: 32 6f 2d 63 6f 64 65 20 65 78 70 65 63 74 2d 6d  2o-code expect-m
8cb0: 73 67 0a 20 20 20 20 6c 6f 67 20 21 74 69 6d 65  sg.    log !time
8cc0: 20 65 6e 64 2d 77 69 74 68 20 6a 6f 69 6e 2c 20   end-with join, 
8cd0: 67 65 74 2d 69 70 20 65 6e 64 2d 63 6f 64 65 20  get-ip end-code 
8ce0: 3b 0a 0a 3a 20 63 68 61 74 2d 65 6e 74 72 79 20  ;..: chat-entry 
8cf0: 28 20 2d 2d 20 29 20 20 3f 2e 6e 65 74 32 6f 2f  ( -- )  ?.net2o/
8d00: 63 68 61 74 73 20 20 77 6f 72 64 2d 61 72 67 73  chats  word-args
8d10: 0a 20 20 20 20 3c 77 61 72 6e 3e 20 2e 22 20 54  .    <warn> ." T
8d20: 79 70 65 20 63 74 72 6c 2d 44 20 6f 72 20 27 2f  ype ctrl-D or '/
8d30: 62 79 65 27 20 61 73 20 73 69 6e 67 6c 65 20 69  bye' as single i
8d40: 74 65 6d 20 74 6f 20 71 75 69 74 22 20 3c 64 65  tem to quit" <de
8d50: 66 61 75 6c 74 3e 20 63 72 20 3b 0a 0a 61 6c 73  fault> cr ;..als
8d60: 6f 20 6e 65 74 32 6f 2d 62 61 73 65 0a 5c 20 63  o net2o-base.\ c
8d70: 68 61 69 6e 20 6d 65 73 73 61 67 65 73 20 74 6f  hain messages to
8d80: 20 6f 6e 65 20 70 72 65 76 69 6f 75 73 20 6d 65   one previous me
8d90: 73 73 61 67 65 0a 3a 20 63 68 61 69 6e 2c 20 28  ssage.: chain, (
8da0: 20 6d 73 67 61 64 64 72 20 75 20 2d 2d 20 29 0a   msgaddr u -- ).
8db0: 20 20 20 20 5b 3a 20 32 64 75 70 20 73 74 61 72      [: 2dup star
8dc0: 74 64 61 74 65 40 20 36 34 23 30 20 7b 20 36 34  tdate@ 64#0 { 64
8dd0: 5e 20 73 64 20 7d 20 73 64 20 6c 65 2d 36 34 21  ^ sd } sd le-64!
8de0: 20 20 73 64 20 31 20 36 34 73 20 66 6f 72 74 68    sd 1 64s forth
8df0: 3a 74 79 70 65 0a 09 63 3a 30 6b 65 79 20 73 69  :type..c:0key si
8e00: 67 6f 6e 6c 79 40 20 3e 68 61 73 68 20 68 61 73  gonly@ >hash has
8e10: 68 74 6d 70 20 68 61 73 68 23 31 32 38 20 66 6f  htmp hash#128 fo
8e20: 72 74 68 3a 74 79 70 65 20 3b 5d 20 24 74 6d 70  rth:type ;] $tmp
8e30: 20 24 2c 20 6d 73 67 2d 63 68 61 69 6e 20 3b 0a   $, msg-chain ;.
8e40: 0a 3a 20 28 73 65 6e 64 2d 61 76 61 6c 61 6e 63  .: (send-avalanc
8e50: 68 65 29 20 28 20 78 74 20 2d 2d 20 61 64 64 72  he) ( xt -- addr
8e60: 20 75 20 66 6c 61 67 20 29 0a 20 20 20 20 5b 3a   u flag ).    [:
8e70: 20 30 20 3e 6f 20 5b 3a 20 3c 6d 73 67 20 6d 73   0 >o [: <msg ms
8e80: 67 2d 73 74 61 72 74 20 65 78 65 63 75 74 65 20  g-start execute 
8e90: 6d 73 67 3e 20 3b 5d 20 67 65 6e 2d 63 6d 64 24  msg> ;] gen-cmd$
8ea0: 20 6f 3e 0a 20 20 20 20 20 20 2b 6c 61 73 74 2d   o>.      +last-
8eb0: 73 69 67 6e 65 64 20 6d 73 67 2d 6c 6f 67 2c 20  signed msg-log, 
8ec0: 3b 5d 20 5b 67 72 6f 75 70 5d 20 3b 0a 70 72 65  ;] [group] ;.pre
8ed0: 76 69 6f 75 73 0a 3a 20 73 65 6e 64 2d 61 76 61  vious.: send-ava
8ee0: 6c 61 6e 63 68 65 20 28 20 78 74 20 2d 2d 20 29  lanche ( xt -- )
8ef0: 0a 20 20 20 20 6d 73 67 2d 67 72 6f 75 70 2d 6f  .    msg-group-o
8f00: 20 2e 6d 73 67 3a 3f 6f 74 72 20 49 46 20 20 6e   .msg:?otr IF  n
8f10: 6f 77 3e 6f 74 72 20 20 45 4c 53 45 20 20 6e 6f  ow>otr  ELSE  no
8f20: 77 3e 6e 65 76 65 72 20 20 54 48 45 4e 0a 20 20  w>never  THEN.  
8f30: 20 20 28 73 65 6e 64 2d 61 76 61 6c 61 6e 63 68    (send-avalanch
8f40: 65 29 0a 20 20 20 20 3e 72 20 2e 63 68 61 74 20  e).    >r .chat 
8f50: 72 3e 20 30 3d 20 49 46 20 20 6d 73 67 2d 67 72  r> 0= IF  msg-gr
8f60: 6f 75 70 2d 6f 20 2e 6d 73 67 3a 2e 6e 6f 62 6f  oup-o .msg:.nobo
8f70: 64 79 20 20 54 48 45 4e 20 3b 0a 0a 5c 20 63 68  dy  THEN ;..\ ch
8f80: 61 74 20 68 65 6c 70 65 72 20 77 6f 72 64 73 0a  at helper words.
8f90: 0a 56 61 72 69 61 62 6c 65 20 63 68 61 74 2d 6b  .Variable chat-k
8fa0: 65 79 73 0a 0a 3a 20 40 2f 20 28 20 61 64 64 72  eys..: @/ ( addr
8fb0: 20 75 20 2d 2d 20 61 64 64 72 31 20 75 31 20 61   u -- addr1 u1 a
8fc0: 64 64 72 32 20 75 32 20 29 20 27 40 27 20 24 73  ddr2 u2 ) '@' $s
8fd0: 70 6c 69 74 20 3b 0a 3a 20 40 2f 32 20 28 20 61  plit ;.: @/2 ( a
8fe0: 64 64 72 20 75 20 2d 2d 20 61 64 64 72 32 20 75  ddr u -- addr2 u
8ff0: 32 20 29 20 27 40 27 20 24 73 70 6c 69 74 20 32  2 ) '@' $split 2
9000: 6e 69 70 20 3b 0a 0a 3a 20 40 6e 69 63 6b 3e 63  nip ;..: @nick>c
9010: 68 61 74 20 28 20 61 64 64 72 20 75 20 2d 2d 20  hat ( addr u -- 
9020: 29 0a 20 20 20 20 68 6f 73 74 2e 6e 69 63 6b 3e  ).    host.nick>
9030: 70 6b 20 64 75 70 20 30 3d 20 21 21 6e 6f 2d 6e  pk dup 0= !!no-n
9040: 69 63 6b 21 21 20 63 68 61 74 2d 6b 65 79 73 20  ick!! chat-keys 
9050: 24 2b 5b 5d 21 20 3b 0a 0a 3a 20 40 6e 69 63 6b  $+[]! ;..: @nick
9060: 73 3e 63 68 61 74 20 28 20 2d 2d 20 29 0a 20 20  s>chat ( -- ).  
9070: 20 20 5b 27 5d 20 40 6e 69 63 6b 3e 63 68 61 74    ['] @nick>chat
9080: 20 40 61 72 67 2d 6c 6f 6f 70 20 3b 0a 0a 3a 20   @arg-loop ;..: 
9090: 6e 69 63 6b 3e 63 68 61 74 20 28 20 61 64 64 72  nick>chat ( addr
90a0: 20 75 20 2d 2d 20 29 0a 20 20 20 20 40 2f 20 64   u -- ).    @/ d
90b0: 75 70 20 49 46 0a 09 68 6f 73 74 2e 6e 69 63 6b  up IF..host.nick
90c0: 3e 70 6b 20 64 75 70 20 30 3d 20 21 21 6e 6f 2d  >pk dup 0= !!no-
90d0: 6e 69 63 6b 21 21 0a 09 5b 3a 20 32 73 77 61 70  nick!!..[: 2swap
90e0: 20 74 79 70 65 20 2e 22 20 40 22 20 74 79 70 65   type ." @" type
90f0: 20 3b 5d 20 24 74 6d 70 0a 20 20 20 20 45 4c 53   ;] $tmp.    ELS
9100: 45 20 20 32 64 72 6f 70 20 20 54 48 45 4e 0a 20  E  2drop  THEN. 
9110: 20 20 20 63 68 61 74 2d 6b 65 79 73 20 24 2b 5b     chat-keys $+[
9120: 5d 21 20 3b 0a 0a 3a 20 6e 69 63 6b 73 3e 63 68  ]! ;..: nicks>ch
9130: 61 74 20 28 20 2d 2d 20 29 0a 20 20 20 20 5b 27  at ( -- ).    ['
9140: 5d 20 6e 69 63 6b 3e 63 68 61 74 20 61 72 67 2d  ] nick>chat arg-
9150: 6c 6f 6f 70 20 3b 0a 0a 5c 20 64 6f 20 6f 74 72  loop ;..\ do otr
9160: 69 66 79 0a 0a 61 6c 73 6f 20 6e 65 74 32 6f 2d  ify..also net2o-
9170: 62 61 73 65 0a 0a 3a 20 64 6f 2d 6f 74 72 69 66  base..: do-otrif
9180: 79 20 28 20 6e 20 2d 2d 20 29 20 3e 72 0a 20 20  y ( n -- ) >r.  
9190: 20 20 6d 73 67 2d 67 72 6f 75 70 24 20 24 40 20    msg-group$ $@ 
91a0: 3e 67 72 6f 75 70 20 6d 73 67 2d 67 72 6f 75 70  >group msg-group
91b0: 2d 6f 20 2e 6d 73 67 3a 6c 6f 67 5b 5d 20 24 40  -o .msg:log[] $@
91c0: 0a 20 20 20 20 72 3e 20 63 65 6c 6c 73 20 64 75  .    r> cells du
91d0: 70 20 30 3c 20 49 46 20 20 6f 76 65 72 20 2b 20  p 0< IF  over + 
91e0: 30 20 6d 61 78 20 20 54 48 45 4e 20 73 61 66 65  0 max  THEN safe
91f0: 2f 73 74 72 69 6e 67 0a 20 20 20 20 49 46 20 20  /string.    IF  
9200: 24 40 0a 09 32 64 75 70 20 2b 20 32 20 2d 20 63  $@..2dup + 2 - c
9210: 40 20 24 38 30 20 61 6e 64 20 64 75 70 20 3e 72  @ $80 and dup >r
9220: 0a 09 49 46 20 20 6d 73 67 2d 64 65 63 2d 73 69  ..IF  msg-dec-si
9230: 67 3f 20 20 45 4c 53 45 20 20 70 6b 2d 73 69 67  g?  ELSE  pk-sig
9240: 3f 20 20 54 48 45 4e 20 20 21 21 73 69 67 21 21  ?  THEN  !!sig!!
9250: 0a 09 32 64 75 70 20 2b 20 73 69 67 70 6b 73 69  ..2dup + sigpksi
9260: 7a 65 23 20 2d 20 73 69 67 70 6b 73 69 7a 65 23  ze# - sigpksize#
9270: 0a 09 6f 76 65 72 20 6b 65 79 73 69 7a 65 20 70  ..over keysize p
9280: 6b 40 20 6b 65 79 7c 20 73 74 72 3d 20 49 46 0a  k@ key| str= IF.
9290: 09 20 20 20 20 6b 65 79 73 69 7a 65 20 2f 73 74  .    keysize /st
92a0: 72 69 6e 67 20 24 2c 0a 09 20 20 20 20 72 3e 20  ring $,..    r> 
92b0: 6e 65 77 2d 6f 74 72 73 69 67 20 24 2c 0a 09 20  new-otrsig $,.. 
92c0: 20 20 20 6d 73 67 2d 6f 74 72 69 66 79 0a 09 45     msg-otrify..E
92d0: 4c 53 45 0a 09 20 20 20 20 72 64 72 6f 70 20 32  LSE..    rdrop 2
92e0: 64 72 6f 70 20 32 64 72 6f 70 20 2e 22 20 6e 6f  drop 2drop ." no
92f0: 74 20 79 6f 75 72 20 6d 65 73 73 61 67 65 21 22  t your message!"
9300: 20 66 6f 72 74 68 3a 63 72 0a 09 54 48 45 4e 0a   forth:cr..THEN.
9310: 20 20 20 20 45 4c 53 45 20 20 64 72 6f 70 20 20      ELSE  drop  
9320: 54 48 45 4e 20 3b 0a 0a 70 72 65 76 69 6f 75 73  THEN ;..previous
9330: 0a 0a 5c 20 64 65 62 75 67 67 69 6e 67 20 61 69  ..\ debugging ai
9340: 64 73 20 66 6f 72 20 63 6c 61 73 73 65 73 0a 0a  ds for classes..
9350: 3a 20 2e 61 63 6b 20 28 20 6f 3a 61 63 6b 20 2d  : .ack ( o:ack -
9360: 2d 20 6f 3a 61 63 6b 20 29 0a 20 20 20 20 2e 22  - o:ack ).    ."
9370: 20 61 63 6b 20 63 6f 6e 74 65 78 74 3a 22 20 63   ack context:" c
9380: 72 0a 20 20 20 20 2e 22 20 72 74 64 65 6c 61 79  r.    ." rtdelay
9390: 3a 20 22 20 72 74 64 65 6c 61 79 20 36 34 40 20  : " rtdelay 64@ 
93a0: 73 36 34 2e 20 63 72 20 3b 0a 0a 3a 20 2e 63 6f  s64. cr ;..: .co
93b0: 6e 74 65 78 74 20 28 20 6f 3a 63 6f 6e 74 65 78  ntext ( o:contex
93c0: 74 20 2d 2d 20 6f 3a 63 6f 6e 74 65 78 74 20 29  t -- o:context )
93d0: 0a 20 20 20 20 2e 22 20 43 6f 6e 6e 65 63 74 65  .    ." Connecte
93e0: 64 20 77 69 74 68 3a 20 22 20 2e 63 6f 6e 2d 69  d with: " .con-i
93f0: 64 20 63 72 0a 20 20 20 20 61 63 6b 2d 63 6f 6e  d cr.    ack-con
9400: 74 65 78 74 20 40 20 3f 64 75 70 2d 49 46 20 20  text @ ?dup-IF  
9410: 2e 2e 61 63 6b 20 20 54 48 45 4e 20 3b 0a 0a 3a  ..ack  THEN ;..:
9420: 20 2e 6e 6f 74 69 66 79 20 28 20 2d 2d 20 29 0a   .notify ( -- ).
9430: 20 20 20 20 2e 22 20 6e 6f 74 69 66 79 20 22 20      ." notify " 
9440: 63 6f 6e 66 69 67 3a 6e 6f 74 69 66 79 3f 23 20  config:notify?# 
9450: 3f 0a 20 20 20 20 2e 22 20 6c 65 64 20 22 20 63  ?.    ." led " c
9460: 6f 6e 66 69 67 3a 6e 6f 74 69 66 79 2d 72 67 62  onfig:notify-rgb
9470: 23 20 40 20 68 65 78 2e 20 63 6f 6e 66 69 67 3a  # @ hex. config:
9480: 6e 6f 74 69 66 79 2d 6f 6e 23 20 3f 20 63 6f 6e  notify-on# ? con
9490: 66 69 67 3a 6e 6f 74 69 66 79 2d 6f 66 66 23 20  fig:notify-off# 
94a0: 3f 0a 20 20 20 20 2e 22 20 69 6e 74 65 72 76 61  ?.    ." interva
94b0: 6c 20 22 20 63 6f 6e 66 69 67 3a 64 65 6c 74 61  l " config:delta
94c0: 2d 6e 6f 74 69 66 79 26 20 32 40 20 31 30 30 30  -notify& 2@ 1000
94d0: 30 30 30 20 75 6d 2f 6d 6f 64 20 2e 20 64 72 6f  000 um/mod . dro
94e0: 70 0a 20 20 20 20 2e 22 20 6d 6f 64 65 20 22 20  p.    ." mode " 
94f0: 63 6f 6e 66 69 67 3a 6e 6f 74 69 66 79 2d 6d 6f  config:notify-mo
9500: 64 65 23 20 40 20 2e 0a 20 20 20 20 63 6f 6e 66  de# @ ..    conf
9510: 69 67 3a 6e 6f 74 69 66 79 2d 74 65 78 74 23 20  ig:notify-text# 
9520: 40 0a 20 20 20 20 63 61 73 65 0a 09 2d 31 20 6f  @.    case..-1 o
9530: 66 20 20 2e 22 20 76 69 73 69 62 6c 65 22 20 20  f  ." visible"  
9540: 65 6e 64 6f 66 0a 09 30 20 6f 66 20 20 2e 22 20  endof..0 of  ." 
9550: 68 69 64 64 65 6e 22 20 20 65 6e 64 6f 66 0a 09  hidden"  endof..
9560: 31 20 6f 66 20 20 2e 22 20 68 69 64 65 2d 6f 74  1 of  ." hide-ot
9570: 72 22 20 20 65 6e 64 6f 66 0a 20 20 20 20 65 6e  r"  endof.    en
9580: 64 63 61 73 65 0a 20 20 20 20 66 6f 72 74 68 3a  dcase.    forth:
9590: 63 72 20 3b 0a 0a 3a 20 67 65 74 2d 68 65 78 20  cr ;..: get-hex 
95a0: 28 20 2d 2d 20 6e 20 29 0a 20 20 20 20 70 61 72  ( -- n ).    par
95b0: 73 65 2d 6e 61 6d 65 20 27 24 27 20 73 6b 69 70  se-name '$' skip
95c0: 20 23 30 2e 20 32 73 77 61 70 20 5b 27 5d 20 3e   #0. 2swap ['] >
95d0: 6e 75 6d 62 65 72 20 24 31 30 20 62 61 73 65 2d  number $10 base-
95e0: 65 78 65 63 75 74 65 20 32 73 77 61 70 20 64 72  execute 2swap dr
95f0: 6f 70 20 3b 0a 3a 20 67 65 74 2d 64 65 63 20 28  op ;.: get-dec (
9600: 20 2d 2d 20 6e 20 29 0a 20 20 20 20 70 61 72 73   -- n ).    pars
9610: 65 2d 6e 61 6d 65 20 27 23 27 20 73 6b 69 70 20  e-name '#' skip 
9620: 23 30 2e 20 32 73 77 61 70 20 5b 27 5d 20 3e 6e  #0. 2swap ['] >n
9630: 75 6d 62 65 72 20 23 31 30 20 62 61 73 65 2d 65  umber #10 base-e
9640: 78 65 63 75 74 65 20 32 73 77 61 70 20 64 72 6f  xecute 2swap dro
9650: 70 20 3b 0a 0a 73 63 6f 70 65 3a 20 6e 6f 74 69  p ;..scope: noti
9660: 66 79 2d 63 6d 64 73 0a 0a 3a 20 6f 6e 20 28 20  fy-cmds..: on ( 
9670: 2d 2d 20 29 20 2d 32 20 63 6f 6e 66 69 67 3a 6e  -- ) -2 config:n
9680: 6f 74 69 66 79 3f 23 20 21 20 3b 0a 3a 20 61 6c  otify?# ! ;.: al
9690: 77 61 79 73 20 28 20 2d 2d 20 29 20 2d 33 20 63  ways ( -- ) -3 c
96a0: 6f 6e 66 69 67 3a 6e 6f 74 69 66 79 3f 23 20 21  onfig:notify?# !
96b0: 20 3b 0a 3a 20 6f 66 66 20 28 20 2d 2d 20 29 20   ;.: off ( -- ) 
96c0: 30 20 63 6f 6e 66 69 67 3a 6e 6f 74 69 66 79 3f  0 config:notify?
96d0: 23 20 21 20 3b 0a 3a 20 6c 65 64 20 28 20 2d 2d  # ! ;.: led ( --
96e0: 20 29 20 5c 20 22 3c 72 72 67 67 62 62 3e 20 3c   ) \ "<rrggbb> <
96f0: 6f 6e 2d 6d 73 3e 20 3c 6f 66 66 2d 6d 73 3e 22  on-ms> <off-ms>"
9700: 0a 20 20 20 20 67 65 74 2d 68 65 78 20 63 6f 6e  .    get-hex con
9710: 66 69 67 3a 6e 6f 74 69 66 79 2d 72 67 62 23 20  fig:notify-rgb# 
9720: 21 0a 20 20 20 20 67 65 74 2d 64 65 63 20 23 35  !.    get-dec #5
9730: 30 30 20 6d 61 78 20 63 6f 6e 66 69 67 3a 6e 6f  00 max config:no
9740: 74 69 66 79 2d 6f 6e 23 20 21 0a 20 20 20 20 67  tify-on# !.    g
9750: 65 74 2d 64 65 63 20 23 35 30 30 20 6d 61 78 20  et-dec #500 max 
9760: 63 6f 6e 66 69 67 3a 6e 6f 74 69 66 79 2d 6f 66  config:notify-of
9770: 66 23 20 21 0a 20 20 20 20 6d 73 67 2d 62 75 69  f# !.    msg-bui
9780: 6c 64 65 72 20 3b 0a 3a 20 69 6e 74 65 72 76 61  lder ;.: interva
9790: 6c 20 28 20 2d 2d 20 29 20 70 61 72 73 65 2d 6e  l ( -- ) parse-n
97a0: 61 6d 65 0a 20 20 20 20 23 30 2e 20 32 73 77 61  ame.    #0. 2swa
97b0: 70 20 5b 27 5d 20 3e 6e 75 6d 62 65 72 20 23 31  p ['] >number #1
97c0: 30 20 62 61 73 65 2d 65 78 65 63 75 74 65 20 31  0 base-execute 1
97d0: 20 3d 20 49 46 20 20 6e 69 70 20 63 40 20 63 61   = IF  nip c@ ca
97e0: 73 65 0a 09 20 20 20 20 27 73 27 20 6f 66 20 20  se..    's' of  
97f0: 20 20 20 23 31 30 30 30 20 2a 20 65 6e 64 6f 66     #1000 * endof
9800: 0a 09 20 20 20 20 27 6d 27 20 6f 66 20 20 20 20  ..    'm' of    
9810: 23 36 30 30 30 30 20 2a 20 65 6e 64 6f 66 0a 09  #60000 * endof..
9820: 20 20 20 20 27 68 27 20 6f 66 20 23 33 36 30 30      'h' of #3600
9830: 30 30 30 30 20 2a 20 65 6e 64 6f 66 0a 09 65 6e  0000 * endof..en
9840: 64 63 61 73 65 0a 20 20 20 20 45 4c 53 45 20 20  dcase.    ELSE  
9850: 32 64 72 6f 70 20 20 54 48 45 4e 20 20 23 31 30  2drop  THEN  #10
9860: 30 30 30 30 30 20 75 6d 2a 20 63 6f 6e 66 69 67  00000 um* config
9870: 3a 64 65 6c 74 61 2d 6e 6f 74 69 66 79 26 20 32  :delta-notify& 2
9880: 21 20 3b 0a 3a 20 6d 6f 64 65 20 28 20 2d 2d 20  ! ;.: mode ( -- 
9890: 29 0a 20 20 20 20 67 65 74 2d 64 65 63 20 33 20  ).    get-dec 3 
98a0: 61 6e 64 20 63 6f 6e 66 69 67 3a 6e 6f 74 69 66  and config:notif
98b0: 79 2d 6d 6f 64 65 23 20 21 20 6d 73 67 2d 62 75  y-mode# ! msg-bu
98c0: 69 6c 64 65 72 20 3b 0a 3a 20 76 69 73 69 62 6c  ilder ;.: visibl
98d0: 65 20 28 20 2d 2d 20 29 0a 20 20 20 20 63 6f 6e  e ( -- ).    con
98e0: 66 69 67 3a 6e 6f 74 69 66 79 2d 74 65 78 74 23  fig:notify-text#
98f0: 20 66 6f 72 74 68 3a 6f 6e 20 3b 0a 3a 20 68 69   forth:on ;.: hi
9900: 64 64 65 6e 20 28 20 2d 2d 20 29 0a 20 20 20 20  dden ( -- ).    
9910: 63 6f 6e 66 69 67 3a 6e 6f 74 69 66 79 2d 74 65  config:notify-te
9920: 78 74 23 20 66 6f 72 74 68 3a 6f 66 66 20 3b 0a  xt# forth:off ;.
9930: 3a 20 68 69 64 65 2d 6f 74 72 20 28 20 2d 2d 20  : hide-otr ( -- 
9940: 29 0a 20 20 20 20 31 20 63 6f 6e 66 69 67 3a 6e  ).    1 config:n
9950: 6f 74 69 66 79 2d 74 65 78 74 23 20 21 20 3b 0a  otify-text# ! ;.
9960: 0a 7d 73 63 6f 70 65 0a 0a 3a 20 2e 63 68 61 74  .}scope..: .chat
9970: 68 65 6c 70 20 28 20 61 64 64 72 20 75 20 2d 2d  help ( addr u --
9980: 20 61 64 64 72 20 75 20 29 0a 20 20 20 20 2e 22   addr u ).    ."
9990: 20 2f 22 20 73 6f 75 72 63 65 20 37 20 2f 73 74   /" source 7 /st
99a0: 72 69 6e 67 20 74 79 70 65 20 63 72 20 3b 0a 0a  ring type cr ;..
99b0: 3a 20 2e 6e 32 6f 2d 76 65 72 73 69 6f 6e 20 28  : .n2o-version (
99c0: 20 2d 2d 20 29 0a 20 20 20 20 2e 22 20 6e 32 6f   -- ).    ." n2o
99d0: 2d 22 20 6e 65 74 32 6f 2d 76 65 72 73 69 6f 6e  -" net2o-version
99e0: 20 66 6f 72 74 68 3a 74 79 70 65 20 3b 0a 3a 20   forth:type ;.: 
99f0: 2e 67 66 6f 72 74 68 2d 76 65 72 73 69 6f 6e 20  .gforth-version 
9a00: 28 20 2d 2d 20 29 0a 20 20 20 20 2e 22 20 67 66  ( -- ).    ." gf
9a10: 6f 72 74 68 2d 22 0a 20 20 20 20 63 61 73 65 20  orth-".    case 
9a20: 74 68 72 65 61 64 69 6e 67 2d 6d 65 74 68 6f 64  threading-method
9a30: 0a 09 30 20 6f 66 20 64 65 62 75 67 67 69 6e 67  ..0 of debugging
9a40: 2d 6d 65 74 68 6f 64 20 30 3d 20 49 46 20 2e 22  -method 0= IF ."
9a50: 20 66 61 73 74 2d 22 20 20 54 48 45 4e 20 20 65   fast-"  THEN  e
9a60: 6e 64 6f 66 0a 09 31 20 6f 66 20 2e 22 20 69 74  ndof..1 of ." it
9a70: 63 2d 22 20 65 6e 64 6f 66 0a 09 32 20 6f 66 20  c-" endof..2 of 
9a80: 2e 22 20 64 69 74 63 2d 22 20 65 6e 64 6f 66 0a  ." ditc-" endof.
9a90: 20 20 20 20 65 6e 64 63 61 73 65 0a 20 20 20 20      endcase.    
9aa0: 76 65 72 73 69 6f 6e 2d 73 74 72 69 6e 67 20 66  version-string f
9ab0: 6f 72 74 68 3a 74 79 70 65 20 27 2d 27 20 66 6f  orth:type '-' fo
9ac0: 72 74 68 3a 65 6d 69 74 0a 20 20 20 20 6d 61 63  rth:emit.    mac
9ad0: 68 69 6e 65 20 66 6f 72 74 68 3a 74 79 70 65 20  hine forth:type 
9ae0: 3b 0a 0a 66 6f 72 77 61 72 64 20 61 76 61 6c 61  ;..forward avala
9af0: 6e 63 68 65 2d 74 65 78 74 0a 0a 66 61 6c 73 65  nche-text..false
9b00: 20 76 61 6c 75 65 20 61 77 61 79 3f 0a 0a 3a 20   value away?..: 
9b10: 67 72 6f 75 70 23 6d 61 70 20 28 20 78 74 20 2d  group#map ( xt -
9b20: 2d 20 29 0a 20 20 20 20 6d 73 67 2d 67 72 6f 75  - ).    msg-grou
9b30: 70 23 20 73 77 61 70 20 5b 7b 3a 20 78 74 3a 20  p# swap [{: xt: 
9b40: 78 74 20 3a 7d 6c 20 63 65 6c 6c 2b 20 24 40 20  xt :}l cell+ $@ 
9b50: 64 72 6f 70 20 63 65 6c 6c 2b 20 2e 78 74 20 3b  drop cell+ .xt ;
9b60: 5d 20 23 6d 61 70 20 3b 0a 0a 75 76 61 6c 2d 6f  ] #map ;..uval-o
9b70: 20 63 68 61 74 2d 63 6d 64 2d 6f 0a 0a 6f 62 6a   chat-cmd-o..obj
9b80: 65 63 74 20 75 63 6c 61 73 73 20 63 68 61 74 2d  ect uclass chat-
9b90: 63 6d 64 2d 6f 0a 61 6c 73 6f 20 6e 65 74 32 6f  cmd-o.also net2o
9ba0: 2d 62 61 73 65 20 73 63 6f 70 65 3a 20 2f 63 68  -base scope: /ch
9bb0: 61 74 0a 75 6d 65 74 68 6f 64 20 2f 6d 65 20 28  at.umethod /me (
9bc0: 20 61 64 64 72 20 75 20 2d 2d 20 29 0a 20 20 20   addr u -- ).   
9bd0: 20 5c 55 20 6d 65 20 3c 61 63 74 69 6f 6e 3e 20   \U me <action> 
9be0: 20 20 20 20 20 20 20 20 20 73 65 6e 64 20 73 74           send st
9bf0: 72 69 6e 67 20 61 73 20 61 63 74 69 6f 6e 0a 20  ring as action. 
9c00: 20 20 20 5c 47 20 6d 65 3a 20 73 65 6e 64 20 72     \G me: send r
9c10: 65 6d 61 69 6e 69 6e 67 20 73 74 72 69 6e 67 20  emaining string 
9c20: 61 73 20 61 63 74 69 6f 6e 0a 75 6d 65 74 68 6f  as action.umetho
9c30: 64 20 2f 61 77 61 79 20 28 20 61 64 64 72 20 75  d /away ( addr u
9c40: 20 2d 2d 20 29 0a 20 20 20 20 5c 55 20 61 77 61   -- ).    \U awa
9c50: 79 20 5b 3c 61 63 74 69 6f 6e 3e 5d 20 20 20 20  y [<action>]    
9c60: 20 20 73 65 6e 64 20 73 74 72 69 6e 67 20 6f 72    send string or
9c70: 20 22 61 77 61 79 20 66 72 6f 6d 20 6b 65 79 62   "away from keyb
9c80: 6f 61 72 64 22 20 61 73 20 61 63 74 69 6f 6e 0a  oard" as action.
9c90: 20 20 20 20 5c 47 20 61 77 61 79 3a 20 73 65 6e      \G away: sen
9ca0: 64 20 73 74 72 69 6e 67 20 6f 72 20 22 61 77 61  d string or "awa
9cb0: 79 20 66 72 6f 6d 20 6b 65 79 62 6f 61 72 64 22  y from keyboard"
9cc0: 20 61 73 20 61 63 74 69 6f 6e 0a 73 79 6e 6f 6e   as action.synon
9cd0: 79 6d 20 2f 62 61 63 6b 20 2f 61 77 61 79 0a 75  ym /back /away.u
9ce0: 6d 65 74 68 6f 64 20 2f 6f 74 72 20 28 20 61 64  method /otr ( ad
9cf0: 64 72 20 75 20 2d 2d 20 29 0a 20 20 20 20 5c 55  dr u -- ).    \U
9d00: 20 6f 74 72 20 6f 6e 7c 6f 66 66 7c 6d 65 73 73   otr on|off|mess
9d10: 61 67 65 20 20 20 74 75 72 6e 20 6f 74 72 20 6d  age   turn otr m
9d20: 6f 64 65 20 6f 6e 2f 6f 66 66 20 28 6f 72 20 6f  ode on/off (or o
9d30: 6e 65 2d 73 68 6f 74 29 0a 75 6d 65 74 68 6f 64  ne-shot).umethod
9d40: 20 2f 70 65 65 72 73 20 28 20 61 64 64 72 20 75   /peers ( addr u
9d50: 20 2d 2d 20 29 0a 20 20 20 20 5c 55 20 70 65 65   -- ).    \U pee
9d60: 72 73 20 20 20 20 20 20 20 20 20 20 20 20 20 20  rs              
9d70: 20 20 6c 69 73 74 20 70 65 65 72 73 0a 20 20 20    list peers.   
9d80: 20 5c 47 20 70 65 65 72 73 3a 20 6c 69 73 74 20   \G peers: list 
9d90: 70 65 65 72 73 20 69 6e 20 61 6c 6c 20 67 72 6f  peers in all gro
9da0: 75 70 73 0a 75 6d 65 74 68 6f 64 20 2f 67 70 73  ups.umethod /gps
9db0: 20 28 20 61 64 64 72 20 75 20 2d 2d 20 29 0a 20   ( addr u -- ). 
9dc0: 20 20 20 5c 55 20 67 70 73 20 20 20 20 20 20 20     \U gps       
9dd0: 20 20 20 20 20 20 20 20 20 20 20 73 65 6e 64 20             send 
9de0: 63 6f 6f 72 64 69 6e 61 74 65 73 0a 20 20 20 20  coordinates.    
9df0: 5c 47 20 67 70 73 3a 20 73 65 6e 64 20 79 6f 75  \G gps: send you
9e00: 72 20 63 6f 6f 72 64 69 6e 61 74 65 73 0a 73 79  r coordinates.sy
9e10: 6e 6f 6e 79 6d 20 2f 68 65 72 65 20 2f 67 70 73  nonym /here /gps
9e20: 0a 75 6d 65 74 68 6f 64 20 2f 63 68 61 74 73 20  .umethod /chats 
9e30: 28 20 61 64 64 72 20 75 20 2d 2d 20 29 0a 20 20  ( addr u -- ).  
9e40: 20 20 5c 55 20 63 68 61 74 73 20 20 20 20 20 20    \U chats      
9e50: 20 20 20 20 20 20 20 20 20 20 6c 69 73 74 20 63            list c
9e60: 68 61 74 73 0a 20 20 20 20 5c 47 20 63 68 61 74  hats.    \G chat
9e70: 73 3a 20 6c 69 73 74 20 61 6c 6c 20 63 68 61 74  s: list all chat
9e80: 73 0a 75 6d 65 74 68 6f 64 20 2f 6e 61 74 20 28  s.umethod /nat (
9e90: 20 61 64 64 72 20 75 20 2d 2d 20 29 0a 20 20 20   addr u -- ).   
9ea0: 20 5c 55 20 6e 61 74 20 20 20 20 20 20 20 20 20   \U nat         
9eb0: 20 20 20 20 20 20 20 20 20 6c 69 73 74 20 4e 41           list NA
9ec0: 54 20 69 6e 66 6f 0a 20 20 20 20 5c 47 20 6e 61  T info.    \G na
9ed0: 74 3a 20 6c 69 73 74 20 6e 61 74 20 74 72 61 76  t: list nat trav
9ee0: 65 72 73 61 6c 20 69 6e 66 6f 72 6d 61 74 69 6f  ersal informatio
9ef0: 6e 20 6f 66 20 61 6c 6c 20 70 65 65 72 73 20 69  n of all peers i
9f00: 6e 20 61 6c 6c 20 67 72 6f 75 70 73 0a 75 6d 65  n all groups.ume
9f10: 74 68 6f 64 20 2f 72 65 6e 61 74 20 28 20 61 64  thod /renat ( ad
9f20: 64 72 20 75 20 2d 2d 20 29 0a 20 20 20 20 5c 55  dr u -- ).    \U
9f30: 20 72 65 6e 61 74 20 20 20 20 20 20 20 20 20 20   renat          
9f40: 20 20 20 20 20 20 72 65 64 6f 20 4e 41 54 20 74        redo NAT t
9f50: 72 61 76 65 72 73 61 6c 0a 20 20 20 20 5c 47 20  raversal.    \G 
9f60: 72 65 6e 61 74 3a 20 72 65 64 6f 20 6e 61 74 20  renat: redo nat 
9f70: 74 72 61 76 65 72 73 61 6c 0a 75 6d 65 74 68 6f  traversal.umetho
9f80: 64 20 2f 68 65 6c 70 20 28 20 61 64 64 72 20 75  d /help ( addr u
9f90: 20 2d 2d 20 29 0a 20 20 20 20 5c 55 20 68 65 6c   -- ).    \U hel
9fa0: 70 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20  p               
9fb0: 20 20 73 68 6f 77 20 68 65 6c 70 0a 20 20 20 20    show help.    
9fc0: 5c 47 20 68 65 6c 70 3a 20 6c 69 73 74 20 68 65  \G help: list he
9fd0: 6c 70 0a 75 6d 65 74 68 6f 64 20 2f 6d 79 61 64  lp.umethod /myad
9fe0: 64 72 73 20 28 20 61 64 64 72 20 75 20 2d 2d 20  drs ( addr u -- 
9ff0: 29 0a 20 20 20 20 5c 55 20 6d 79 61 64 64 72 73  ).    \U myaddrs
a000: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 6c 69                li
a010: 73 74 20 6d 79 20 61 64 64 72 65 73 73 65 73 0a  st my addresses.
a020: 20 20 20 20 5c 47 20 6d 79 61 64 64 72 73 3a 20      \G myaddrs: 
a030: 6c 69 73 74 20 6d 79 20 6f 77 6e 20 6c 6f 63 61  list my own loca
a040: 6c 20 61 64 64 72 65 73 73 65 73 20 28 64 65 62  l addresses (deb
a050: 75 67 67 69 6e 67 29 0a 75 6d 65 74 68 6f 64 20  ugging).umethod 
a060: 2f 21 6d 79 61 64 64 72 73 20 28 20 61 64 64 72  /!myaddrs ( addr
a070: 20 75 20 2d 2d 20 29 0a 20 20 20 20 5c 55 20 21   u -- ).    \U !
a080: 6d 79 61 64 64 72 73 20 20 20 20 20 20 20 20 20  myaddrs         
a090: 20 20 20 20 72 65 2d 6f 62 74 61 69 6e 20 6d 79      re-obtain my
a0a0: 20 61 64 64 72 65 73 73 65 73 0a 20 20 20 20 5c   addresses.    \
a0b0: 47 20 21 6d 79 61 64 64 72 73 3a 20 69 66 20 61  G !myaddrs: if a
a0c0: 75 74 6f 6d 61 74 69 63 20 64 65 74 65 63 74 69  utomatic detecti
a0d0: 6f 6e 20 6f 66 20 61 64 64 72 65 73 73 20 63 68  on of address ch
a0e0: 61 6e 67 65 73 20 66 61 69 6c 2c 0a 20 20 20 20  anges fail,.    
a0f0: 5c 47 20 21 6d 79 61 64 64 72 73 3a 20 79 6f 75  \G !myaddrs: you
a100: 20 63 61 6e 20 75 73 65 20 74 68 69 73 20 63 6f   can use this co
a110: 6d 6d 61 6e 64 20 74 6f 20 72 65 2d 6f 62 74 61  mmand to re-obta
a120: 69 6e 20 79 6f 75 72 20 6c 6f 63 61 6c 20 61 64  in your local ad
a130: 64 72 65 73 73 65 73 0a 75 6d 65 74 68 6f 64 20  dresses.umethod 
a140: 2f 6e 6f 74 69 66 79 20 28 20 61 64 64 72 20 75  /notify ( addr u
a150: 20 2d 2d 20 29 0a 20 20 20 20 5c 55 20 6e 6f 74   -- ).    \U not
a160: 69 66 79 20 61 6c 77 61 79 73 7c 6f 6e 7c 6f 66  ify always|on|of
a170: 66 7c 6c 65 64 20 3c 72 67 62 3e 20 3c 6f 6e 2d  f|led <rgb> <on-
a180: 6d 73 3e 20 3c 6f 66 66 2d 6d 73 3e 7c 69 6e 74  ms> <off-ms>|int
a190: 65 72 76 61 6c 20 3c 74 69 6d 65 3e 5b 73 6d 68  erval <time>[smh
a1a0: 5d 7c 6d 6f 64 65 20 30 2d 33 0a 20 20 20 20 5c  ]|mode 0-3.    \
a1b0: 47 20 6e 6f 74 69 66 79 3a 20 43 68 61 6e 67 65  G notify: Change
a1c0: 20 6e 6f 74 69 66 69 63 61 74 6f 6e 20 73 65 74   notificaton set
a1d0: 74 69 6e 67 73 0a 75 6d 65 74 68 6f 64 20 2f 62  tings.umethod /b
a1e0: 65 61 63 6f 6e 73 20 28 20 61 64 64 72 20 75 20  eacons ( addr u 
a1f0: 2d 2d 20 29 0a 20 20 20 20 5c 55 20 62 65 61 63  -- ).    \U beac
a200: 6f 6e 73 20 20 20 20 20 20 20 20 20 20 20 20 20  ons             
a210: 20 6c 69 73 74 20 62 65 61 63 6f 6e 73 0a 20 20   list beacons.  
a220: 20 20 5c 47 20 62 65 61 63 6f 6e 73 3a 20 6c 69    \G beacons: li
a230: 73 74 20 61 6c 6c 20 62 65 61 63 6f 6e 73 0a 75  st all beacons.u
a240: 6d 65 74 68 6f 64 20 2f 6e 32 6f 20 28 20 61 64  method /n2o ( ad
a250: 64 72 20 75 20 2d 2d 20 29 0a 20 20 20 20 5c 55  dr u -- ).    \U
a260: 20 6e 32 6f 20 3c 63 6d 64 3e 20 20 20 20 20 20   n2o <cmd>      
a270: 20 20 20 20 20 20 65 78 65 63 75 74 65 20 6e 32        execute n2
a280: 6f 20 63 6f 6d 6d 61 6e 64 0a 20 20 20 20 5c 47  o command.    \G
a290: 20 6e 32 6f 3a 20 45 78 65 63 75 74 65 20 6e 6f   n2o: Execute no
a2a0: 72 6d 61 6c 20 6e 32 6f 20 63 6f 6d 6d 61 6e 64  rmal n2o command
a2b0: 0a 75 6d 65 74 68 6f 64 20 2f 69 6e 76 69 74 61  .umethod /invita
a2c0: 74 69 6f 6e 73 20 28 20 61 64 64 72 20 75 20 2d  tions ( addr u -
a2d0: 2d 20 29 0a 20 20 20 20 5c 55 20 69 6e 76 69 74  - ).    \U invit
a2e0: 61 74 69 6f 6e 73 20 20 20 20 20 20 20 20 20 20  ations          
a2f0: 68 61 6e 64 6c 65 20 69 6e 76 69 74 61 74 69 6f  handle invitatio
a300: 6e 73 0a 20 20 20 20 5c 47 20 69 6e 76 69 74 61  ns.    \G invita
a310: 74 69 6f 6e 73 3a 20 68 61 6e 64 6c 65 20 69 6e  tions: handle in
a320: 76 69 74 61 74 69 6f 6e 73 3a 20 61 63 63 65 70  vitations: accep
a330: 74 2c 20 69 67 6e 6f 72 65 20 6f 72 20 62 6c 6f  t, ignore or blo
a340: 63 6b 20 69 6e 76 69 74 61 74 69 6f 6e 73 0a 75  ck invitations.u
a350: 6d 65 74 68 6f 64 20 2f 73 79 6e 63 20 28 20 61  method /sync ( a
a360: 64 64 72 20 75 20 2d 2d 20 29 0a 20 20 20 20 5c  ddr u -- ).    \
a370: 55 20 73 79 6e 63 20 5b 2b 64 61 74 65 5d 20 5b  U sync [+date] [
a380: 2d 64 61 74 65 5d 20 73 79 6e 63 68 72 6f 6e 69  -date] synchroni
a390: 7a 65 20 6c 6f 67 73 0a 20 20 20 20 5c 47 20 73  ze logs.    \G s
a3a0: 79 6e 63 3a 20 73 79 6e 63 68 72 6f 6e 69 7a 65  ync: synchronize
a3b0: 20 63 68 61 74 20 6c 6f 67 73 2c 20 73 74 61 72   chat logs, star
a3c0: 74 69 6e 67 20 61 6e 64 2f 6f 72 20 65 6e 64 69  ting and/or endi
a3d0: 6e 67 20 61 74 20 73 70 65 63 69 66 69 63 0a 20  ng at specific. 
a3e0: 20 20 20 5c 47 20 73 79 6e 63 3a 20 74 69 6d 65     \G sync: time
a3f0: 2f 64 61 74 65 0a 75 6d 65 74 68 6f 64 20 2f 76  /date.umethod /v
a400: 65 72 73 69 6f 6e 20 28 20 61 64 64 72 20 75 20  ersion ( addr u 
a410: 2d 2d 20 29 0a 20 20 20 20 5c 55 20 76 65 72 73  -- ).    \U vers
a420: 69 6f 6e 20 20 20 20 20 20 20 20 20 20 20 20 20  ion             
a430: 20 76 65 72 73 69 6f 6e 20 73 74 72 69 6e 67 0a   version string.
a440: 20 20 20 20 5c 47 20 76 65 72 73 69 6f 6e 3a 20      \G version: 
a450: 70 72 69 6e 74 20 76 65 72 73 69 6f 6e 20 73 74  print version st
a460: 72 69 6e 67 0a 75 6d 65 74 68 6f 64 20 2f 6c 6f  ring.umethod /lo
a470: 67 20 28 20 61 64 64 72 20 75 20 2d 2d 20 29 0a  g ( addr u -- ).
a480: 20 20 20 20 5c 55 20 6c 6f 67 20 5b 23 6c 69 6e      \U log [#lin
a490: 65 73 5d 20 20 20 20 20 20 20 20 20 73 68 6f 77  es]         show
a4a0: 20 6c 6f 67 0a 20 20 20 20 5c 47 20 6c 6f 67 3a   log.    \G log:
a4b0: 20 73 68 6f 77 20 74 68 65 20 6c 6f 67 2c 20 64   show the log, d
a4c0: 65 66 61 75 6c 74 20 69 73 20 61 20 73 63 72 65  efault is a scre
a4d0: 65 6e 66 75 6c 0a 75 6d 65 74 68 6f 64 20 2f 6c  enful.umethod /l
a4e0: 6f 67 73 74 79 6c 65 20 28 20 61 64 64 72 20 75  ogstyle ( addr u
a4f0: 20 2d 2d 20 29 0a 20 20 20 20 5c 55 20 6c 6f 67   -- ).    \U log
a500: 73 74 79 6c 65 20 5b 2b 2d 73 74 79 6c 65 5d 20  style [+-style] 
a510: 20 20 73 65 74 20 6c 6f 67 20 73 74 79 6c 65 0a    set log style.
a520: 20 20 20 20 5c 47 20 6c 6f 67 73 74 79 6c 65 3a      \G logstyle:
a530: 20 73 65 74 20 6c 6f 67 20 73 74 79 6c 65 73 2c   set log styles,
a540: 20 74 68 65 20 66 6f 6c 6c 6f 77 69 6e 67 20 73   the following s
a550: 65 74 74 69 6e 67 73 20 65 78 69 73 74 3a 0a 20  ettings exist:. 
a560: 20 20 20 5c 47 20 6c 6f 67 73 74 79 6c 65 3a 20     \G logstyle: 
a570: 2b 64 61 74 65 20 20 20 20 20 20 61 20 64 61 74  +date      a dat
a580: 65 20 70 65 72 20 6c 6f 67 20 6c 69 6e 65 0a 20  e per log line. 
a590: 20 20 20 5c 47 20 6c 6f 67 73 74 79 6c 65 3a 20     \G logstyle: 
a5a0: 2b 6e 75 6d 20 20 20 20 20 20 20 61 20 6d 65 73  +num       a mes
a5b0: 73 61 67 65 20 6e 75 6d 62 65 72 20 70 65 72 20  sage number per 
a5c0: 6c 6f 67 20 6c 69 6e 65 0a 75 6d 65 74 68 6f 64  log line.umethod
a5d0: 20 2f 6f 74 72 69 66 79 20 28 20 61 64 64 72 20   /otrify ( addr 
a5e0: 75 20 2d 2d 20 29 0a 20 20 20 20 5c 55 20 6f 74  u -- ).    \U ot
a5f0: 72 69 66 79 20 23 6c 69 6e 65 5b 73 5d 20 20 20  rify #line[s]   
a600: 20 20 20 6f 74 72 69 66 79 20 6d 65 73 73 61 67     otrify messag
a610: 65 0a 20 20 20 20 5c 47 20 6f 74 72 69 66 79 3a  e.    \G otrify:
a620: 20 74 75 72 6e 20 61 6e 20 6f 6c 64 65 72 20 6d   turn an older m
a630: 65 73 73 61 67 65 20 6f 66 20 79 6f 75 72 73 20  essage of yours 
a640: 69 6e 74 6f 20 61 6e 20 4f 54 52 20 6d 65 73 73  into an OTR mess
a650: 61 67 65 0a 75 6d 65 74 68 6f 64 20 2f 6c 6f 63  age.umethod /loc
a660: 6b 20 28 20 61 64 64 72 20 75 20 2d 2d 20 29 0a  k ( addr u -- ).
a670: 20 20 20 20 5c 55 20 6c 6f 63 6b 20 7b 40 6e 69      \U lock {@ni
a680: 63 6b 7d 20 20 20 20 20 20 20 20 20 6c 6f 63 6b  ck}         lock
a690: 20 64 6f 77 6e 0a 20 20 20 20 5c 47 20 6c 6f 63   down.    \G loc
a6a0: 6b 3a 20 6c 6f 63 6b 20 64 6f 77 6e 20 63 6f 6d  k: lock down com
a6b0: 6d 75 6e 69 63 61 74 69 6f 6e 20 74 6f 20 6c 69  munication to li
a6c0: 73 74 20 6f 66 20 6e 69 63 6b 73 0a 75 6d 65 74  st of nicks.umet
a6d0: 68 6f 64 20 2f 75 6e 6c 6f 63 6b 20 28 20 61 64  hod /unlock ( ad
a6e0: 64 72 20 75 20 2d 2d 20 29 0a 20 20 20 20 5c 55  dr u -- ).    \U
a6f0: 20 75 6e 6c 6f 63 6b 20 20 20 20 20 20 20 20 20   unlock         
a700: 20 20 20 20 20 20 73 74 6f 70 20 6c 6f 63 6b 20        stop lock 
a710: 64 6f 77 6e 0a 20 20 20 20 5c 47 20 75 6e 6c 6f  down.    \G unlo
a720: 63 6b 3a 20 73 74 6f 70 20 6c 6f 63 6b 20 64 6f  ck: stop lock do
a730: 77 6e 0a 75 6d 65 74 68 6f 64 20 2f 6c 6f 63 6b  wn.umethod /lock
a740: 3f 20 28 20 61 64 64 72 20 75 20 2d 2d 20 29 0a  ? ( addr u -- ).
a750: 20 20 20 20 5c 55 20 6c 6f 63 6b 3f 20 20 20 20      \U lock?    
a760: 20 20 20 20 20 20 20 20 20 20 20 20 63 68 65 63              chec
a770: 6b 20 6c 6f 63 6b 20 73 74 61 74 75 73 0a 20 20  k lock status.  
a780: 20 20 5c 47 20 6c 6f 63 6b 3f 3a 20 72 65 70 6f    \G lock?: repo
a790: 72 74 20 6c 6f 63 6b 20 73 74 61 74 75 73 0a 75  rt lock status.u
a7a0: 6d 65 74 68 6f 64 20 2f 70 65 72 6d 73 20 28 20  method /perms ( 
a7b0: 61 64 64 72 20 75 20 2d 2d 20 29 0a 20 20 20 20  addr u -- ).    
a7c0: 5c 55 20 70 65 72 6d 73 20 72 6f 6c 65 73 20 7b  \U perms roles {
a7d0: 40 6b 65 79 73 7d 20 20 73 65 74 20 61 6e 64 20  @keys}  set and 
a7e0: 63 68 61 6e 67 65 20 70 65 72 6d 69 73 73 69 6f  change permissio
a7f0: 6e 73 20 6f 66 20 75 73 65 72 73 0a 20 20 20 20  ns of users.    
a800: 5c 47 20 70 65 72 6d 73 3a 20 73 65 74 20 70 65  \G perms: set pe
a810: 72 6d 69 73 73 69 6f 6e 73 0a 75 6d 65 74 68 6f  rmissions.umetho
a820: 64 20 2f 62 79 65 20 28 20 61 64 64 72 20 75 20  d /bye ( addr u 
a830: 2d 2d 20 29 0a 20 20 20 20 5c 55 20 62 79 65 0a  -- ).    \U bye.
a840: 20 20 20 20 5c 47 20 62 79 65 3a 20 6c 65 61 76      \G bye: leav
a850: 65 73 20 74 68 65 20 63 75 72 72 65 6e 74 20 63  es the current c
a860: 68 61 74 0a 75 6d 65 74 68 6f 64 20 2f 63 68 61  hat.umethod /cha
a870: 74 20 28 20 61 64 64 72 20 75 20 2d 2d 20 29 0a  t ( addr u -- ).
a880: 20 20 20 20 5c 55 20 63 68 61 74 20 5b 67 72 6f      \U chat [gro
a890: 75 70 5d 5b 40 75 73 65 72 5d 20 20 73 77 69 74  up][@user]  swit
a8a0: 63 68 2f 63 6f 6e 6e 65 63 74 20 63 68 61 74 0a  ch/connect chat.
a8b0: 20 20 20 20 5c 47 20 63 68 61 74 3a 20 73 77 69      \G chat: swi
a8c0: 74 63 68 20 74 6f 20 63 68 61 74 20 77 69 74 68  tch to chat with
a8d0: 20 75 73 65 72 20 6f 72 20 67 72 6f 75 70 0a 75   user or group.u
a8e0: 6d 65 74 68 6f 64 20 2f 73 70 6c 69 74 20 28 20  method /split ( 
a8f0: 61 64 64 72 20 75 20 2d 2d 20 29 0a 20 20 20 20  addr u -- ).    
a900: 5c 55 20 73 70 6c 69 74 20 20 20 20 20 20 20 20  \U split        
a910: 20 20 20 20 20 20 20 20 73 70 6c 69 74 20 6c 6f          split lo
a920: 61 64 0a 20 20 20 20 5c 47 20 73 70 6c 69 74 3a  ad.    \G split:
a930: 20 72 65 64 75 63 65 20 64 69 73 74 72 69 62 75   reduce distribu
a940: 74 69 6f 6e 20 6c 6f 61 64 20 62 79 20 72 65 63  tion load by rec
a950: 6f 6e 6e 65 63 74 69 6e 67 0a 65 6e 64 2d 63 6c  onnecting.end-cl
a960: 61 73 73 20 63 68 61 74 2d 63 6d 64 73 0a 0a 63  ass chat-cmds..c
a970: 68 61 74 2d 63 6d 64 73 20 6e 65 77 20 43 6f 6e  hat-cmds new Con
a980: 73 74 61 6e 74 20 74 65 78 74 2d 63 68 61 74 2d  stant text-chat-
a990: 63 6d 64 2d 6f 0a 0a 74 65 78 74 2d 63 68 61 74  cmd-o..text-chat
a9a0: 2d 63 6d 64 2d 6f 20 74 6f 20 63 68 61 74 2d 63  -cmd-o to chat-c
a9b0: 6d 64 2d 6f 0a 0a 3a 6e 6f 6e 61 6d 65 20 28 20  md-o..:noname ( 
a9c0: 61 64 64 72 20 75 20 2d 2d 20 29 0a 20 20 20 20  addr u -- ).    
a9d0: 5b 3a 20 24 2c 20 6d 73 67 2d 61 63 74 69 6f 6e  [: $, msg-action
a9e0: 20 3b 5d 20 73 65 6e 64 2d 61 76 61 6c 61 6e 63   ;] send-avalanc
a9f0: 68 65 20 3b 20 69 73 20 2f 6d 65 0a 0a 3a 6e 6f  he ; is /me..:no
aa00: 6e 61 6d 65 20 28 20 61 64 64 72 20 75 20 2d 2d  name ( addr u --
aa10: 20 29 0a 20 20 20 20 64 75 70 20 30 3d 20 49 46   ).    dup 0= IF
aa20: 20 20 32 64 72 6f 70 0a 09 61 77 61 79 3f 20 49    2drop..away? I
aa30: 46 20 20 22 49 27 6d 20 62 61 63 6b 22 20 20 45  F  "I'm back"  E
aa40: 4c 53 45 20 20 22 41 77 61 79 20 66 72 6f 6d 20  LSE  "Away from 
aa50: 6b 65 79 62 6f 61 72 64 22 20 20 54 48 45 4e 0a  keyboard"  THEN.
aa60: 09 61 77 61 79 3f 20 30 3d 20 74 6f 20 61 77 61  .away? 0= to awa
aa70: 79 3f 0a 20 20 20 20 54 48 45 4e 0a 20 20 20 20  y?.    THEN.    
aa80: 5b 3a 20 24 2c 20 6d 73 67 2d 61 63 74 69 6f 6e  [: $, msg-action
aa90: 20 3b 5d 20 73 65 6e 64 2d 61 76 61 6c 61 6e 63   ;] send-avalanc
aaa0: 68 65 20 3b 20 69 73 20 2f 61 77 61 79 0a 0a 3a  he ; is /away..:
aab0: 6e 6f 6e 61 6d 65 20 28 20 61 64 64 72 20 75 20  noname ( addr u 
aac0: 2d 2d 20 29 0a 20 20 20 20 32 64 75 70 20 73 22  -- ).    2dup s"
aad0: 20 6f 6e 22 20 73 74 72 3d 20 3e 72 0a 20 20 20   on" str= >r.   
aae0: 20 32 64 75 70 20 73 22 20 6f 66 66 22 20 73 74   2dup s" off" st
aaf0: 72 3d 20 72 40 20 6f 72 20 49 46 20 20 20 32 64  r= r@ or IF   2d
ab00: 72 6f 70 0a 09 6d 73 67 2d 67 72 6f 75 70 2d 6f  rop..msg-group-o
ab10: 20 72 40 20 49 46 20 20 2e 6d 73 67 3a 2b 6f 74   r@ IF  .msg:+ot
ab20: 72 20 20 45 4c 53 45 20 20 2e 6d 73 67 3a 2d 6f  r  ELSE  .msg:-o
ab30: 74 72 20 20 54 48 45 4e 0a 09 3c 69 6e 66 6f 3e  tr  THEN..<info>
ab40: 20 2e 22 20 3d 3d 3d 20 22 20 72 3e 20 49 46 20   ." === " r> IF 
ab50: 20 2e 22 20 65 6e 74 65 72 22 20 20 45 4c 53 45   ." enter"  ELSE
ab60: 20 20 2e 22 20 6c 65 61 76 65 22 20 20 54 48 45    ." leave"  THE
ab70: 4e 0a 09 2e 22 20 20 6f 74 72 20 6d 6f 64 65 20  N..."  otr mode 
ab80: 3d 3d 3d 22 20 3c 64 65 66 61 75 6c 74 3e 20 66  ===" <default> f
ab90: 6f 72 74 68 3a 63 72 0a 20 20 20 20 45 4c 53 45  orth:cr.    ELSE
aba0: 20 20 72 64 72 6f 70 0a 09 6d 73 67 2d 67 72 6f    rdrop..msg-gro
abb0: 75 70 2d 6f 20 2e 6d 73 67 3a 6d 6f 64 65 20 40  up-o .msg:mode @
abc0: 20 3e 72 0a 09 6d 73 67 2d 67 72 6f 75 70 2d 6f   >r..msg-group-o
abd0: 20 2e 6d 73 67 3a 2b 6f 74 72 20 61 76 61 6c 61   .msg:+otr avala
abe0: 6e 63 68 65 2d 74 65 78 74 0a 09 72 3e 20 6d 73  nche-text..r> ms
abf0: 67 2d 67 72 6f 75 70 2d 6f 20 2e 6d 73 67 3a 6d  g-group-o .msg:m
ac00: 6f 64 65 20 21 0a 20 20 20 20 54 48 45 4e 20 3b  ode !.    THEN ;
ac10: 20 69 73 20 2f 6f 74 72 0a 0a 3a 6e 6f 6e 61 6d   is /otr..:nonam
ac20: 65 20 28 20 61 64 64 72 20 75 20 2d 2d 20 29 20  e ( addr u -- ) 
ac30: 20 32 64 72 6f 70 0a 20 20 20 20 5b 3a 20 6d 73   2drop.    [: ms
ac40: 67 3a 6e 61 6d 65 24 20 2e 67 72 6f 75 70 20 2e  g:name$ .group .
ac50: 22 20 3a 20 22 0a 09 6d 73 67 3a 70 65 65 72 73  " : "..msg:peers
ac60: 5b 5d 20 24 40 20 62 6f 75 6e 64 73 20 3f 44 4f  [] $@ bounds ?DO
ac70: 0a 09 20 20 20 20 73 70 61 63 65 20 49 20 40 20  ..    space I @ 
ac80: 3e 6f 20 2e 63 6f 6e 2d 69 64 20 73 70 61 63 65  >o .con-id space
ac90: 0a 09 20 20 20 20 61 63 6b 40 20 2e 72 74 64 65  ..    ack@ .rtde
aca0: 6c 61 79 20 36 34 40 20 36 34 3e 66 20 31 6e 20  lay 64@ 64>f 1n 
acb0: 66 2a 20 28 2e 74 69 6d 65 29 20 6f 3e 0a 09 63  f* (.time) o>..c
acc0: 65 6c 6c 20 2b 4c 4f 4f 50 20 20 66 6f 72 74 68  ell +LOOP  forth
acd0: 3a 63 72 20 3b 5d 20 67 72 6f 75 70 23 6d 61 70  :cr ;] group#map
ace0: 20 3b 20 69 73 20 2f 70 65 65 72 73 0a 0a 3a 6e   ; is /peers..:n
acf0: 6f 6e 61 6d 65 20 28 20 61 64 64 72 20 75 20 2d  oname ( addr u -
ad00: 2d 20 29 20 20 32 64 72 6f 70 0a 20 20 20 20 63  - )  2drop.    c
ad10: 6f 6f 72 64 21 20 63 6f 6f 72 64 40 20 32 64 75  oord! coord@ 2du
ad20: 70 20 30 20 2d 73 6b 69 70 20 6e 69 70 20 30 3d  p 0 -skip nip 0=
ad30: 20 49 46 20 20 32 64 72 6f 70 0a 20 20 20 20 45   IF  2drop.    E
ad40: 4c 53 45 0a 09 5b 3a 20 24 2c 20 6d 73 67 2d 63  LSE..[: $, msg-c
ad50: 6f 6f 72 64 20 3b 5d 20 73 65 6e 64 2d 61 76 61  oord ;] send-ava
ad60: 6c 61 6e 63 68 65 0a 20 20 20 20 54 48 45 4e 20  lanche.    THEN 
ad70: 3b 20 69 73 20 2f 67 70 73 0a 0a 3a 6e 6f 6e 61  ; is /gps..:nona
ad80: 6d 65 20 28 20 61 64 64 72 20 75 20 2d 2d 20 29  me ( addr u -- )
ad90: 0a 20 20 20 20 62 6c 20 73 6b 69 70 20 27 2f 27  .    bl skip '/'
ada0: 20 73 6b 69 70 0a 20 20 20 20 32 64 75 70 20 5b   skip.    2dup [
adb0: 3a 20 2e 22 20 20 20 20 20 5c 55 20 22 20 66 6f  : ."     \U " fo
adc0: 72 74 68 3a 74 79 70 65 20 3b 5d 20 24 74 6d 70  rth:type ;] $tmp
add0: 20 5b 27 5d 20 2e 63 68 61 74 68 65 6c 70 20 73   ['] .chathelp s
ade0: 65 61 72 63 68 2d 68 65 6c 70 0a 20 20 20 20 5b  earch-help.    [
adf0: 3a 20 2e 22 20 20 20 20 20 5c 47 20 22 20 66 6f  : ."     \G " fo
ae00: 72 74 68 3a 74 79 70 65 20 27 3a 27 20 66 6f 72  rth:type ':' for
ae10: 74 68 3a 65 6d 69 74 20 3b 5d 20 24 74 6d 70 20  th:emit ;] $tmp 
ae20: 5b 27 5d 20 2e 63 6d 64 20 73 65 61 72 63 68 2d  ['] .cmd search-
ae30: 68 65 6c 70 20 3b 0a 69 73 20 2f 68 65 6c 70 0a  help ;.is /help.
ae40: 0a 3a 6e 6f 6e 61 6d 65 20 28 20 61 64 64 72 20  .:noname ( addr 
ae50: 75 20 2d 2d 20 29 0a 20 20 20 20 32 64 72 6f 70  u -- ).    2drop
ae60: 20 2e 69 6e 76 69 74 61 74 69 6f 6e 73 20 3b 20   .invitations ; 
ae70: 69 73 20 2f 69 6e 76 69 74 61 74 69 6f 6e 73 0a  is /invitations.
ae80: 0a 3a 6e 6f 6e 61 6d 65 20 28 20 61 64 64 72 20  .:noname ( addr 
ae90: 75 20 2d 2d 20 29 0a 20 20 20 20 32 64 72 6f 70  u -- ).    2drop
aea0: 20 2e 22 20 3d 3d 3d 3d 3d 20 63 68 61 74 73 3a   ." ===== chats:
aeb0: 20 22 0a 20 20 20 20 5b 3a 20 20 6d 73 67 3a 6e   ".    [:  msg:n
aec0: 61 6d 65 24 20 6d 73 67 2d 67 72 6f 75 70 24 20  ame$ msg-group$ 
aed0: 24 40 20 73 74 72 3d 20 49 46 20 2e 22 20 2a 22  $@ str= IF ." *"
aee0: 20 54 48 45 4e 0a 09 6d 73 67 3a 6e 61 6d 65 24   THEN..msg:name$
aef0: 20 2e 67 72 6f 75 70 0a 09 2e 22 20 5b 22 20 6d   .group..." [" m
af00: 73 67 3a 70 65 65 72 73 5b 5d 20 24 5b 5d 23 20  sg:peers[] $[]# 
af10: 30 20 2e 72 20 2e 22 20 5d 23 22 0a 09 6d 73 67  0 .r ." ]#"..msg
af20: 3a 6c 6f 67 5b 5d 20 24 5b 5d 23 20 75 2e 20 3b  :log[] $[]# u. ;
af30: 5d 20 67 72 6f 75 70 23 6d 61 70 0a 20 20 20 20  ] group#map.    
af40: 2e 22 20 3d 3d 3d 3d 3d 22 20 66 6f 72 74 68 3a  ." =====" forth:
af50: 63 72 20 3b 20 69 73 20 2f 63 68 61 74 73 0a 0a  cr ; is /chats..
af60: 3a 6e 6f 6e 61 6d 65 20 28 20 61 64 64 72 20 75  :noname ( addr u
af70: 20 2d 2d 20 29 20 20 32 64 72 6f 70 0a 20 20 20   -- )  2drop.   
af80: 20 5b 3a 20 20 2e 22 20 3d 3d 3d 3d 3d 20 47 72   [:  ." ===== Gr
af90: 6f 75 70 3a 20 22 20 6d 73 67 3a 6e 61 6d 65 24  oup: " msg:name$
afa0: 20 2e 67 72 6f 75 70 20 2e 22 20 20 3d 3d 3d 3d   .group ."  ====
afb0: 3d 22 20 66 6f 72 74 68 3a 63 72 0a 09 6d 73 67  =" forth:cr..msg
afc0: 3a 70 65 65 72 73 5b 5d 20 24 40 20 62 6f 75 6e  :peers[] $@ boun
afd0: 64 73 20 3f 44 4f 0a 09 20 20 20 20 2e 22 20 2d  ds ?DO..    ." -
afe0: 2d 2d 20 22 20 49 20 40 20 3e 6f 20 2e 63 6f 6e  -- " I @ >o .con
aff0: 2d 69 64 20 2e 22 20 3a 20 22 20 72 65 74 75 72  -id ." : " retur
b000: 6e 2d 61 64 64 72 65 73 73 20 2e 61 64 64 72 2d  n-address .addr-
b010: 70 61 74 68 0a 09 20 20 20 20 2e 22 20 20 2d 2d  path..    ."  --
b020: 2d 22 20 66 6f 72 74 68 3a 63 72 20 2e 6e 61 74  -" forth:cr .nat
b030: 2d 61 64 64 72 73 20 6f 3e 0a 09 63 65 6c 6c 20  -addrs o>..cell 
b040: 2b 4c 4f 4f 50 20 3b 5d 20 67 72 6f 75 70 23 6d  +LOOP ;] group#m
b050: 61 70 20 3b 20 69 73 20 2f 6e 61 74 0a 0a 3a 6e  ap ; is /nat..:n
b060: 6f 6e 61 6d 65 20 28 20 61 64 64 72 20 75 20 2d  oname ( addr u -
b070: 2d 20 29 0a 20 20 20 20 32 64 72 6f 70 0a 20 20  - ).    2drop.  
b080: 20 20 2e 22 20 3d 3d 3d 3d 3d 20 61 6c 6c 20 3d    ." ===== all =
b090: 3d 3d 3d 3d 22 20 66 6f 72 74 68 3a 63 72 20 20  ====" forth:cr  
b0a0: 20 20 2e 6d 79 2d 61 64 64 72 24 73 0a 20 20 20    .my-addr$s.   
b0b0: 20 2e 22 20 3d 3d 3d 3d 3d 20 70 75 62 6c 69 63   ." ===== public
b0c0: 20 3d 3d 3d 3d 3d 22 20 66 6f 72 74 68 3a 63 72   =====" forth:cr
b0d0: 20 2e 70 75 62 2d 61 64 64 72 24 73 0a 20 20 20   .pub-addr$s.   
b0e0: 20 2e 22 20 3d 3d 3d 3d 3d 20 70 72 69 76 61 74   ." ===== privat
b0f0: 65 20 3d 3d 3d 3d 3d 22 20 66 6f 72 74 68 3a 63  e =====" forth:c
b100: 72 20 2e 70 72 69 76 2d 61 64 64 72 24 73 20 3b  r .priv-addr$s ;
b110: 20 69 73 20 2f 6d 79 61 64 64 72 73 0a 3a 6e 6f   is /myaddrs.:no
b120: 6e 61 6d 65 20 28 20 61 64 64 72 20 75 20 2d 2d  name ( addr u --
b130: 20 29 0a 20 20 20 20 32 64 72 6f 70 20 21 6d 79   ).    2drop !my
b140: 2d 61 64 64 72 20 3b 20 69 73 20 2f 21 6d 79 61  -addr ; is /!mya
b150: 64 64 72 73 0a 0a 3a 6e 6f 6e 61 6d 65 20 28 20  ddrs..:noname ( 
b160: 61 64 64 72 20 75 20 2d 2d 20 29 0a 20 20 20 20  addr u -- ).    
b170: 5b 27 5d 20 6e 6f 74 69 66 79 2d 63 6d 64 73 20  ['] notify-cmds 
b180: 65 76 61 6c 75 61 74 65 2d 69 6e 20 2e 6e 6f 74  evaluate-in .not
b190: 69 66 79 20 3b 20 69 73 20 2f 6e 6f 74 69 66 79  ify ; is /notify
b1a0: 0a 0a 3a 6e 6f 6e 61 6d 65 20 28 20 61 64 64 72  ..:noname ( addr
b1b0: 20 75 20 2d 2d 20 29 0a 20 20 20 20 32 64 72 6f   u -- ).    2dro
b1c0: 70 20 2e 22 20 3d 3d 3d 20 62 65 61 63 6f 6e 73  p ." === beacons
b1d0: 20 3d 3d 3d 22 20 66 6f 72 74 68 3a 63 72 0a 20   ===" forth:cr. 
b1e0: 20 20 20 62 65 61 63 6f 6e 73 23 20 5b 3a 20 64     beacons# [: d
b1f0: 75 70 20 24 40 20 2e 61 64 64 72 65 73 73 20 73  up $@ .address s
b200: 70 61 63 65 0a 20 20 20 20 20 20 63 65 6c 6c 2b  pace.      cell+
b210: 20 24 40 20 6f 76 65 72 20 36 34 40 20 2e 74 69   $@ over 64@ .ti
b220: 63 6b 73 20 73 70 61 63 65 0a 20 20 20 20 20 20  cks space.      
b230: 31 20 36 34 73 20 73 61 66 65 2f 73 74 72 69 6e  1 64s safe/strin
b240: 67 20 62 6f 75 6e 64 73 20 3f 44 4f 0a 09 20 20  g bounds ?DO..  
b250: 49 20 32 40 20 3f 64 75 70 2d 49 46 20 2e 2e 63  I 2@ ?dup-IF ..c
b260: 6f 6e 2d 69 64 20 73 70 61 63 65 20 54 48 45 4e  on-id space THEN
b270: 20 2e 6e 61 6d 65 0a 20 20 20 20 20 20 32 20 63   .name.      2 c
b280: 65 6c 6c 73 20 2b 4c 4f 4f 50 20 66 6f 72 74 68  ells +LOOP forth
b290: 3a 63 72 20 3b 5d 20 23 6d 61 70 20 3b 20 69 73  :cr ;] #map ; is
b2a0: 20 2f 62 65 61 63 6f 6e 73 0a 0a 3a 6e 6f 6e 61   /beacons..:nona
b2b0: 6d 65 20 28 20 61 64 64 72 20 75 20 2d 2d 20 29  me ( addr u -- )
b2c0: 0a 20 20 20 20 73 3e 75 6e 75 6d 62 65 72 3f 20  .    s>unumber? 
b2d0: 49 46 20 20 64 72 6f 70 20 20 45 4c 53 45 20 20  IF  drop  ELSE  
b2e0: 32 64 72 6f 70 20 30 20 20 54 48 45 4e 20 20 63  2drop 0  THEN  c
b2f0: 65 6c 6c 73 20 3e 72 0a 20 20 20 20 6d 73 67 2d  ells >r.    msg-
b300: 67 72 6f 75 70 2d 6f 20 2e 6d 73 67 3a 70 65 65  group-o .msg:pee
b310: 72 73 5b 5d 20 24 40 20 72 40 20 75 3c 3d 20 49  rs[] $@ r@ u<= I
b320: 46 20 20 64 72 6f 70 20 72 64 72 6f 70 20 20 45  F  drop rdrop  E
b330: 58 49 54 20 20 54 48 45 4e 0a 20 20 20 20 72 3e  XIT  THEN.    r>
b340: 20 2b 20 40 20 3e 6f 20 6f 20 74 6f 20 63 6f 6e   + @ >o o to con
b350: 6e 65 63 74 69 6f 6e 0a 20 20 20 20 2e 22 20 3d  nection.    ." =
b360: 3d 3d 20 73 79 6e 63 20 3d 3d 3d 22 20 66 6f 72  == sync ===" for
b370: 74 68 3a 63 72 0a 20 20 20 20 6e 65 74 32 6f 2d  th:cr.    net2o-
b380: 63 6f 64 65 20 65 78 70 65 63 74 2d 6d 73 67 20  code expect-msg 
b390: 5b 3a 20 6d 73 67 2d 67 72 6f 75 70 20 6c 61 73  [: msg-group las
b3a0: 74 3f 2c 20 3b 5d 20 5b 6d 73 67 2c 5d 20 65 6e  t?, ;] [msg,] en
b3b0: 64 2d 63 6f 64 65 20 6f 3e 20 3b 20 69 73 20 2f  d-code o> ; is /
b3c0: 73 79 6e 63 0a 0a 3a 6e 6f 6e 61 6d 65 20 28 20  sync..:noname ( 
b3d0: 61 64 64 72 20 75 20 2d 2d 20 29 0a 20 20 20 20  addr u -- ).    
b3e0: 32 64 72 6f 70 20 2e 6e 32 6f 2d 76 65 72 73 69  2drop .n2o-versi
b3f0: 6f 6e 20 73 70 61 63 65 20 2e 67 66 6f 72 74 68  on space .gforth
b400: 2d 76 65 72 73 69 6f 6e 20 66 6f 72 74 68 3a 63  -version forth:c
b410: 72 20 3b 20 69 73 20 2f 76 65 72 73 69 6f 6e 0a  r ; is /version.
b420: 0a 3a 6e 6f 6e 61 6d 65 20 28 20 61 64 64 72 20  .:noname ( addr 
b430: 75 20 2d 2d 20 29 0a 20 20 20 20 73 3e 75 6e 75  u -- ).    s>unu
b440: 6d 62 65 72 3f 20 49 46 20 20 64 72 6f 70 20 3e  mber? IF  drop >
b450: 72 20 20 45 4c 53 45 20 20 32 64 72 6f 70 20 72  r  ELSE  2drop r
b460: 6f 77 73 20 3e 72 20 20 54 48 45 4e 0a 20 20 20  ows >r  THEN.   
b470: 20 6d 73 67 2d 67 72 6f 75 70 24 20 24 40 20 3e   msg-group$ $@ >
b480: 67 72 6f 75 70 20 70 75 72 67 65 2d 6c 6f 67 0a  group purge-log.
b490: 20 20 20 20 72 3e 20 20 64 69 73 70 6c 61 79 2d      r>  display-
b4a0: 6c 61 73 74 6e 20 3b 20 69 73 20 2f 6c 6f 67 0a  lastn ; is /log.
b4b0: 0a 3a 6e 6f 6e 61 6d 65 20 28 20 61 64 64 72 20  .:noname ( addr 
b4c0: 75 20 2d 2d 20 29 0a 20 20 20 20 5b 27 5d 20 6c  u -- ).    ['] l
b4d0: 6f 67 73 74 79 6c 65 73 20 65 76 61 6c 75 61 74  ogstyles evaluat
b4e0: 65 2d 69 6e 20 3b 20 69 73 20 2f 6c 6f 67 73 74  e-in ; is /logst
b4f0: 79 6c 65 0a 0a 3a 6e 6f 6e 61 6d 65 20 28 20 61  yle..:noname ( a
b500: 64 64 72 20 75 20 2d 2d 20 29 0a 20 20 20 20 5b  ddr u -- ).    [
b510: 3a 20 42 45 47 49 4e 20 20 62 6c 20 24 73 70 6c  : BEGIN  bl $spl
b520: 69 74 20 32 3e 72 20 64 75 70 20 20 57 48 49 4c  it 2>r dup  WHIL
b530: 45 20 20 73 3e 6e 75 6d 62 65 72 3f 20 57 48 49  E  s>number? WHI
b540: 4c 45 0a 09 09 20 20 20 20 64 72 6f 70 20 64 6f  LE...    drop do
b550: 2d 6f 74 72 69 66 79 20 20 32 72 3e 20 20 52 45  -otrify  2r>  RE
b560: 50 45 41 54 20 54 48 45 4e 0a 09 32 64 72 6f 70  PEAT THEN..2drop
b570: 20 32 72 3e 20 32 64 72 6f 70 20 20 6e 6f 77 3e   2r> 2drop  now>
b580: 6f 74 72 0a 20 20 20 20 3b 5d 20 28 73 65 6e 64  otr.    ;] (send
b590: 2d 61 76 61 6c 61 6e 63 68 65 29 20 64 72 6f 70  -avalanche) drop
b5a0: 20 2e 63 68 61 74 20 73 61 76 65 2d 6d 73 67 73   .chat save-msgs
b5b0: 26 20 3b 20 69 73 20 2f 6f 74 72 69 66 79 0a 0a  & ; is /otrify..
b5c0: 3a 6e 6f 6e 61 6d 65 20 28 20 61 64 64 72 20 75  :noname ( addr u
b5d0: 20 2d 2d 20 29 0a 20 20 20 20 6d 73 67 2d 67 72   -- ).    msg-gr
b5e0: 6f 75 70 2d 6f 20 2e 6d 73 67 3a 2d 6c 6f 63 6b  oup-o .msg:-lock
b5f0: 0a 20 20 20 20 77 6f 72 64 2d 61 72 67 73 20 5b  .    word-args [
b600: 27 5d 20 61 72 67 73 3e 6b 65 79 6c 69 73 74 20  '] args>keylist 
b610: 65 78 65 63 75 74 65 2d 70 61 72 73 69 6e 67 0a  execute-parsing.
b620: 20 20 20 20 5b 3a 20 6b 65 79 2d 6c 69 73 74 20      [: key-list 
b630: 76 2d 65 6e 63 24 20 24 2c 20 6e 65 74 32 6f 2d  v-enc$ $, net2o-
b640: 62 61 73 65 3a 6d 73 67 2d 6c 6f 63 6b 20 3b 5d  base:msg-lock ;]
b650: 20 73 65 6e 64 2d 61 76 61 6c 61 6e 63 68 65 0a   send-avalanche.
b660: 20 20 20 20 76 6b 65 79 20 6b 65 79 73 69 7a 65      vkey keysize
b670: 20 24 6d 61 6b 65 20 6d 73 67 2d 67 72 6f 75 70   $make msg-group
b680: 2d 6f 20 2e 6d 73 67 3a 6b 65 79 73 5b 5d 20 3e  -o .msg:keys[] >
b690: 62 61 63 6b 0a 20 20 20 20 6d 73 67 2d 67 72 6f  back.    msg-gro
b6a0: 75 70 2d 6f 20 2e 6d 73 67 3a 2b 6c 6f 63 6b 0a  up-o .msg:+lock.
b6b0: 3b 20 69 73 20 2f 6c 6f 63 6b 0a 3a 6e 6f 6e 61  ; is /lock.:nona
b6c0: 6d 65 20 28 20 61 64 64 72 20 75 20 2d 2d 20 29  me ( addr u -- )
b6d0: 0a 20 20 20 20 32 64 72 6f 70 20 6d 73 67 2d 67  .    2drop msg-g
b6e0: 72 6f 75 70 2d 6f 20 2e 6d 73 67 3a 2d 6c 6f 63  roup-o .msg:-loc
b6f0: 6b 0a 20 20 20 20 5b 3a 20 6e 65 74 32 6f 2d 62  k.    [: net2o-b
b700: 61 73 65 3a 6d 73 67 2d 75 6e 6c 6f 63 6b 20 3b  ase:msg-unlock ;
b710: 5d 20 73 65 6e 64 2d 61 76 61 6c 61 6e 63 68 65  ] send-avalanche
b720: 0a 3b 20 69 73 20 2f 75 6e 6c 6f 63 6b 0a 3a 6e  .; is /unlock.:n
b730: 6f 6e 61 6d 65 20 28 20 61 64 64 72 20 75 20 2d  oname ( addr u -
b740: 2d 20 29 0a 20 20 20 20 32 64 72 6f 70 20 6d 73  - ).    2drop ms
b750: 67 2d 67 72 6f 75 70 2d 6f 20 2e 6d 73 67 3a 3f  g-group-o .msg:?
b760: 6c 6f 63 6b 20 30 3d 20 49 46 20 20 2e 22 20 75  lock 0= IF  ." u
b770: 6e 22 20 20 54 48 45 4e 20 20 2e 22 20 6c 6f 63  n"  THEN  ." loc
b780: 6b 65 64 22 20 66 6f 72 74 68 3a 63 72 0a 3b 20  ked" forth:cr.; 
b790: 69 73 20 2f 6c 6f 63 6b 3f 0a 0a 24 31 30 30 20  is /lock?..$100 
b7a0: 62 75 66 66 65 72 3a 20 70 65 72 6d 63 68 61 72  buffer: permchar
b7b0: 3e 62 69 74 73 0a 6d 73 67 3a 72 6f 6c 65 2d 61  >bits.msg:role-a
b7c0: 64 6d 69 6e 23 20 6d 73 67 3a 6b 65 79 2d 61 64  dmin# msg:key-ad
b7d0: 6d 69 6e 23 20 6d 73 67 3a 6d 6f 64 65 72 61 74  min# msg:moderat
b7e0: 6f 72 23 20 6f 72 20 6f 72 20 27 61 27 20 70 65  or# or or 'a' pe
b7f0: 72 6d 63 68 61 72 3e 62 69 74 73 20 2b 20 63 21  rmchar>bits + c!
b800: 0a 6d 73 67 3a 72 6f 6c 65 2d 61 64 6d 69 6e 23  .msg:role-admin#
b810: 20 27 72 27 20 70 65 72 6d 63 68 61 72 3e 62 69   'r' permchar>bi
b820: 74 73 20 2b 20 63 21 0a 6d 73 67 3a 6b 65 79 2d  ts + c!.msg:key-
b830: 61 64 6d 69 6e 23 20 20 27 6b 27 20 70 65 72 6d  admin#  'k' perm
b840: 63 68 61 72 3e 62 69 74 73 20 2b 20 63 21 0a 6d  char>bits + c!.m
b850: 73 67 3a 6d 6f 64 65 72 61 74 6f 72 23 20 20 27  sg:moderator#  '
b860: 6d 27 20 70 65 72 6d 63 68 61 72 3e 62 69 74 73  m' permchar>bits
b870: 20 2b 20 63 21 0a 6d 73 67 3a 74 72 6f 6c 6c 23   + c!.msg:troll#
b880: 20 20 20 20 20 20 27 74 27 20 70 65 72 6d 63 68        't' permch
b890: 61 72 3e 62 69 74 73 20 2b 20 63 21 0a 3a 20 3e  ar>bits + c!.: >
b8a0: 70 65 72 6d 73 20 28 20 61 64 64 72 20 75 20 2d  perms ( addr u -
b8b0: 2d 20 70 65 72 6d 73 20 29 0a 20 20 20 20 30 20  - perms ).    0 
b8c0: 2d 72 6f 74 20 62 6f 75 6e 64 73 20 3f 44 4f 20  -rot bounds ?DO 
b8d0: 20 49 20 63 40 20 70 65 72 6d 63 68 61 72 3e 62   I c@ permchar>b
b8e0: 69 74 73 20 2b 20 63 40 0a 09 64 75 70 20 30 3d  its + c@..dup 0=
b8f0: 20 21 21 69 6e 76 2d 70 65 72 6d 21 21 20 6f 72   !!inv-perm!! or
b900: 20 20 4c 4f 4f 50 20 3b 0a 0a 3a 6e 6f 6e 61 6d    LOOP ;..:nonam
b910: 65 20 28 20 61 64 64 72 20 75 20 2d 2d 20 29 0a  e ( addr u -- ).
b920: 20 20 20 20 77 6f 72 64 2d 61 72 67 73 20 5b 3a      word-args [:
b930: 20 70 61 72 73 65 2d 6e 61 6d 65 20 3e 70 65 72   parse-name >per
b940: 6d 73 20 61 72 67 73 3e 6b 65 79 6c 69 73 74 20  ms args>keylist 
b950: 3b 5d 20 65 78 65 63 75 74 65 2d 70 61 72 73 69  ;] execute-parsi
b960: 6e 67 0a 20 20 20 20 5b 7b 3a 20 70 65 72 6d 20  ng.    [{: perm 
b970: 3a 7d 6c 0a 09 70 65 72 6d 20 6b 65 79 2d 6c 69  :}l..perm key-li
b980: 73 74 20 5b 3a 20 6b 65 79 7c 20 24 2c 20 64 75  st [: key| $, du
b990: 70 20 75 6c 69 74 2c 20 6e 65 74 32 6f 2d 62 61  p ulit, net2o-ba
b9a0: 73 65 3a 6d 73 67 2d 70 65 72 6d 73 20 3b 5d 20  se:msg-perms ;] 
b9b0: 24 5b 5d 6d 61 70 20 64 72 6f 70 0a 20 20 20 20  $[]map drop.    
b9c0: 3b 5d 20 73 65 6e 64 2d 61 76 61 6c 61 6e 63 68  ;] send-avalanch
b9d0: 65 0a 3b 20 69 73 20 2f 70 65 72 6d 73 0a 0a 3a  e.; is /perms..:
b9e0: 6e 6f 6e 61 6d 65 20 28 20 61 64 64 72 20 75 20  noname ( addr u 
b9f0: 2d 2d 20 29 0a 20 20 20 20 32 64 72 6f 70 20 2d  -- ).    2drop -
ba00: 31 20 5b 49 46 44 45 46 5d 20 61 6e 64 72 6f 69  1 [IFDEF] androi
ba10: 64 20 61 6e 64 72 6f 69 64 3a 6c 65 76 65 6c 23  d android:level#
ba20: 20 5b 45 4c 53 45 5d 20 6c 65 76 65 6c 23 20 5b   [ELSE] level# [
ba30: 54 48 45 4e 5d 20 2b 21 20 3b 20 69 73 20 2f 62  THEN] +! ; is /b
ba40: 79 65 0a 7d 73 63 6f 70 65 0a 0a 3a 20 3f 73 6c  ye.}scope..: ?sl
ba50: 61 73 68 20 28 20 61 64 64 72 20 75 20 2d 2d 20  ash ( addr u -- 
ba60: 61 64 64 72 20 75 20 66 6c 61 67 20 29 0a 20 20  addr u flag ).  
ba70: 20 20 6f 76 65 72 20 63 40 20 64 75 70 20 27 2f    over c@ dup '/
ba80: 27 20 3d 20 73 77 61 70 20 27 5c 27 20 3d 20 6f  ' = swap '\' = o
ba90: 72 20 3b 0a 0a 3a 20 64 6f 2d 63 68 61 74 2d 63  r ;..: do-chat-c
baa0: 6d 64 3f 20 28 20 61 64 64 72 20 75 20 2d 2d 20  md? ( addr u -- 
bab0: 74 20 2f 20 61 64 64 72 20 75 20 66 20 29 0a 20  t / addr u f ). 
bac0: 20 20 20 3f 73 6c 61 73 68 20 64 75 70 20 30 3d     ?slash dup 0=
bad0: 20 3f 45 58 49 54 20 20 64 72 6f 70 0a 20 20 20   ?EXIT  drop.   
bae0: 20 6f 76 65 72 20 27 2f 27 20 73 77 61 70 20 63   over '/' swap c
baf0: 21 20 62 6c 20 24 73 70 6c 69 74 20 32 73 77 61  ! bl $split 2swa
bb00: 70 0a 20 20 20 20 32 64 75 70 20 5b 27 5d 20 2f  p.    2dup ['] /
bb10: 63 68 61 74 20 3e 62 6f 64 79 20 66 69 6e 64 2d  chat >body find-
bb20: 6e 61 6d 65 2d 69 6e 0a 20 20 20 20 3f 64 75 70  name-in.    ?dup
bb30: 2d 49 46 20 20 6e 69 70 20 6e 69 70 20 6e 61 6d  -IF  nip nip nam
bb40: 65 3e 69 6e 74 20 65 78 65 63 75 74 65 20 74 72  e>int execute tr
bb50: 75 65 0a 20 20 20 20 45 4c 53 45 20 20 64 72 6f  ue.    ELSE  dro
bb60: 70 20 31 2d 20 2d 72 6f 74 20 2b 20 6f 76 65 72  p 1- -rot + over
bb70: 20 2d 20 66 61 6c 73 65 0a 20 20 20 20 54 48 45   - false.    THE
bb80: 4e 20 3b 0a 0a 30 20 56 61 6c 75 65 20 6c 61 73  N ;..0 Value las
bb90: 74 2d 3e 69 6e 0a 0a 3a 20 3f 66 6c 75 73 68 2d  t->in..: ?flush-
bba0: 74 65 78 74 20 28 20 61 64 64 72 20 2d 2d 20 29  text ( addr -- )
bbb0: 0a 20 20 20 20 6c 61 73 74 2d 3e 69 6e 20 3f 64  .    last->in ?d
bbc0: 75 70 2d 30 3d 2d 49 46 20 20 73 6f 75 72 63 65  up-0=-IF  source
bbd0: 20 64 72 6f 70 20 20 54 48 45 4e 0a 20 20 20 20   drop  THEN.    
bbe0: 74 75 63 6b 20 2d 20 64 75 70 20 49 46 0a 09 5c  tuck - dup IF..\
bbf0: 20 2e 22 20 74 65 78 74 3a 20 27 22 20 66 6f 72   ." text: '" for
bc00: 74 68 3a 74 79 70 65 20 27 27 27 20 66 6f 72 74  th:type ''' fort
bc10: 68 3a 65 6d 69 74 20 66 6f 72 74 68 3a 63 72 0a  h:emit forth:cr.
bc20: 09 24 2c 20 6d 73 67 2d 74 65 78 74 0a 20 20 20  .$, msg-text.   
bc30: 20 45 4c 53 45 20 20 32 64 72 6f 70 20 20 54 48   ELSE  2drop  TH
bc40: 45 4e 20 3b 0a 0a 3a 20 74 65 78 74 2d 72 65 63  EN ;..: text-rec
bc50: 20 28 20 61 64 64 72 20 75 20 2d 2d 20 29 0a 20   ( addr u -- ). 
bc60: 20 20 20 32 64 72 6f 70 20 5b 27 5d 20 6e 6f 6f     2drop ['] noo
bc70: 70 20 72 65 63 74 79 70 65 2d 6e 61 6d 65 20 3b  p rectype-name ;
bc80: 0a 3a 20 74 61 67 2d 72 65 63 20 28 20 61 64 64  .: tag-rec ( add
bc90: 72 20 75 20 2d 2d 20 29 0a 20 20 20 20 6f 76 65  r u -- ).    ove
bca0: 72 20 63 40 20 27 23 27 20 3d 20 49 46 0a 09 6f  r c@ '#' = IF..o
bcb0: 76 65 72 20 3f 66 6c 75 73 68 2d 74 65 78 74 20  ver ?flush-text 
bcc0: 32 64 75 70 20 2b 20 74 6f 20 6c 61 73 74 2d 3e  2dup + to last->
bcd0: 69 6e 0a 09 5b 3a 20 31 20 2f 73 74 72 69 6e 67  in..[: 1 /string
bce0: 0a 09 20 20 20 20 5c 20 2e 22 20 74 61 67 3a 20  ..    \ ." tag: 
bcf0: 27 22 20 66 6f 72 74 68 3a 74 79 70 65 20 27 27  '" forth:type ''
bd00: 27 20 66 6f 72 74 68 3a 65 6d 69 74 20 66 6f 72  ' forth:emit for
bd10: 74 68 3a 63 72 0a 09 20 20 20 20 24 2c 20 6d 73  th:cr..    $, ms
bd20: 67 2d 74 61 67 0a 09 3b 5d 20 72 65 63 74 79 70  g-tag..;] rectyp
bd30: 65 2d 6e 61 6d 65 0a 20 20 20 20 45 4c 53 45 20  e-name.    ELSE 
bd40: 20 32 64 72 6f 70 20 72 65 63 74 79 70 65 2d 6e   2drop rectype-n
bd50: 75 6c 6c 20 20 54 48 45 4e 20 3b 0a 3a 20 70 6b  ull  THEN ;.: pk
bd60: 2d 72 65 63 20 28 20 61 64 64 72 20 75 20 2d 2d  -rec ( addr u --
bd70: 20 29 0a 20 20 20 20 6f 76 65 72 20 63 40 20 27   ).    over c@ '
bd80: 40 27 20 3d 20 49 46 20 20 32 64 75 70 20 31 20  @' = IF  2dup 1 
bd90: 2f 73 74 72 69 6e 67 20 27 3a 27 20 2d 73 6b 69  /string ':' -ski
bda0: 70 20 6e 69 63 6b 3e 70 6b 0a 09 32 64 75 70 20  p nick>pk..2dup 
bdb0: 64 30 3d 20 49 46 20 20 32 64 72 6f 70 20 32 64  d0= IF  2drop 2d
bdc0: 72 6f 70 20 72 65 63 74 79 70 65 2d 6e 75 6c 6c  rop rectype-null
bdd0: 0a 09 45 4c 53 45 0a 09 20 20 20 20 32 3e 72 20  ..ELSE..    2>r 
bde0: 6f 76 65 72 20 3f 66 6c 75 73 68 2d 74 65 78 74  over ?flush-text
bdf0: 20 2b 20 74 6f 20 6c 61 73 74 2d 3e 69 6e 20 20   + to last->in  
be00: 32 72 3e 0a 09 20 20 20 20 5b 3a 0a 09 09 5c 20  2r>..    [:...\ 
be10: 2e 22 20 73 69 67 6e 61 6c 3a 20 27 22 20 38 35  ." signal: '" 85
be20: 74 79 70 65 20 27 27 27 20 66 6f 72 74 68 3a 65  type ''' forth:e
be30: 6d 69 74 20 66 6f 72 74 68 3a 63 72 0a 09 09 24  mit forth:cr...$
be40: 2c 20 6d 73 67 2d 73 69 67 6e 61 6c 0a 09 20 20  , msg-signal..  
be50: 20 20 3b 5d 20 72 65 63 74 79 70 65 2d 6e 61 6d    ;] rectype-nam
be60: 65 0a 09 54 48 45 4e 0a 20 20 20 20 45 4c 53 45  e..THEN.    ELSE
be70: 20 20 32 64 72 6f 70 20 72 65 63 74 79 70 65 2d    2drop rectype-
be80: 6e 75 6c 6c 20 20 54 48 45 4e 20 3b 0a 3a 20 63  null  THEN ;.: c
be90: 68 61 69 6e 2d 72 65 63 20 28 20 61 64 64 72 20  hain-rec ( addr 
bea0: 75 20 2d 2d 20 29 0a 20 20 20 20 6f 76 65 72 20  u -- ).    over 
beb0: 63 40 20 27 21 27 20 3d 20 49 46 0a 09 32 64 75  c@ '!' = IF..2du
bec0: 70 20 31 20 2f 73 74 72 69 6e 67 20 64 75 70 20  p 1 /string dup 
bed0: 30 3d 20 49 46 20 20 32 64 72 6f 70 20 32 64 72  0= IF  2drop 2dr
bee0: 6f 70 20 72 65 63 74 79 70 65 2d 6e 75 6c 6c 20  op rectype-null 
bef0: 20 45 58 49 54 20 20 54 48 45 4e 0a 09 73 6e 75   EXIT  THEN..snu
bf00: 6d 62 65 72 3f 0a 09 63 61 73 65 0a 09 20 20 20  mber?..case..   
bf10: 20 30 20 6f 66 20 20 65 6e 64 6f 66 0a 09 20 20   0 of  endof..  
bf20: 20 20 2d 31 20 6f 66 0a 09 09 6d 73 67 2d 67 72    -1 of...msg-gr
bf30: 6f 75 70 2d 6f 20 2e 6d 73 67 3a 6c 6f 67 5b 5d  oup-o .msg:log[]
bf40: 20 24 5b 5d 23 0a 09 09 6f 76 65 72 20 61 62 73   $[]#...over abs
bf50: 20 6f 76 65 72 20 75 3c 20 49 46 20 20 6f 76 65   over u< IF  ove
bf60: 72 20 30 3c 20 49 46 20 20 2b 20 20 45 4c 53 45  r 0< IF  +  ELSE
bf70: 20 20 64 72 6f 70 20 20 54 48 45 4e 0a 09 09 20    drop  THEN... 
bf80: 20 20 20 3e 72 20 6f 76 65 72 20 3f 66 6c 75 73     >r over ?flus
bf90: 68 2d 74 65 78 74 20 2b 20 74 6f 20 6c 61 73 74  h-text + to last
bfa0: 2d 3e 69 6e 20 20 72 3e 0a 09 09 20 20 20 20 5b  ->in  r>...    [
bfb0: 3a 20 6d 73 67 2d 67 72 6f 75 70 2d 6f 20 2e 6d  : msg-group-o .m
bfc0: 73 67 3a 6c 6f 67 5b 5d 20 24 5b 5d 40 20 63 68  sg:log[] $[]@ ch
bfd0: 61 69 6e 2c 20 3b 5d 0a 09 09 20 20 20 20 72 65  ain, ;]...    re
bfe0: 63 74 79 70 65 2d 6e 61 6d 65 20 20 45 58 49 54  ctype-name  EXIT
bff0: 20 20 54 48 45 4e 0a 09 20 20 20 20 65 6e 64 6f    THEN..    endo
c000: 66 0a 09 20 20 20 20 32 64 72 6f 70 0a 09 65 6e  f..    2drop..en
c010: 64 63 61 73 65 0a 20 20 20 20 54 48 45 4e 20 20  dcase.    THEN  
c020: 32 64 72 6f 70 20 20 72 65 63 74 79 70 65 2d 6e  2drop  rectype-n
c030: 75 6c 6c 20 20 3b 0a 3a 20 68 74 74 70 2d 72 65  ull  ;.: http-re
c040: 63 20 28 20 61 64 64 72 20 75 20 2d 2d 20 29 0a  c ( addr u -- ).
c050: 20 20 20 20 32 64 75 70 20 22 68 74 74 70 73 3a      2dup "https:
c060: 2f 2f 22 20 73 74 72 69 6e 67 2d 70 72 65 66 69  //" string-prefi
c070: 78 3f 20 3e 72 0a 20 20 20 20 32 64 75 70 20 22  x? >r.    2dup "
c080: 68 74 74 70 3a 2f 2f 22 20 73 74 72 69 6e 67 2d  http://" string-
c090: 70 72 65 66 69 78 3f 20 72 3e 20 6f 72 20 49 46  prefix? r> or IF
c0a0: 0a 09 6f 76 65 72 20 3f 66 6c 75 73 68 2d 74 65  ..over ?flush-te
c0b0: 78 74 20 32 64 75 70 20 2b 20 74 6f 20 6c 61 73  xt 2dup + to las
c0c0: 74 2d 3e 69 6e 0a 09 5b 3a 20 24 2c 20 6d 73 67  t->in..[: $, msg
c0d0: 2d 75 72 6c 20 3b 5d 20 72 65 63 74 79 70 65 2d  -url ;] rectype-
c0e0: 6e 61 6d 65 0a 20 20 20 20 45 4c 53 45 20 20 32  name.    ELSE  2
c0f0: 64 72 6f 70 20 72 65 63 74 79 70 65 2d 6e 75 6c  drop rectype-nul
c100: 6c 20 20 54 48 45 4e 20 3b 0a 0a 24 56 61 72 69  l  THEN ;..$Vari
c110: 61 62 6c 65 20 6d 73 67 2d 72 65 63 6f 67 6e 69  able msg-recogni
c120: 7a 65 72 0a 27 20 74 65 78 74 2d 72 65 63 20 27  zer.' text-rec '
c130: 20 68 74 74 70 2d 72 65 63 20 27 20 63 68 61 69   http-rec ' chai
c140: 6e 2d 72 65 63 20 27 20 74 61 67 2d 72 65 63 20  n-rec ' tag-rec 
c150: 27 20 70 6b 2d 72 65 63 20 35 20 6d 73 67 2d 72  ' pk-rec 5 msg-r
c160: 65 63 6f 67 6e 69 7a 65 72 20 73 65 74 2d 73 74  ecognizer set-st
c170: 61 63 6b 0a 0a 3a 20 70 61 72 73 65 2d 74 65 78  ack..: parse-tex
c180: 74 20 28 20 61 64 64 72 20 75 20 2d 2d 20 29 20  t ( addr u -- ) 
c190: 6c 61 73 74 23 20 3e 72 20 20 66 6f 72 74 68 2d  last# >r  forth-
c1a0: 72 65 63 6f 67 6e 69 7a 65 72 20 3e 72 0a 20 20  recognizer >r.  
c1b0: 20 20 30 20 74 6f 20 6c 61 73 74 2d 3e 69 6e 0a    0 to last->in.
c1c0: 20 20 20 20 6d 73 67 2d 72 65 63 6f 67 6e 69 7a      msg-recogniz
c1d0: 65 72 20 74 6f 20 66 6f 72 74 68 2d 72 65 63 6f  er to forth-reco
c1e0: 67 6e 69 7a 65 72 20 32 64 75 70 20 65 76 61 6c  gnizer 2dup eval
c1f0: 75 61 74 65 0a 20 20 20 20 6c 61 73 74 2d 3e 69  uate.    last->i
c200: 6e 20 49 46 20 20 2b 20 6c 61 73 74 2d 3e 69 6e  n IF  + last->in
c210: 20 74 75 63 6b 20 2d 20 20 54 48 45 4e 20 20 64   tuck -  THEN  d
c220: 75 70 20 49 46 0a 09 5c 20 2e 22 20 74 65 78 74  up IF..\ ." text
c230: 3a 20 27 22 20 66 6f 72 74 68 3a 74 79 70 65 20  : '" forth:type 
c240: 27 27 27 20 66 6f 72 74 68 3a 65 6d 69 74 20 66  ''' forth:emit f
c250: 6f 72 74 68 3a 63 72 0a 09 24 2c 20 6d 73 67 2d  orth:cr..$, msg-
c260: 74 65 78 74 0a 20 20 20 20 45 4c 53 45 20 20 32  text.    ELSE  2
c270: 64 72 6f 70 20 20 54 48 45 4e 0a 20 20 20 20 72  drop  THEN.    r
c280: 3e 20 74 6f 20 66 6f 72 74 68 2d 72 65 63 6f 67  > to forth-recog
c290: 6e 69 7a 65 72 20 20 72 3e 20 74 6f 20 6c 61 73  nizer  r> to las
c2a0: 74 23 20 3b 0a 0a 3a 20 61 76 61 6c 61 6e 63 68  t# ;..: avalanch
c2b0: 65 2d 74 65 78 74 20 28 20 61 64 64 72 20 75 20  e-text ( addr u 
c2c0: 2d 2d 20 29 0a 20 20 20 20 3e 75 74 66 38 24 20  -- ).    >utf8$ 
c2d0: 5b 27 5d 20 70 61 72 73 65 2d 74 65 78 74 20 73  ['] parse-text s
c2e0: 65 6e 64 2d 61 76 61 6c 61 6e 63 68 65 20 3b 0a  end-avalanche ;.
c2f0: 0a 70 72 65 76 69 6f 75 73 0a 0a 3a 20 6c 6f 61  .previous..: loa
c300: 64 2d 6d 73 67 6e 20 28 20 61 64 64 72 20 75 20  d-msgn ( addr u 
c310: 6e 20 2d 2d 20 29 0a 20 20 20 20 3e 72 20 6c 6f  n -- ).    >r lo
c320: 61 64 2d 6d 73 67 20 72 3e 20 64 69 73 70 6c 61  ad-msg r> displa
c330: 79 2d 6c 61 73 74 6e 20 3b 0a 0a 3a 20 2b 67 72  y-lastn ;..: +gr
c340: 6f 75 70 20 28 20 2d 2d 20 29 20 6d 73 67 2d 67  oup ( -- ) msg-g
c350: 72 6f 75 70 24 20 24 40 20 3e 67 72 6f 75 70 20  roup$ $@ >group 
c360: 2b 75 6e 69 71 75 65 2d 63 6f 6e 20 3b 0a 0a 3a  +unique-con ;..:
c370: 20 6d 73 67 2d 74 69 6d 65 6f 75 74 20 28 20 2d   msg-timeout ( -
c380: 2d 20 29 0a 20 20 20 20 70 61 63 6b 65 74 73 32  - ).    packets2
c390: 20 40 20 20 63 6f 6e 6e 65 63 74 65 64 2d 74 69   @  connected-ti
c3a0: 6d 65 6f 75 74 20 20 70 61 63 6b 65 74 73 32 20  meout  packets2 
c3b0: 40 20 3c 3e 0a 20 20 20 20 49 46 20 20 72 65 70  @ <>.    IF  rep
c3c0: 6c 79 28 20 2e 22 20 52 65 73 65 6e 64 20 74 6f  ly( ." Resend to
c3d0: 20 22 20 70 75 62 6b 65 79 20 24 40 20 6b 65 79   " pubkey $@ key
c3e0: 3e 6e 69 63 6b 20 74 79 70 65 20 63 72 20 29 0a  >nick type cr ).
c3f0: 09 74 69 6d 65 6f 75 74 2d 65 78 70 69 72 65 64  .timeout-expired
c400: 3f 20 49 46 0a 09 20 20 20 20 74 69 6d 65 6f 75  ? IF..    timeou
c410: 74 28 20 3c 65 72 72 3e 20 2e 22 20 45 78 63 65  t( <err> ." Exce
c420: 73 73 69 76 65 20 74 69 6d 65 6f 75 74 73 20 66  ssive timeouts f
c430: 72 6f 6d 20 22 0a 09 20 20 20 20 70 75 62 6b 65  rom "..    pubke
c440: 79 20 24 40 20 6b 65 79 3e 6e 69 63 6b 20 74 79  y $@ key>nick ty
c450: 70 65 20 2e 22 20 3a 20 22 0a 09 20 20 20 20 61  pe ." : "..    a
c460: 63 6b 40 20 2e 74 69 6d 65 6f 75 74 73 20 40 20  ck@ .timeouts @ 
c470: 2e 20 3c 64 65 66 61 75 6c 74 3e 20 63 72 20 29  . <default> cr )
c480: 0a 09 20 20 20 20 6d 73 67 2d 67 72 6f 75 70 24  ..    msg-group$
c490: 20 24 40 6c 65 6e 20 49 46 0a 09 09 6d 73 67 2d   $@len IF...msg-
c4a0: 67 72 6f 75 70 2d 6f 20 2e 6d 73 67 3a 6d 6f 64  group-o .msg:mod
c4b0: 65 20 64 75 70 20 40 20 6d 73 67 3a 6f 74 72 23  e dup @ msg:otr#
c4c0: 20 6f 72 20 73 77 61 70 0a 09 09 5b 3a 20 70 75   or swap...[: pu
c4d0: 62 6b 65 79 20 24 40 20 5b 27 5d 20 6c 65 66 74  bkey $@ ['] left
c4e0: 2c 20 73 65 6e 64 2d 61 76 61 6c 61 6e 63 68 65  , send-avalanche
c4f0: 20 3b 5d 20 21 77 72 61 70 70 65 72 0a 09 20 20   ;] !wrapper..  
c500: 20 20 54 48 45 4e 0a 09 20 20 20 20 6e 65 74 32    THEN..    net2
c510: 6f 3a 64 69 73 70 6f 73 65 2d 63 6f 6e 74 65 78  o:dispose-contex
c520: 74 0a 09 20 20 20 20 45 58 49 54 0a 09 54 48 45  t..    EXIT..THE
c530: 4e 0a 20 20 20 20 45 4c 53 45 20 20 65 78 70 65  N.    ELSE  expe
c540: 63 74 65 64 40 20 75 3c 3d 20 49 46 20 20 2d 74  cted@ u<= IF  -t
c550: 69 6d 65 6f 75 74 20 20 54 48 45 4e 20 20 54 48  imeout  THEN  TH
c560: 45 4e 20 3b 0a 0a 3a 20 2b 72 65 73 65 6e 64 2d  EN ;..: +resend-
c570: 6d 73 67 20 28 20 2d 2d 20 29 0a 20 20 20 20 5b  msg ( -- ).    [
c580: 27 5d 20 6d 73 67 2d 74 69 6d 65 6f 75 74 20 69  '] msg-timeout i
c590: 73 20 74 69 6d 65 6f 75 74 2d 78 74 20 20 6f 2b  s timeout-xt  o+
c5a0: 74 69 6d 65 6f 75 74 20 3b 0a 0a 24 42 20 24 45  timeout ;..$B $E
c5b0: 20 32 56 61 6c 75 65 20 63 68 61 74 2d 62 75 66   2Value chat-buf
c5c0: 73 23 0a 0a 3a 20 2b 63 68 61 74 2d 63 6f 6e 74  s#..: +chat-cont
c5d0: 72 6f 6c 20 28 20 2d 2d 20 29 0a 20 20 20 20 2b  rol ( -- ).    +
c5e0: 72 65 73 65 6e 64 2d 6d 73 67 20 2b 66 6c 6f 77  resend-msg +flow
c5f0: 2d 63 6f 6e 74 72 6f 6c 20 3b 0a 0a 3a 20 63 68  -control ;..: ch
c600: 61 74 23 2d 63 6f 6e 6e 65 63 74 3f 20 28 20 61  at#-connect? ( a
c610: 64 64 72 20 75 20 62 75 66 31 20 62 75 66 32 20  ddr u buf1 buf2 
c620: 2d 2d 2d 20 66 6c 61 67 20 29 0a 20 20 20 20 70  --- flag ).    p
c630: 6b 2d 63 6f 6e 6e 65 63 74 3f 20 64 75 70 20 49  k-connect? dup I
c640: 46 20 20 63 6f 6e 6e 65 63 74 69 6f 6e 20 3e 6f  F  connection >o
c650: 20 72 64 72 6f 70 20 2b 63 68 61 74 2d 63 6f 6e   rdrop +chat-con
c660: 74 72 6f 6c 20 20 2b 67 72 6f 75 70 20 20 54 48  trol  +group  TH
c670: 45 4e 20 3b 0a 0a 3a 20 63 68 61 74 2d 63 6f 6e  EN ;..: chat-con
c680: 6e 65 63 74 20 28 20 61 64 64 72 20 75 20 2d 2d  nect ( addr u --
c690: 20 29 0a 20 20 20 20 63 68 61 74 2d 62 75 66 73   ).    chat-bufs
c6a0: 23 20 63 68 61 74 23 2d 63 6f 6e 6e 65 63 74 3f  # chat#-connect?
c6b0: 20 49 46 20 20 67 72 65 65 74 20 20 54 48 45 4e   IF  greet  THEN
c6c0: 20 3b 0a 0a 3a 20 6b 65 79 2d 63 74 72 6c 62 69   ;..: key-ctrlbi
c6d0: 74 20 28 20 2d 2d 20 6e 20 29 0a 20 20 20 20 5c  t ( -- n ).    \
c6e0: 47 20 72 65 74 75 72 6e 20 61 20 62 69 74 20 6d  G return a bit m
c6f0: 61 73 6b 20 66 6f 72 20 74 68 65 20 63 6f 6e 74  ask for the cont
c700: 72 6f 6c 20 6b 65 79 20 70 72 65 73 73 65 64 0a  rol key pressed.
c710: 20 20 20 20 31 20 6b 65 79 20 64 75 70 20 62 6c      1 key dup bl
c720: 20 3c 20 3e 72 20 6c 73 68 69 66 74 20 72 3e 20   < >r lshift r> 
c730: 61 6e 64 20 3b 0a 0a 3a 20 77 61 69 74 2d 6b 65  and ;..: wait-ke
c740: 79 20 28 20 2d 2d 20 29 0a 20 20 20 20 42 45 47  y ( -- ).    BEG
c750: 49 4e 20 20 6b 65 79 2d 63 74 72 6c 62 69 74 20  IN  key-ctrlbit 
c760: 5b 20 31 20 63 74 72 6c 20 4c 20 6c 73 68 69 66  [ 1 ctrl L lshif
c770: 74 20 31 20 63 74 72 6c 20 5a 20 6c 73 68 69 66  t 1 ctrl Z lshif
c780: 74 20 6f 72 20 5d 4c 0a 20 20 20 20 61 6e 64 20  t or ]L.    and 
c790: 30 3d 20 20 55 4e 54 49 4c 20 3b 0a 0a 3a 20 63  0=  UNTIL ;..: c
c7a0: 68 61 74 73 23 20 28 20 2d 2d 20 6e 20 29 0a 20  hats# ( -- n ). 
c7b0: 20 20 20 30 20 5b 3a 20 6d 73 67 3a 70 65 65 72     0 [: msg:peer
c7c0: 73 5b 5d 20 24 5b 5d 23 20 31 20 6d 61 78 20 2b  s[] $[]# 1 max +
c7d0: 20 3b 5d 20 67 72 6f 75 70 23 6d 61 70 20 3b 0a   ;] group#map ;.
c7e0: 0a 3a 20 77 61 69 74 2d 63 68 61 74 20 28 20 2d  .: wait-chat ( -
c7f0: 2d 20 29 0a 20 20 20 20 63 68 61 74 2d 6b 65 79  - ).    chat-key
c800: 73 20 5b 3a 20 40 2f 32 20 64 75 70 20 30 3d 20  s [: @/2 dup 0= 
c810: 49 46 20 20 32 64 72 6f 70 20 20 45 58 49 54 20  IF  2drop  EXIT 
c820: 20 54 48 45 4e 0a 20 20 20 20 20 20 32 64 75 70   THEN.      2dup
c830: 20 6b 65 79 73 69 7a 65 32 20 73 61 66 65 2f 73   keysize2 safe/s
c840: 74 72 69 6e 67 20 74 75 63 6b 20 3c 69 6e 66 6f  tring tuck <info
c850: 3e 20 74 79 70 65 20 49 46 20 27 2e 27 20 65 6d  > type IF '.' em
c860: 69 74 20 20 54 48 45 4e 0a 20 20 20 20 20 20 2e  it  THEN.      .
c870: 6b 65 79 2d 69 64 20 73 70 61 63 65 20 3b 5d 20  key-id space ;] 
c880: 24 5b 5d 6d 61 70 0a 20 20 20 20 2e 22 20 69 73  $[]map.    ." is
c890: 20 6e 6f 74 20 6f 6e 6c 69 6e 65 2e 20 70 72 65   not online. pre
c8a0: 73 73 20 6b 65 79 20 74 6f 20 72 65 63 68 65 63  ss key to rechec
c8b0: 6b 2e 22 0a 20 20 20 20 5b 3a 20 30 20 74 6f 20  k.".    [: 0 to 
c8c0: 63 6f 6e 6e 65 63 74 69 6f 6e 20 2d 35 36 20 74  connection -56 t
c8d0: 68 72 6f 77 20 3b 5d 20 69 73 20 64 6f 2d 64 69  hrow ;] is do-di
c8e0: 73 63 6f 6e 6e 65 63 74 0a 20 20 20 20 5b 3a 20  sconnect.    [: 
c8f0: 66 61 6c 73 65 20 63 68 61 74 2d 6b 65 79 73 20  false chat-keys 
c900: 5b 3a 20 40 2f 32 20 6b 65 79 7c 20 70 75 62 6b  [: @/2 key| pubk
c910: 65 79 20 24 40 20 6b 65 79 7c 20 73 74 72 3d 20  ey $@ key| str= 
c920: 6f 72 20 3b 5d 20 24 5b 5d 6d 61 70 0a 09 49 46  or ;] $[]map..IF
c930: 20 20 62 6c 20 69 6e 73 6b 65 79 20 20 54 48 45    bl inskey  THE
c940: 4e 20 20 75 70 40 20 77 61 69 74 2d 74 61 73 6b  N  up@ wait-task
c950: 20 21 20 3b 5d 20 69 73 20 64 6f 2d 63 6f 6e 6e   ! ;] is do-conn
c960: 65 63 74 0a 20 20 20 20 77 61 69 74 2d 6b 65 79  ect.    wait-key
c970: 20 63 72 20 5b 3a 20 75 70 40 20 77 61 69 74 2d   cr [: up@ wait-
c980: 74 61 73 6b 20 21 20 3b 5d 20 49 53 20 64 6f 2d  task ! ;] IS do-
c990: 63 6f 6e 6e 65 63 74 20 3b 0a 0a 3a 20 73 65 61  connect ;..: sea
c9a0: 72 63 68 2d 63 6f 6e 6e 65 63 74 20 28 20 6b 65  rch-connect ( ke
c9b0: 79 20 75 20 2d 2d 20 6f 2f 30 20 29 20 20 6b 65  y u -- o/0 )  ke
c9c0: 79 7c 0a 20 20 20 20 30 20 5b 3a 20 64 72 6f 70  y|.    0 [: drop
c9d0: 20 32 64 75 70 20 70 75 62 6b 65 79 20 24 40 20   2dup pubkey $@ 
c9e0: 6b 65 79 7c 20 73 74 72 3d 20 6f 20 61 6e 64 20  key| str= o and 
c9f0: 20 64 75 70 20 30 3d 20 3b 5d 20 73 65 61 72 63   dup 0= ;] searc
ca00: 68 2d 63 6f 6e 74 65 78 74 0a 20 20 20 20 6e 69  h-context.    ni
ca10: 70 20 6e 69 70 20 20 64 75 70 20 74 6f 20 63 6f  p nip  dup to co
ca20: 6e 6e 65 63 74 69 6f 6e 20 3b 0a 0a 3a 20 73 65  nnection ;..: se
ca30: 61 72 63 68 2d 70 65 65 72 20 28 20 2d 2d 20 63  arch-peer ( -- c
ca40: 68 61 74 20 29 0a 20 20 20 20 66 61 6c 73 65 20  hat ).    false 
ca50: 63 68 61 74 2d 6b 65 79 73 0a 20 20 20 20 5b 3a  chat-keys.    [:
ca60: 20 40 2f 32 20 6b 65 79 7c 20 72 6f 74 20 64 75   @/2 key| rot du
ca70: 70 20 30 3d 20 49 46 20 64 72 6f 70 20 73 65 61  p 0= IF drop sea
ca80: 72 63 68 2d 63 6f 6e 6e 65 63 74 0a 20 20 20 20  rch-connect.    
ca90: 20 20 45 4c 53 45 20 20 6e 69 70 20 6e 69 70 20    ELSE  nip nip 
caa0: 20 54 48 45 4e 20 3b 5d 20 24 5b 5d 6d 61 70 20   THEN ;] $[]map 
cab0: 3b 0a 0a 3a 20 6b 65 79 3e 67 72 6f 75 70 20 28  ;..: key>group (
cac0: 20 61 64 64 72 20 75 20 2d 2d 20 70 6b 20 75 20   addr u -- pk u 
cad0: 29 0a 20 20 20 20 40 2f 20 32 73 77 61 70 20 74  ).    @/ 2swap t
cae0: 75 63 6b 20 6d 73 67 2d 67 72 6f 75 70 24 20 24  uck msg-group$ $
caf0: 21 20 20 30 3d 0a 20 20 20 20 49 46 20 20 32 64  !  0=.    IF  2d
cb00: 75 70 20 6b 65 79 7c 20 6d 73 67 2d 67 72 6f 75  up key| msg-grou
cb10: 70 24 20 24 21 20 20 54 48 45 4e 20 3b 20 5c 20  p$ $!  THEN ; \ 
cb20: 31 3a 31 20 63 68 61 74 2d 67 72 6f 75 70 3d 6b  1:1 chat-group=k
cb30: 65 79 0a 0a 3a 20 3f 6c 6f 61 64 2d 6d 73 67 6e  ey..: ?load-msgn
cb40: 20 28 20 2d 2d 20 29 0a 20 20 20 20 6d 73 67 2d   ( -- ).    msg-
cb50: 67 72 6f 75 70 24 20 24 40 20 3e 67 72 6f 75 70  group$ $@ >group
cb60: 20 6d 73 67 2d 67 72 6f 75 70 2d 6f 20 2e 6d 73   msg-group-o .ms
cb70: 67 3a 6c 6f 67 5b 5d 20 24 40 6c 65 6e 20 30 3d  g:log[] $@len 0=
cb80: 20 49 46 0a 09 6d 73 67 2d 67 72 6f 75 70 24 20   IF..msg-group$ 
cb90: 24 40 20 72 6f 77 73 20 6c 6f 61 64 2d 6d 73 67  $@ rows load-msg
cba0: 6e 20 20 54 48 45 4e 20 3b 0a 0a 3a 20 63 68 61  n  THEN ;..: cha
cbb0: 74 2d 63 6f 6e 6e 65 63 74 73 20 28 20 2d 2d 20  t-connects ( -- 
cbc0: 29 0a 20 20 20 20 63 68 61 74 2d 6b 65 79 73 20  ).    chat-keys 
cbd0: 5b 3a 20 6b 65 79 3e 67 72 6f 75 70 20 3f 6c 6f  [: key>group ?lo
cbe0: 61 64 2d 6d 73 67 6e 0a 20 20 20 20 20 20 64 75  ad-msgn.      du
cbf0: 70 20 30 3d 20 49 46 20 20 32 64 72 6f 70 20 6d  p 0= IF  2drop m
cc00: 73 67 2d 67 72 6f 75 70 24 20 24 40 20 3e 67 72  sg-group$ $@ >gr
cc10: 6f 75 70 20 20 45 58 49 54 20 20 54 48 45 4e 0a  oup  EXIT  THEN.
cc20: 20 20 20 20 20 20 32 64 75 70 20 73 65 61 72 63        2dup searc
cc30: 68 2d 63 6f 6e 6e 65 63 74 20 3f 64 75 70 2d 49  h-connect ?dup-I
cc40: 46 20 20 3e 6f 20 2b 67 72 6f 75 70 20 67 72 65  F  >o +group gre
cc50: 65 74 20 6f 3e 20 32 64 72 6f 70 20 45 58 49 54  et o> 2drop EXIT
cc60: 20 20 54 48 45 4e 0a 20 20 20 20 20 20 32 64 75    THEN.      2du
cc70: 70 20 70 6b 2d 70 65 65 6b 3f 20 20 49 46 20 20  p pk-peek?  IF  
cc80: 63 68 61 74 2d 63 6f 6e 6e 65 63 74 20 20 45 4c  chat-connect  EL
cc90: 53 45 20 20 32 64 72 6f 70 20 20 54 48 45 4e 20  SE  2drop  THEN 
cca0: 3b 5d 20 24 5b 5d 6d 61 70 20 3b 0a 0a 3a 20 3f  ;] $[]map ;..: ?
ccb0: 77 61 69 74 2d 63 68 61 74 20 28 20 2d 2d 20 61  wait-chat ( -- a
ccc0: 64 64 72 20 75 20 29 20 23 30 2e 20 2f 63 68 61  ddr u ) #0. /cha
ccd0: 74 3a 2f 63 68 61 74 73 0a 20 20 20 20 42 45 47  t:/chats.    BEG
cce0: 49 4e 20 20 63 68 61 74 73 23 20 30 3d 20 57 48  IN  chats# 0= WH
ccf0: 49 4c 45 20 20 77 61 69 74 2d 63 68 61 74 20 63  ILE  wait-chat c
cd00: 68 61 74 2d 63 6f 6e 6e 65 63 74 73 20 20 52 45  hat-connects  RE
cd10: 50 45 41 54 0a 20 20 20 20 6d 73 67 2d 67 72 6f  PEAT.    msg-gro
cd20: 75 70 24 20 24 40 20 3b 20 5c 20 73 74 75 62 0a  up$ $@ ; \ stub.
cd30: 0a 73 63 6f 70 65 7b 20 2f 63 68 61 74 0a 3a 6e  .scope{ /chat.:n
cd40: 6f 6e 61 6d 65 20 28 20 61 64 64 72 20 75 20 2d  oname ( addr u -
cd50: 2d 20 29 0a 20 20 20 20 63 68 61 74 2d 6b 65 79  - ).    chat-key
cd60: 73 20 24 5b 5d 6f 66 66 20 6e 69 63 6b 3e 63 68  s $[]off nick>ch
cd70: 61 74 20 30 20 63 68 61 74 2d 6b 65 79 73 20 24  at 0 chat-keys $
cd80: 5b 5d 40 20 6b 65 79 3e 67 72 6f 75 70 0a 20 20  []@ key>group.  
cd90: 20 20 6d 73 67 2d 67 72 6f 75 70 24 20 24 40 20    msg-group$ $@ 
cda0: 3e 67 72 6f 75 70 20 6d 73 67 2d 67 72 6f 75 70  >group msg-group
cdb0: 2d 6f 20 2e 6d 73 67 3a 70 65 65 72 73 5b 5d 20  -o .msg:peers[] 
cdc0: 24 40 20 64 75 70 20 30 3d 20 49 46 20 20 32 64  $@ dup 0= IF  2d
cdd0: 72 6f 70 0a 09 6e 69 70 20 49 46 20 20 63 68 61  rop..nip IF  cha
cde0: 74 2d 63 6f 6e 6e 65 63 74 73 0a 09 45 4c 53 45  t-connects..ELSE
cdf0: 20 20 2e 22 20 54 68 61 74 20 63 68 61 74 20 69    ." That chat i
ce00: 73 6e 27 74 20 61 63 74 69 76 65 22 20 66 6f 72  sn't active" for
ce10: 74 68 3a 63 72 20 20 54 48 45 4e 0a 20 20 20 20  th:cr  THEN.    
ce20: 45 4c 53 45 0a 09 62 6f 75 6e 64 73 20 3f 44 4f  ELSE..bounds ?DO
ce30: 20 20 32 64 75 70 20 49 20 40 20 2e 70 75 62 6b    2dup I @ .pubk
ce40: 65 79 20 24 40 20 6b 65 79 32 7c 20 73 74 72 3d  ey $@ key2| str=
ce50: 20 30 3d 20 57 48 49 4c 45 20 20 63 65 6c 6c 20   0= WHILE  cell 
ce60: 2b 4c 4f 4f 50 0a 09 20 20 20 20 32 64 72 6f 70  +LOOP..    2drop
ce70: 20 63 68 61 74 2d 63 6f 6e 6e 65 63 74 73 20 20   chat-connects  
ce80: 45 4c 53 45 20 20 55 4e 4c 4f 4f 50 20 32 64 72  ELSE  UNLOOP 2dr
ce90: 6f 70 20 54 48 45 4e 0a 20 20 20 20 54 48 45 4e  op THEN.    THEN
cea0: 20 20 23 30 2e 20 2f 63 68 61 74 73 20 3b 20 69    #0. /chats ; i
ceb0: 73 20 2f 63 68 61 74 0a 7d 73 63 6f 70 65 0a 0a  s /chat.}scope..
cec0: 61 6c 73 6f 20 6e 65 74 32 6f 2d 62 61 73 65 0a  also net2o-base.
ced0: 3a 20 70 75 6e 63 68 2d 61 64 64 72 2d 69 6e 64  : punch-addr-ind
cee0: 40 20 28 20 2d 2d 20 6f 20 29 0a 20 20 20 20 70  @ ( -- o ).    p
cef0: 75 6e 63 68 2d 61 64 64 72 73 20 24 5b 5d 23 20  unch-addrs $[]# 
cf00: 30 20 55 2b 44 4f 0a 09 49 20 70 75 6e 63 68 2d  0 U+DO..I punch-
cf10: 61 64 64 72 73 20 24 5b 5d 20 40 20 2e 68 6f 73  addrs $[] @ .hos
cf20: 74 3a 72 6f 75 74 65 20 24 40 6c 65 6e 20 49 46  t:route $@len IF
cf30: 0a 09 20 20 20 20 49 20 70 75 6e 63 68 2d 61 64  ..    I punch-ad
cf40: 64 72 73 20 24 5b 5d 20 40 20 75 6e 6c 6f 6f 70  drs $[] @ unloop
cf50: 20 20 45 58 49 54 0a 09 54 48 45 4e 0a 20 20 20    EXIT..THEN.   
cf60: 20 4c 4f 4f 50 20 20 30 20 70 75 6e 63 68 2d 61   LOOP  0 punch-a
cf70: 64 64 72 73 20 24 5b 5d 20 40 20 3b 0a 3a 20 72  ddrs $[] @ ;.: r
cf80: 65 63 6f 6e 6e 65 63 74 2c 20 28 20 6f 3a 63 6f  econnect, ( o:co
cf90: 6e 6e 65 63 74 69 6f 6e 20 2d 2d 20 29 0a 20 20  nnection -- ).  
cfa0: 20 20 5b 3a 20 70 75 6e 63 68 2d 61 64 64 72 2d    [: punch-addr-
cfb0: 69 6e 64 40 20 6f 3e 61 64 64 72 20 66 6f 72 74  ind@ o>addr fort
cfc0: 68 3a 74 79 70 65 0a 20 20 20 20 20 20 70 75 62  h:type.      pub
cfd0: 6b 65 79 20 24 40 20 6b 65 79 7c 20 74 75 63 6b  key $@ key| tuck
cfe0: 20 66 6f 72 74 68 3a 74 79 70 65 20 66 6f 72 74   forth:type fort
cff0: 68 3a 65 6d 69 74 20 3b 5d 20 24 74 6d 70 0a 20  h:emit ;] $tmp. 
d000: 20 20 20 72 65 63 6f 6e 6e 65 63 74 28 20 2e 22     reconnect( ."
d010: 20 73 65 6e 64 20 72 65 63 6f 6e 6e 65 63 74 3a   send reconnect:
d020: 20 22 20 32 64 75 70 20 32 64 75 70 20 2b 20 31   " 2dup 2dup + 1
d030: 2d 20 63 40 20 31 2b 20 2d 20 2e 61 64 64 72 24  - c@ 1+ - .addr$
d040: 20 66 6f 72 74 68 3a 63 72 20 29 0a 20 20 20 20   forth:cr ).    
d050: 24 2c 20 6d 73 67 2d 72 65 63 6f 6e 6e 65 63 74  $, msg-reconnect
d060: 20 3b 0a 0a 3a 20 72 65 63 6f 6e 6e 65 63 74 73   ;..: reconnects
d070: 2c 20 28 20 6f 3a 67 72 6f 75 70 20 2d 2d 20 29  , ( o:group -- )
d080: 0a 20 20 20 20 6d 73 67 2d 67 72 6f 75 70 2d 6f  .    msg-group-o
d090: 20 2e 6d 73 67 3a 70 65 65 72 73 5b 5d 20 24 40   .msg:peers[] $@
d0a0: 20 63 65 6c 6c 20 73 61 66 65 2f 73 74 72 69 6e   cell safe/strin
d0b0: 67 20 62 6f 75 6e 64 73 20 55 2b 44 4f 0a 09 49  g bounds U+DO..I
d0c0: 20 40 20 2e 72 65 63 6f 6e 6e 65 63 74 2c 0a 20   @ .reconnect,. 
d0d0: 20 20 20 63 65 6c 6c 20 2b 4c 4f 4f 50 20 3b 0a     cell +LOOP ;.
d0e0: 0a 3a 20 73 65 6e 64 2d 72 65 63 6f 6e 6e 65 63  .: send-reconnec
d0f0: 74 73 20 28 20 6f 3a 67 72 6f 75 70 20 2d 2d 20  ts ( o:group -- 
d100: 29 0a 20 20 20 20 6e 65 74 32 6f 2d 63 6f 64 65  ).    net2o-code
d110: 20 65 78 70 65 63 74 2d 6d 73 67 0a 20 20 20 20   expect-msg.    
d120: 5b 3a 20 20 6d 73 67 2d 67 72 6f 75 70 2d 6f 20  [:  msg-group-o 
d130: 2e 6d 73 67 3a 6e 61 6d 65 24 20 3f 64 65 73 74  .msg:name$ ?dest
d140: 70 6b 20 24 2c 20 6d 73 67 2d 6c 65 61 76 65 0a  pk $, msg-leave.
d150: 09 3c 6d 73 67 20 6d 73 67 2d 73 74 61 72 74 20  .<msg msg-start 
d160: 22 6c 65 66 74 22 20 24 2c 20 6d 73 67 2d 61 63  "left" $, msg-ac
d170: 74 69 6f 6e 20 6d 73 67 2d 6f 74 72 3e 0a 09 72  tion msg-otr>..r
d180: 65 63 6f 6e 6e 65 63 74 73 2c 20 3b 5d 20 5b 6d  econnects, ;] [m
d190: 73 67 2c 5d 0a 20 20 20 20 65 6e 64 2d 63 6f 64  sg,].    end-cod
d1a0: 65 7c 20 3b 0a 0a 3a 20 73 65 6e 64 2d 72 65 63  e| ;..: send-rec
d1b0: 6f 6e 6e 65 63 74 31 20 28 20 6f 3a 67 72 6f 75  onnect1 ( o:grou
d1c0: 70 20 2d 2d 20 29 0a 20 20 20 20 6e 65 74 32 6f  p -- ).    net2o
d1d0: 2d 63 6f 64 65 20 65 78 70 65 63 74 2d 6d 73 67  -code expect-msg
d1e0: 0a 20 20 20 20 5b 3a 20 20 6d 73 67 3a 6e 61 6d  .    [:  msg:nam
d1f0: 65 24 20 3f 64 65 73 74 70 6b 20 24 2c 20 6d 73  e$ ?destpk $, ms
d200: 67 2d 6c 65 61 76 65 0a 09 3c 6d 73 67 20 6d 73  g-leave..<msg ms
d210: 67 2d 73 74 61 72 74 20 22 6c 65 66 74 22 20 24  g-start "left" $
d220: 2c 20 6d 73 67 2d 61 63 74 69 6f 6e 20 6d 73 67  , msg-action msg
d230: 2d 6f 74 72 3e 0a 09 2e 72 65 63 6f 6e 6e 65 63  -otr>...reconnec
d240: 74 2c 20 3b 5d 20 5b 6d 73 67 2c 5d 0a 20 20 20  t, ;] [msg,].   
d250: 20 65 6e 64 2d 63 6f 64 65 7c 20 3b 0a 70 72 65   end-code| ;.pre
d260: 76 69 6f 75 73 0a 0a 3a 20 73 65 6e 64 2d 72 65  vious..: send-re
d270: 63 6f 6e 6e 65 63 74 2d 78 74 20 28 20 6f 3a 67  connect-xt ( o:g
d280: 72 6f 75 70 20 78 74 20 2d 2d 20 29 20 7b 20 78  roup xt -- ) { x
d290: 74 3a 20 78 74 20 7d 0a 20 20 20 20 6d 73 67 3a  t: xt }.    msg:
d2a0: 70 65 65 72 73 5b 5d 20 24 40 0a 20 20 20 20 63  peers[] $@.    c
d2b0: 61 73 65 0a 09 30 20 20 20 20 6f 66 20 20 64 72  ase..0    of  dr
d2c0: 6f 70 20 20 65 6e 64 6f 66 0a 09 63 65 6c 6c 20  op  endof..cell 
d2d0: 6f 66 20 20 40 20 3e 6f 20 6f 20 74 6f 20 63 6f  of  @ >o o to co
d2e0: 6e 6e 65 63 74 69 6f 6e 20 78 74 20 6f 3e 20 20  nnection xt o>  
d2f0: 65 6e 64 6f 66 0a 09 64 72 6f 70 20 40 20 3e 6f  endof..drop @ >o
d300: 20 6f 20 74 6f 20 63 6f 6e 6e 65 63 74 69 6f 6e   o to connection
d310: 20 20 73 65 6e 64 2d 72 65 63 6f 6e 6e 65 63 74    send-reconnect
d320: 73 20 6f 3e 0a 09 30 0a 20 20 20 20 65 6e 64 63  s o>..0.    endc
d330: 61 73 65 20 3b 0a 3a 20 73 65 6e 64 2d 72 65 63  ase ;.: send-rec
d340: 6f 6e 6e 65 63 74 20 28 20 6f 3a 67 72 6f 75 70  onnect ( o:group
d350: 20 2d 2d 20 29 0a 20 20 20 20 5b 27 5d 20 73 65   -- ).    ['] se
d360: 6e 64 2d 6c 65 61 76 65 20 73 65 6e 64 2d 72 65  nd-leave send-re
d370: 63 6f 6e 6e 65 63 74 2d 78 74 20 3b 0a 3a 20 73  connect-xt ;.: s
d380: 65 6e 64 2d 73 69 6c 65 6e 74 2d 72 65 63 6f 6e  end-silent-recon
d390: 6e 65 63 74 20 28 20 6f 3a 67 72 6f 75 70 20 2d  nect ( o:group -
d3a0: 2d 20 29 0a 20 20 20 20 5b 27 5d 20 73 65 6e 64  - ).    ['] send
d3b0: 2d 73 69 6c 65 6e 74 2d 6c 65 61 76 65 20 73 65  -silent-leave se
d3c0: 6e 64 2d 72 65 63 6f 6e 6e 65 63 74 2d 78 74 20  nd-reconnect-xt 
d3d0: 3b 0a 0a 3a 20 64 69 73 63 6f 6e 6e 65 63 74 2d  ;..: disconnect-
d3e0: 67 72 6f 75 70 20 28 20 6f 3a 67 72 6f 75 70 20  group ( o:group 
d3f0: 2d 2d 20 29 0a 20 20 20 20 6d 73 67 3a 70 65 65  -- ).    msg:pee
d400: 72 73 5b 5d 20 67 65 74 2d 73 74 61 63 6b 20 30  rs[] get-stack 0
d410: 20 3f 44 4f 20 20 3e 6f 20 6f 20 74 6f 20 63 6f   ?DO  >o o to co
d420: 6e 6e 65 63 74 69 6f 6e 0a 09 64 69 73 63 6f 6e  nnection..discon
d430: 6e 65 63 74 2d 6d 65 20 6f 3e 0a 20 20 20 20 4c  nect-me o>.    L
d440: 4f 4f 50 20 3b 0a 3a 20 64 69 73 63 6f 6e 6e 65  OOP ;.: disconne
d450: 63 74 2d 61 6c 6c 20 28 20 6f 3a 67 72 6f 75 70  ct-all ( o:group
d460: 20 2d 2d 20 29 0a 20 20 20 20 6d 73 67 3a 70 65   -- ).    msg:pe
d470: 65 72 73 5b 5d 20 67 65 74 2d 73 74 61 63 6b 20  ers[] get-stack 
d480: 30 20 3f 44 4f 20 20 3e 6f 20 6f 20 74 6f 20 63  0 ?DO  >o o to c
d490: 6f 6e 6e 65 63 74 69 6f 6e 0a 09 73 65 6e 64 2d  onnection..send-
d4a0: 6c 65 61 76 65 20 20 64 69 73 63 6f 6e 6e 65 63  leave  disconnec
d4b0: 74 2d 6d 65 20 6f 3e 0a 20 20 20 20 4c 4f 4f 50  t-me o>.    LOOP
d4c0: 20 3b 0a 0a 3a 20 6c 65 61 76 65 2d 63 68 61 74   ;..: leave-chat
d4d0: 20 28 20 6f 3a 67 72 6f 75 70 20 2d 2d 20 29 0a   ( o:group -- ).
d4e0: 20 20 20 20 73 65 6e 64 2d 72 65 63 6f 6e 6e 65      send-reconne
d4f0: 63 74 20 64 69 73 63 6f 6e 6e 65 63 74 2d 67 72  ct disconnect-gr
d500: 6f 75 70 20 3b 0a 3a 20 73 69 6c 65 6e 74 2d 6c  oup ;.: silent-l
d510: 65 61 76 65 2d 63 68 61 74 20 28 20 6f 3a 67 72  eave-chat ( o:gr
d520: 6f 75 70 20 2d 2d 20 29 0a 20 20 20 20 73 65 6e  oup -- ).    sen
d530: 64 2d 73 69 6c 65 6e 74 2d 72 65 63 6f 6e 6e 65  d-silent-reconne
d540: 63 74 20 64 69 73 63 6f 6e 6e 65 63 74 2d 67 72  ct disconnect-gr
d550: 6f 75 70 20 3b 0a 0a 3a 20 6c 65 61 76 65 2d 63  oup ;..: leave-c
d560: 68 61 74 73 20 28 20 2d 2d 20 29 0a 20 20 20 20  hats ( -- ).    
d570: 5b 27 5d 20 6c 65 61 76 65 2d 63 68 61 74 20 67  ['] leave-chat g
d580: 72 6f 75 70 23 6d 61 70 20 3b 0a 0a 3a 20 73 70  roup#map ;..: sp
d590: 6c 69 74 2d 6c 6f 61 64 20 28 20 6f 3a 67 72 6f  lit-load ( o:gro
d5a0: 75 70 20 2d 2d 20 29 0a 20 20 20 20 6d 73 67 3a  up -- ).    msg:
d5b0: 70 65 65 72 73 5b 5d 20 3e 72 20 30 0a 20 20 20  peers[] >r 0.   
d5c0: 20 42 45 47 49 4e 20 20 64 75 70 20 31 2b 20 72   BEGIN  dup 1+ r
d5d0: 40 20 24 5b 5d 23 20 75 3c 20 20 57 48 49 4c 45  @ $[]# u<  WHILE
d5e0: 0a 09 20 20 20 20 64 75 70 20 72 40 20 24 5b 5d  ..    dup r@ $[]
d5f0: 20 32 40 20 2e 73 65 6e 64 2d 72 65 63 6f 6e 6e   2@ .send-reconn
d600: 65 63 74 31 0a 09 20 20 20 20 31 2b 20 64 75 70  ect1..    1+ dup
d610: 20 72 40 20 24 5b 5d 20 40 20 3e 6f 20 6f 20 74   r@ $[] @ >o o t
d620: 6f 20 63 6f 6e 6e 65 63 74 69 6f 6e 20 64 69 73  o connection dis
d630: 63 6f 6e 6e 65 63 74 2d 6d 65 20 6f 3e 0a 20 20  connect-me o>.  
d640: 20 20 52 45 50 45 41 54 20 64 72 6f 70 20 72 64    REPEAT drop rd
d650: 72 6f 70 20 3b 0a 0a 73 63 6f 70 65 7b 20 2f 63  rop ;..scope{ /c
d660: 68 61 74 0a 3a 6e 6f 6e 61 6d 65 20 28 20 61 64  hat.:noname ( ad
d670: 64 72 20 75 20 2d 2d 20 29 20 20 32 64 72 6f 70  dr u -- )  2drop
d680: 0a 20 20 20 20 6d 73 67 2d 67 72 6f 75 70 24 20  .    msg-group$ 
d690: 24 40 20 3e 67 72 6f 75 70 20 6d 73 67 2d 67 72  $@ >group msg-gr
d6a0: 6f 75 70 2d 6f 20 2e 73 70 6c 69 74 2d 6c 6f 61  oup-o .split-loa
d6b0: 64 20 3b 20 69 73 20 2f 73 70 6c 69 74 0a 7d 73  d ; is /split.}s
d6c0: 63 6f 70 65 0a 0a 5c 20 63 68 61 74 20 74 6f 70  cope..\ chat top
d6d0: 6c 65 76 65 6c 0a 0a 3a 20 64 6f 2d 63 68 61 74  level..: do-chat
d6e0: 20 28 20 61 64 64 72 20 75 20 2d 2d 20 29 0a 20   ( addr u -- ). 
d6f0: 20 20 20 67 65 74 2d 6f 72 64 65 72 20 6e 3e 72     get-order n>r
d700: 0a 20 20 20 20 63 68 61 74 2d 68 69 73 74 6f 72  .    chat-histor
d710: 79 20 20 5b 27 5d 20 2f 63 68 61 74 20 3e 62 6f  y  ['] /chat >bo
d720: 64 79 20 31 20 73 65 74 2d 6f 72 64 65 72 0a 20  dy 1 set-order. 
d730: 20 20 20 6d 73 67 2d 67 72 6f 75 70 24 20 24 21     msg-group$ $!
d740: 20 63 68 61 74 2d 65 6e 74 72 79 20 5c 20 5b 27   chat-entry \ ['
d750: 5d 20 63 6d 64 28 20 3e 62 6f 64 79 20 6f 6e 0a  ] cmd( >body on.
d760: 20 20 20 20 5b 3a 20 75 70 40 20 77 61 69 74 2d      [: up@ wait-
d770: 74 61 73 6b 20 21 20 3b 5d 20 49 53 20 64 6f 2d  task ! ;] IS do-
d780: 63 6f 6e 6e 65 63 74 0a 20 20 20 20 42 45 47 49  connect.    BEGI
d790: 4e 20 20 67 65 74 2d 69 6e 70 75 74 2d 6c 69 6e  N  get-input-lin
d7a0: 65 0a 09 32 64 75 70 20 22 2f 62 79 65 22 20 73  e..2dup "/bye" s
d7b0: 74 72 3d 20 3e 72 20 32 64 75 70 20 22 5c 5c 62  tr= >r 2dup "\\b
d7c0: 79 65 22 20 73 74 72 3d 20 72 3e 20 6f 72 20 30  ye" str= r> or 0
d7d0: 3d 20 57 48 49 4c 45 0a 09 20 20 20 20 64 6f 2d  = WHILE..    do-
d7e0: 63 68 61 74 2d 63 6d 64 3f 20 30 3d 20 49 46 20  chat-cmd? 0= IF 
d7f0: 20 61 76 61 6c 61 6e 63 68 65 2d 74 65 78 74 20   avalanche-text 
d800: 20 54 48 45 4e 0a 20 20 20 20 52 45 50 45 41 54   THEN.    REPEAT
d810: 20 20 32 64 72 6f 70 20 6c 65 61 76 65 2d 63 68    2drop leave-ch
d820: 61 74 73 20 20 78 63 68 61 72 2d 68 69 73 74 6f  ats  xchar-histo
d830: 72 79 0a 20 20 20 20 6e 72 3e 20 73 65 74 2d 6f  ry.    nr> set-o
d840: 72 64 65 72 20 3b 0a 0a 3a 20 61 76 61 6c 61 6e  rder ;..: avalan
d850: 63 68 65 2d 74 6f 20 28 20 61 64 64 72 20 75 20  che-to ( addr u 
d860: 6f 3a 63 6f 6e 74 65 78 74 20 2d 2d 20 29 0a 20  o:context -- ). 
d870: 20 20 20 61 76 61 6c 61 6e 63 68 65 28 20 2e 22     avalanche( ."
d880: 20 53 65 6e 64 20 61 76 61 6c 61 6e 63 68 65 20   Send avalanche 
d890: 74 6f 3a 20 22 20 70 75 62 6b 65 79 20 24 40 20  to: " pubkey $@ 
d8a0: 6b 65 79 3e 6e 69 63 6b 20 74 79 70 65 20 73 70  key>nick type sp
d8b0: 61 63 65 20 6f 76 65 72 20 68 65 78 2e 20 63 72  ace over hex. cr
d8c0: 20 29 0a 20 20 20 20 6f 20 74 6f 20 63 6f 6e 6e   ).    o to conn
d8d0: 65 63 74 69 6f 6e 0a 20 20 20 20 6e 65 74 32 6f  ection.    net2o
d8e0: 2d 63 6f 64 65 20 65 78 70 65 63 74 2d 6d 73 67  -code expect-msg
d8f0: 20 6d 65 73 73 61 67 65 0a 20 20 20 20 6d 73 67   message.    msg
d900: 2d 67 72 6f 75 70 2d 6f 20 2e 6d 73 67 3a 6e 61  -group-o .msg:na
d910: 6d 65 24 20 32 64 75 70 20 70 75 62 6b 65 79 20  me$ 2dup pubkey 
d920: 24 40 20 6b 65 79 7c 20 73 74 72 3d 20 49 46 20  $@ key| str= IF 
d930: 20 32 64 72 6f 70 20 20 45 4c 53 45 20 20 67 72   2drop  ELSE  gr
d940: 6f 75 70 2c 20 20 54 48 45 4e 0a 20 20 20 20 24  oup,  THEN.    $
d950: 2c 20 6e 65 73 74 73 69 67 20 65 6e 64 2d 77 69  , nestsig end-wi
d960: 74 68 0a 20 20 20 20 65 6e 64 2d 63 6f 64 65 20  th.    end-code 
d970: 3b 0a 0a 5c 5c 5c 0a 4c 6f 63 61 6c 20 56 61 72  ;..\\\.Local Var
d980: 69 61 62 6c 65 73 3a 0a 66 6f 72 74 68 2d 6c 6f  iables:.forth-lo
d990: 63 61 6c 2d 77 6f 72 64 73 3a 0a 20 20 20 20 28  cal-words:.    (
d9a0: 0a 20 20 20 20 20 28 28 22 6e 65 74 32 6f 3a 22  .     (("net2o:"
d9b0: 20 22 2b 6e 65 74 32 6f 3a 22 29 20 64 65 66 69   "+net2o:") defi
d9c0: 6e 69 74 69 6f 6e 2d 73 74 61 72 74 65 72 20 28  nition-starter (
d9d0: 66 6f 6e 74 2d 6c 6f 63 6b 2d 6b 65 79 77 6f 72  font-lock-keywor
d9e0: 64 2d 66 61 63 65 20 2e 20 31 29 0a 20 20 20 20  d-face . 1).    
d9f0: 20 20 22 5b 20 5c 74 5c 6e 5d 22 20 74 20 6e 61    "[ \t\n]" t na
da00: 6d 65 20 28 66 6f 6e 74 2d 6c 6f 63 6b 2d 66 75  me (font-lock-fu
da10: 6e 63 74 69 6f 6e 2d 6e 61 6d 65 2d 66 61 63 65  nction-name-face
da20: 20 2e 20 33 29 29 0a 20 20 20 20 20 28 22 5b 61   . 3)).     ("[a
da30: 2d 7a 5c 2d 30 2d 39 5d 2b 28 22 20 69 6d 6d 65  -z\-0-9]+(" imme
da40: 64 69 61 74 65 20 28 66 6f 6e 74 2d 6c 6f 63 6b  diate (font-lock
da50: 2d 63 6f 6d 6d 65 6e 74 2d 66 61 63 65 20 2e 20  -comment-face . 
da60: 31 29 0a 20 20 20 20 20 20 22 29 22 20 6e 69 6c  1).      ")" nil
da70: 20 63 6f 6d 6d 65 6e 74 20 28 66 6f 6e 74 2d 6c   comment (font-l
da80: 6f 63 6b 2d 63 6f 6d 6d 65 6e 74 2d 66 61 63 65  ock-comment-face
da90: 20 2e 20 31 29 29 0a 20 20 20 20 29 0a 66 6f 72   . 1)).    ).for
daa0: 74 68 2d 6c 6f 63 61 6c 2d 69 6e 64 65 6e 74 2d  th-local-indent-
dab0: 77 6f 72 64 73 3a 0a 20 20 20 20 28 0a 20 20 20  words:.    (.   
dac0: 20 20 28 28 22 6e 65 74 32 6f 3a 22 20 22 2b 6e    (("net2o:" "+n
dad0: 65 74 32 6f 3a 22 29 20 28 30 20 2e 20 32 29 20  et2o:") (0 . 2) 
dae0: 28 30 20 2e 20 32 29 20 6e 6f 6e 2d 69 6d 6d 65  (0 . 2) non-imme
daf0: 64 69 61 74 65 29 0a 20 20 20 20 29 0a 45 6e 64  diate).    ).End
db00: 3a 0a 5b 54 48 45 4e 5d 0a                       :.[THEN].