Unified · Split
| @@ -0,0 +1,6 @@ | |||
| 1 | #!/bin/rc | ||
| 2 | if(~ $#* 0){ | ||
| 3 | echo usage: Acid pid >[2=1] | ||
| 4 | exit usage | ||
| 5 | } | ||
| 6 | win acid -l acme $* | ||
| @@ -0,0 +1,3 @@ | |||
| 1 | broke|rc kill program|rc | ||
| 2 | Acid pid | ||
| 3 | Acid -l thread -l acidfile pid | ||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
| @@ -0,0 +1,30 @@ | |||
| 1 | #!/bin/rc | ||
| 2 | |||
| 3 | if(! test -f /mnt/apm/battery){ | ||
| 4 | echo no apm >[1=2] | ||
| 5 | exit 'no apm' | ||
| 6 | } | ||
| 7 | |||
| 8 | cd /mnt/acme/new | ||
| 9 | echo name /dev/apm >ctl | ||
| 10 | echo dump Battery >ctl | ||
| 11 | |||
| 12 | awkscript=' | ||
| 13 | NR==1 { | ||
| 14 | if($3 != -1) | ||
| 15 | printf("%d%% %d:%02d %s", $2, $3/3600, ($3/60)%60, $1); | ||
| 16 | else | ||
| 17 | printf("%d%% %s", $2, $1); | ||
| 18 | } | ||
| 19 | ' | ||
| 20 | |||
| 21 | fn chk { | ||
| 22 | what=`{awk $awkscript /mnt/apm/battery} | ||
| 23 | echo cleartag >ctl || exit die | ||
| 24 | echo clean >ctl || exit die | ||
| 25 | echo ' '^$"what >tag || exit die | ||
| 26 | } | ||
| 27 | |||
| 28 | chk | ||
| 29 | while(sleep 60) | ||
| 30 | chk | ||
| @@ -0,0 +1,13 @@ | |||
| 1 | #!/bin/rc | ||
| 2 | |||
| 3 | if(! ~ $#* 0){ | ||
| 4 | echo usage: Isspam >[1=2] | ||
| 5 | exit usage | ||
| 6 | } | ||
| 7 | |||
| 8 | if(! ~ `{pwd} /mail/fs/*/[0-9]* || ! test -f raw || ! test -f unixheader){ | ||
| 9 | echo must run in mail directory >[1=2] | ||
| 10 | exit 'bad dir' | ||
| 11 | } | ||
| 12 | |||
| 13 | cat unixheader raw | upas/isspam | ||
| @@ -0,0 +1,9 @@ | |||
| 1 | #!/bin/rc | ||
| 2 | |||
| 3 | #/mail/fs is read-protected unless fs is mounted | ||
| 4 | test -r /mail/fs || { | ||
| 5 | if(test -d /mnt/term/mail/fs/mbox) bind /mnt/term/mail/fs /mail/fs | ||
| 6 | if not upas/fs | ||
| 7 | } | ||
| 8 | |||
| 9 | exec /acme/bin/$objtype/Mail $* | ||
| @@ -0,0 +1,7 @@ | |||
| 1 | #!/bin/rc | ||
| 2 | |||
| 3 | # aperl: | ||
| 4 | # Executes perl command and alters stderr to produce Acme-friendly error messages | ||
| 5 | # Created 02-JUL-1996, Luther Huffman, lutherh@stratcom.com | ||
| 6 | |||
| 7 | /bin/perl $* |[2] /bin/perl -pe 's/ line (\d+)/:$1 /' >[1=2] | ||
| @@ -0,0 +1,3 @@ | |||
| 1 | The source directory should be called ./src instead of ./source, | ||
| 2 | but this directory is bound into /bin and there is a command called | ||
| 3 | src that the local directory would hide. | ||
| @@ -0,0 +1,13 @@ | |||
| 1 | #!/bin/rc | ||
| 2 | |||
| 3 | if(! ~ $#* 0){ | ||
| 4 | echo usage: Spam >[1=2] | ||
| 5 | exit usage | ||
| 6 | } | ||
| 7 | |||
| 8 | if(! ~ `{pwd} /mail/fs/*/[0-9]* || ! test -f raw || ! test -f unixheader){ | ||
| 9 | echo must run in mail directory >[1=2] | ||
| 10 | exit 'bad dir' | ||
| 11 | } | ||
| 12 | |||
| 13 | cat unixheader raw | upas/spam | ||
| @@ -0,0 +1,13 @@ | |||
| 1 | #!/bin/rc | ||
| 2 | |||
| 3 | if(! ~ $#* 0){ | ||
| 4 | echo usage: Unspam >[1=2] | ||
| 5 | exit usage | ||
| 6 | } | ||
| 7 | |||
| 8 | if(! ~ `{pwd} /mail/fs/*/[0-9]* || ! test -f raw || ! test -f unixheader){ | ||
| 9 | echo must run in mail directory >[1=2] | ||
| 10 | exit 'bad dir' | ||
| 11 | } | ||
| 12 | |||
| 13 | cat unixheader raw | upas/unspam | ||
| @@ -0,0 +1,24 @@ | |||
| 1 | #!/bin/rc | ||
| 2 | |||
| 3 | if(~ $#* 0 1){ | ||
| 4 | echo >[1=2] usage: adiff file1 file2 | ||
| 5 | echo >[1=2] or adiff file1 file2... dir | ||
| 6 | exit usage | ||
| 7 | } | ||
| 8 | |||
| 9 | dir = /mnt/wsys | ||
| 10 | if(! test -f $dir/cons) | ||
| 11 | dir = /mnt/term/$dir | ||
| 12 | id=`{cat $dir/new/ctl} | ||
| 13 | id=$id(1) | ||
| 14 | |||
| 15 | l=$1 | ||
| 16 | r=$2 | ||
| 17 | if (test -d $1) l=$1/`{basename $2} | ||
| 18 | if not if (test -d $2) r=$2/`{basename $1} | ||
| 19 | |||
| 20 | echo 'name '^`{pwd}^/-diff-^`{basename $l} > $dir/$id/ctl | ||
| 21 | |||
| 22 | diff $* | awk -v 'l='$l -v 'r='^$r '/^diff/ {l=$2; r=$3; next} /^[1-9]/ {sub("[acd]", " & " r ":"); sub("^", l ":", $0)} | ||
| 23 | {print $0}' > $dir/$id/body | ||
| 24 | echo clean > $dir/$id/ctl | ||
| @@ -0,0 +1,3 @@ | |||
| 1 | #!/bin/rc | ||
| 2 | |||
| 3 | exec grep -n $* /dev/null | ||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
| @@ -0,0 +1,12 @@ | |||
| 1 | #!/bin/rc | ||
| 2 | args='' | ||
| 3 | while(~ $1 -*) { | ||
| 4 | args=$args^' '^$1 | ||
| 5 | shift 1 | ||
| 6 | } | ||
| 7 | if (~ $#1 0) | ||
| 8 | sysname=alice | ||
| 9 | if not | ||
| 10 | sysname=$1 | ||
| 11 | if (! test -f /n/$sysname/usr/spool/ap ) { 9fs $sysname } | ||
| 12 | eval exec /acme/bin/$cputype/apread $args $sysname | ||
| @@ -0,0 +1,43 @@ | |||
| 1 | #!/bin/rc | ||
| 2 | |||
| 3 | spellflags=() | ||
| 4 | fflag='' | ||
| 5 | for(x){ | ||
| 6 | switch($x){ | ||
| 7 | case -[bcvx] | ||
| 8 | spellflags=($spellflags $x) | ||
| 9 | case -f | ||
| 10 | fflag=$x | ||
| 11 | case * | ||
| 12 | if(~ $fflag -f) { | ||
| 13 | spellflags=($spellflags -f $x) | ||
| 14 | fflag='' | ||
| 15 | } | ||
| 16 | if not args = ($args $x) | ||
| 17 | } | ||
| 18 | } | ||
| 19 | |||
| 20 | dir = /mnt/wsys | ||
| 21 | if(! test -f $dir/cons) | ||
| 22 | dir = /mnt/term/$dir | ||
| 23 | id=`{cat $dir/new/ctl} | ||
| 24 | id=$id(1) | ||
| 25 | |||
| 26 | if(~ $#args 1 && ~ $args /*){ | ||
| 27 | adir = `{basename -d $args} | ||
| 28 | args = `{basename $args} | ||
| 29 | echo 'name '^$adir^/-spell > $dir/$id/ctl | ||
| 30 | cd $adir | ||
| 31 | } | ||
| 32 | if not { | ||
| 33 | echo 'name '^`{pwd}^/-spell > $dir/$id/ctl | ||
| 34 | } | ||
| 35 | |||
| 36 | { | ||
| 37 | echo noscroll | ||
| 38 | if(~ $#args 0) | ||
| 39 | /acme/bin/$cputype/spout | sort -t: -u +2 | sort -t: +1.1n | aux/sprog -a $spellflags > $dir/$id/body | ||
| 40 | if not for(i in $args) | ||
| 41 | /acme/bin/$cputype/spout $i | sort -t: -u +2 | sort -t: +1.1n | aux/sprog -a $spellflags > $dir/$id/body | ||
| 42 | echo clean | ||
| 43 | }> $dir/$id/ctl | ||
| @@ -0,0 +1,4 @@ | |||
| 1 | win | ||
| 2 | aspell file | ||
| 3 | adiff file1 file2 | ||
| 4 | adict -d oed | ||
| @@ -0,0 +1,3 @@ | |||
| 1 | #!/bin/rc | ||
| 2 | |||
| 3 | sed 's/^/ /' $* | ||
| @@ -0,0 +1,10 @@ | |||
| 1 | #!/bin/rc | ||
| 2 | |||
| 3 | id=`{cat /mnt/acme/new/ctl} | ||
| 4 | id=$id(1) | ||
| 5 | cmd = $* | ||
| 6 | if(~ $#cmd 0) cmd = cat | ||
| 7 | |||
| 8 | echo 'name '^`{pwd}^/-^`{basename $cmd(1)} > /mnt/acme/$id/ctl | ||
| 9 | $cmd > /mnt/acme/$id/body | ||
| 10 | echo clean > /mnt/acme/$id/ctl | ||
| @@ -0,0 +1,3 @@ | |||
| 1 | #!/bin/rc | ||
| 2 | |||
| 3 | sed 's/^/> /' $* | ||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
| @@ -0,0 +1,33 @@ | |||
| 1 | This is a CD player for use under Acme. | ||
| 2 | |||
| 3 | It is derived from my earlier cdplay, which | ||
| 4 | was in turn derived from a 2nd edition player | ||
| 5 | called vcd. I think hardly any of the code from | ||
| 6 | vcd is left anymore, but it's what got me started. | ||
| 7 | Vcd was originally by David Hogan with additions | ||
| 8 | by Alberto Nava. David Hogan claims the only | ||
| 9 | code left is the definition of struct Msf. | ||
| 10 | |||
| 11 | Run it by executing "acd /dev/sdD0", where | ||
| 12 | /dev/sdD0 is your CD reader. | ||
| 13 | |||
| 14 | A window with a track list will appear, with | ||
| 15 | tracks named Track 1, Track 2, etc. | ||
| 16 | If it can be found in the freedb.org CD database, | ||
| 17 | real track names will replace the boring | ||
| 18 | ones before long. | ||
| 19 | |||
| 20 | To start playing a track, right click the number. | ||
| 21 | A "> " marks the currently playing track. | ||
| 22 | When that track finishes, acd plays the track | ||
| 23 | on the next line. This means you can edit | ||
| 24 | the window as thought it were a play list. | ||
| 25 | |||
| 26 | If the next line is "repeat", acd will start again | ||
| 27 | at the first song listed in the window. | ||
| 28 | |||
| 29 | CD changes are handled gracefully. | ||
| 30 | |||
| 31 | Russ Cox | ||
| 32 | 9 August 2000 | ||
| 33 | rsc@plan9.bell-labs.com | ||
| @@ -0,0 +1,243 @@ | |||
| 1 | TWO FORMS OF ACCESS TO THE FREEDB | ||
| 2 | --------------------------------- | ||
| 3 | |||
| 4 | In the following document we will refer to CDDB instead of freedb, since | ||
| 5 | from a technical point of view, freedb is a CDDB-Server as it uses the | ||
| 6 | CDDB-protocol. | ||
| 7 | |||
| 8 | If you are interested in incorporating the use of freedb in your | ||
| 9 | software, there are two forms of access that you may consider. | ||
| 10 | |||
| 11 | 1. <a href="#local">Local access</a> | ||
| 12 | |||
| 13 | In this mode your software simply attempts to open local files on | ||
| 14 | the computer to access the CDDB. | ||
| 15 | |||
| 16 | 2. <a href="#remote">Remote access</a> | ||
| 17 | |||
| 18 | In this mode the software must connect to a freedb server on the | ||
| 19 | network to access the CDDB. There is a CDDB server protocol that | ||
| 20 | the software (also known as the "client") must use to converse with | ||
| 21 | the server. | ||
| 22 | |||
| 23 | You may choose to support either one, or both of these modes. | ||
| 24 | |||
| 25 | |||
| 26 | CDDB DISCID | ||
| 27 | ----------- | ||
| 28 | |||
| 29 | Both forms of CDDB access requires that the software computes a "disc | ||
| 30 | ID" which is an identifier that is used to access the CDDB. The disc | ||
| 31 | ID is a 8-digit hexadecimal (base-16) number, computed using data from | ||
| 32 | a CD's Table-of-Contents (TOC) in MSF (Minute Second Frame) form. The | ||
| 33 | algorithm is listed below in the <a href="http://freedb.freedb.org/sections.php?op=viewarticle&artid=6">DISCID Howto</a>. | ||
| 34 | |||
| 35 | It is crucial that your software compute the disc ID correctly. If it | ||
| 36 | does not generate the disc ID, it will not be compatible with the | ||
| 37 | CDDB. Moreover, if your software submits CDDB entries with bad disc | ||
| 38 | IDs to the freedb archives, it could compromise the integrity of the | ||
| 39 | freedb. | ||
| 40 | |||
| 41 | If you have access to a UNIX platform that xmcd supports, we suggest | ||
| 42 | installing xmcd, and then test the disc ID code in your software by | ||
| 43 | comparing the disc ID generated by xmcd with that of your software, | ||
| 44 | for as large a number of CDs as possible. | ||
| 45 | |||
| 46 | |||
| 47 | <a name="local"></a>LOCAL CDDB ACCESS | ||
| 48 | ----------------- | ||
| 49 | |||
| 50 | There are two forms of the CDDB archive available, the standard form | ||
| 51 | and the alternate form. Both forms are available for download from | ||
| 52 | various servers. You can always find an actual list of mirrors on the | ||
| 53 | freedb-homepage at <a href="http://freedb.freedb.org">http://freedb.freedb.org</a>. | ||
| 54 | The standard form of the CDDB archive is released to the public as | ||
| 55 | a UNIX tar(1)-format archive, compressed with gzip. The alternate | ||
| 56 | form archive is in the .zip format that is popular on the Windows | ||
| 57 | platform. | ||
| 58 | |||
| 59 | Standard Form: | ||
| 60 | -------------- | ||
| 61 | |||
| 62 | Each CD entry is a separate file in the xmcd CDDB. These files are | ||
| 63 | organized in several directories, each directory is a category of | ||
| 64 | music. Currently the "official" categories are listed as follows: | ||
| 65 | |||
| 66 | blues | ||
| 67 | classical | ||
| 68 | country | ||
| 69 | data | ||
| 70 | folk | ||
| 71 | jazz | ||
| 72 | misc | ||
| 73 | newage | ||
| 74 | reggae | ||
| 75 | rock | ||
| 76 | soundtrack | ||
| 77 | |||
| 78 | The individual CDDB files have a file name that is the 8-digit disc | ||
| 79 | ID. For example, under the blues directory there may be the following | ||
| 80 | files: | ||
| 81 | |||
| 82 | 0511c012 | ||
| 83 | 060e7314 | ||
| 84 | 0c01e902 | ||
| 85 | 0f0c3112 | ||
| 86 | ... | ||
| 87 | fa0f6f10 | ||
| 88 | fb0f8814 | ||
| 89 | fd0e6013 | ||
| 90 | |||
| 91 | To access the CDDB entry associated with a CD, your software simply | ||
| 92 | opens the appropriate file and reads the information. | ||
| 93 | |||
| 94 | The content of each of these files is in a format described in the | ||
| 95 | <a href="http://freedb.freedb.org/software/old/DBFORMAT">database-format specification</a>. | ||
| 96 | |||
| 97 | Different pressings of a particular CD title may contain differences | ||
| 98 | in timings that can cause the computed disc ID to be different. | ||
| 99 | The CDDB allows this by having multiple file names be links to | ||
| 100 | the same file. The links are implemented as actual filesystem links | ||
| 101 | (see the ln(1) command) on UNIX systems. For example, the following | ||
| 102 | files in the rock directory are all links to the same file, and | ||
| 103 | refer to the CD "Pink Floyd / The Division Bell".: | ||
| 104 | |||
| 105 | 850f740b | ||
| 106 | 850f950b | ||
| 107 | 850f970b | ||
| 108 | 860f960b | ||
| 109 | 890f970b | ||
| 110 | |||
| 111 | Xmcd and the CD database server use this form of the CDDB archive. The | ||
| 112 | benefit of the standard form of the CDDB archive is very fast access, | ||
| 113 | and ease of add/delete/edit operations on entries. | ||
| 114 | |||
| 115 | Alternate Form: | ||
| 116 | --------------- | ||
| 117 | |||
| 118 | Due to limitations in the FAT file system used on Windows 9x and | ||
| 119 | Windows ME, it is unfeasible to use the standard format CDDB archive | ||
| 120 | due to the large number of files. This is because such a filesystem | ||
| 121 | operates on fixed-size clusters and even a small file (and most CDDB | ||
| 122 | files are 1KB or less) would consume the space of a full cluster | ||
| 123 | (Depending upon disk size, a cluster can range from 4KB to 32KB in | ||
| 124 | size). Thus, a tremendous amount of disk space would be wasted on | ||
| 125 | these systems if the CDDB archive is used in its standard form. | ||
| 126 | |||
| 127 | An alternate form of the CDDB archives was created for use by software | ||
| 128 | that must operate on a system with the FAT limitations. | ||
| 129 | |||
| 130 | The alterate form still use the separate category directories as the | ||
| 131 | standard form, but concatenates many files into a smaller number of | ||
| 132 | files under each category. The first two digits of the CDDB file names | ||
| 133 | is used as a key for concatenation, each file is allowed to grow to | ||
| 134 | approximately 64KB in size before a new file is started. The file name | ||
| 135 | indicates what range of the digits are included in that file. For | ||
| 136 | example, under the blues category we may have the following files: | ||
| 137 | |||
| 138 | 01to36 | ||
| 139 | 37to55 | ||
| 140 | 56to71 | ||
| 141 | ... | ||
| 142 | b2tod7 | ||
| 143 | d8toff | ||
| 144 | |||
| 145 | The 01to36 file contains all CDDB entries with disc ID 01xxxxxx, | ||
| 146 | 02xxxxxx, 03xxxxxx and so on, up to 36xxxxxx. | ||
| 147 | |||
| 148 | Each entry in the concatenated file begins with the keyword | ||
| 149 | |||
| 150 | #FILENAME=xxxxxxxx | ||
| 151 | |||
| 152 | where discid is the 8-digit hexadecimal disc ID of that entry. Your | ||
| 153 | software must search through the appropriate file to locate the desired | ||
| 154 | entry. The CDDB entry is in the format described in Appendix B below. | ||
| 155 | |||
| 156 | The alternate form avoids the problem of inefficient disk space | ||
| 157 | utilization on FAT-based filesystems, but is slower to access than the | ||
| 158 | standard form, and it is much more cumbersome to perform add/delete/edit | ||
| 159 | operations on a CDDB entry. | ||
| 160 | |||
| 161 | |||
| 162 | <a name="remote"></a>REMOTE CDDB ACCESS | ||
| 163 | ------------------ | ||
| 164 | |||
| 165 | Your software must be able to communicate with a remote CD server | ||
| 166 | system via TCP/IP or HTTP. | ||
| 167 | There are a number of public freedb servers operating | ||
| 168 | on the Internet. The <a href="http://freedb.freedb.org/sections.php?op=viewarticle&artid=9">current list of public servers</a> is listed on the | ||
| 169 | freedb web page at: | ||
| 170 | |||
| 171 | http://freedb.freedb.org. | ||
| 172 | |||
| 173 | It may also be obtained programmatically via the CDDB protocol "sites" | ||
| 174 | command. | ||
| 175 | |||
| 176 | TCP/IP access: | ||
| 177 | |||
| 178 | All current freedb servers answer at TCP port 888. There may be future | ||
| 179 | sites that deviate from this convention, however. | ||
| 180 | |||
| 181 | HTTP access: | ||
| 182 | |||
| 183 | The freedb-servers can be accessed via the cddb.cgi. This is resides at the | ||
| 184 | following path: /~cddb/cddb.cgi | ||
| 185 | Thus, the URL for accessing the server at freedb.freedb.org is: | ||
| 186 | http://freedb.freedb.org/~cddb/cddb.cgi | ||
| 187 | |||
| 188 | You should make the freedb server host (or hosts) and port numbers | ||
| 189 | user-configurable in your software. Do not hard-wire the list of | ||
| 190 | CD database servers into your code. The list of active servers changes | ||
| 191 | over time. | ||
| 192 | |||
| 193 | The CDDB server protocol is described in the <a href="http://freedb.freedb.org/sections.php?op=viewarticle&artid=28">CDDB-protocol documentation</a>. | ||
| 194 | |||
| 195 | The CDDB entry returned from the server via a "cddb read" command is in | ||
| 196 | the format described <a href="http://freedb.freedb.org/software/old/DBFORMAT">database-format specification</a>. | ||
| 197 | |||
| 198 | You may experiment with the freedb server by connecting to port 888 of | ||
| 199 | the server host via the "telnet" program, and then typing the cddb | ||
| 200 | protocol commands by hand. For example: | ||
| 201 | |||
| 202 | telnet freedb.freedb.org 888 | ||
| 203 | |||
| 204 | connects you to the freedb server at freedb.freedb.org. | ||
| 205 | |||
| 206 | Some additional notes for accessing freedb over the Internet: | ||
| 207 | |||
| 208 | Your application should always specify the highest documented protocol | ||
| 209 | level. The highest level currently supported is "3". Lower protocol | ||
| 210 | levels will work, but are only provided for compatibility with older | ||
| 211 | CDDB applications. If you do not use the highest available protocol | ||
| 212 | level, certain important features will not be available to your | ||
| 213 | application. | ||
| 214 | |||
| 215 | Make sure to use the proper arguments with the "hello" command. The user | ||
| 216 | and hostname arguments should be that of the user's email address, not | ||
| 217 | some fixed hard-coded value. The application name and version should be | ||
| 218 | that of your application, not that of another existing application. | ||
| 219 | |||
| 220 | We consider the use of the "cddb query" command mandatory for all CDDB | ||
| 221 | clients. It is not valid to issue a "cddb read" command without issuing | ||
| 222 | a prior "cddb query" and receiving a good response, as it may yield incorrect | ||
| 223 | results. In addition, it is clients should support close matches | ||
| 224 | (aka "fuzzy" matches, or response code 211). | ||
| 225 | |||
| 226 | The proper way to handle multiple fuzzy matches is to present the | ||
| 227 | entire list of matches to the user and to let the user choose between them. | ||
| 228 | Matches are listed in the order of best fit for the user's disc, so they | ||
| 229 | should be presented to the user in the order they are listed by the server. | ||
| 230 | |||
| 231 | The suggested algorithm for obtaining the list of server sites is | ||
| 232 | as follows. The application should offer to get the list from | ||
| 233 | freedb.freedb.org with the "sites" command the first time the user runs | ||
| 234 | the program. Additionally the application should provide the user with | ||
| 235 | some method of downloading the list on-demand. | ||
| 236 | |||
| 237 | We do strongly suggest that you provide your users with the capability of | ||
| 238 | choosing freedb server sites as described above. However, for some | ||
| 239 | applications this may not be feasible. If you do not wish to offer this | ||
| 240 | functionality, you may safely hard-code "freedb.freedb.org" in your | ||
| 241 | application as the sole freedb site to access. This will deprive your users | ||
| 242 | of the option to choose a site near their locale for optimal response, but | ||
| 243 | that is your choice. | ||
| @@ -0,0 +1,171 @@ | |||
| 1 | #include <u.h> | ||
| 2 | #include <libc.h> | ||
| 3 | #include <bio.h> | ||
| 4 | #include <disk.h> | ||
| 5 | #include <auth.h> | ||
| 6 | #include <fcall.h> | ||
| 7 | #include <thread.h> | ||
| 8 | #include <9p.h> | ||
| 9 | |||
| 10 | /* acme */ | ||
| 11 | typedef struct Event Event; | ||
| 12 | typedef struct Window Window; | ||
| 13 | |||
| 14 | enum | ||
| 15 | { | ||
| 16 | STACK = 16384, | ||
| 17 | EVENTSIZE = 256, | ||
| 18 | NEVENT = 5, | ||
| 19 | }; | ||
| 20 | |||
| 21 | struct Event | ||
| 22 | { | ||
| 23 | int c1; | ||
| 24 | int c2; | ||
| 25 | int q0; | ||
| 26 | int q1; | ||
| 27 | int flag; | ||
| 28 | int nb; | ||
| 29 | int nr; | ||
| 30 | char b[EVENTSIZE*UTFmax+1]; | ||
| 31 | Rune r[EVENTSIZE+1]; | ||
| 32 | }; | ||
| 33 | |||
| 34 | struct Window | ||
| 35 | { | ||
| 36 | /* file descriptors */ | ||
| 37 | int ctl; | ||
| 38 | int event; | ||
| 39 | int addr; | ||
| 40 | int data; | ||
| 41 | Biobuf *body; | ||
| 42 | |||
| 43 | /* event input */ | ||
| 44 | char buf[512]; | ||
| 45 | char *bufp; | ||
| 46 | int nbuf; | ||
| 47 | Event e[NEVENT]; | ||
| 48 | |||
| 49 | int id; | ||
| 50 | int open; | ||
| 51 | Channel *cevent; /* chan(Event*) */ | ||
| 52 | }; | ||
| 53 | |||
| 54 | extern Window* newwindow(void); | ||
| 55 | extern int winopenfile(Window*, char*); | ||
| 56 | extern void winopenbody(Window*, int); | ||
| 57 | extern void winclosebody(Window*); | ||
| 58 | extern void wintagwrite(Window*, char*, int); | ||
| 59 | extern void winname(Window*, char*); | ||
| 60 | extern void winwriteevent(Window*, Event*); | ||
| 61 | extern void winread(Window*, uint, uint, char*); | ||
| 62 | extern int windel(Window*, int); | ||
| 63 | extern void wingetevent(Window*, Event*); | ||
| 64 | extern void wineventproc(void*); | ||
| 65 | extern void winwritebody(Window*, char*, int); | ||
| 66 | extern void winclean(Window*); | ||
| 67 | extern int winselect(Window*, char*, int); | ||
| 68 | extern int winsetaddr(Window*, char*, int); | ||
| 69 | extern char* winreadbody(Window*, int*); | ||
| 70 | extern void windormant(Window*); | ||
| 71 | extern void winsetdump(Window*, char*, char*); | ||
| 72 | |||
| 73 | extern char* readfile(char*, char*, int*); | ||
| 74 | extern void ctlprint(int, char*, ...); | ||
| 75 | extern void* emalloc(uint); | ||
| 76 | extern char* estrdup(char*); | ||
| 77 | extern char* estrstrdup(char*, char*); | ||
| 78 | extern char* egrow(char*, char*, char*); | ||
| 79 | extern char* eappend(char*, char*, char*); | ||
| 80 | extern void error(char*, ...); | ||
| 81 | extern int tokenizec(char*, char**, int, char*); | ||
| 82 | |||
| 83 | /* cd stuff */ | ||
| 84 | typedef struct Msf Msf; /* minute, second, frame */ | ||
| 85 | struct Msf { | ||
| 86 | int m; | ||
| 87 | int s; | ||
| 88 | int f; | ||
| 89 | }; | ||
| 90 | |||
| 91 | typedef struct Track Track; | ||
| 92 | struct Track { | ||
| 93 | Msf start; | ||
| 94 | Msf end; | ||
| 95 | ulong bstart; | ||
| 96 | ulong bend; | ||
| 97 | char *title; | ||
| 98 | }; | ||
| 99 | |||
| 100 | enum { | ||
| 101 | MTRACK = 64, | ||
| 102 | }; | ||
| 103 | typedef struct Toc Toc; | ||
| 104 | struct Toc { | ||
| 105 | int ntrack; | ||
| 106 | int nchange; | ||
| 107 | int changetime; | ||
| 108 | int track0; | ||
| 109 | Track track[MTRACK]; | ||
| 110 | char *title; | ||
| 111 | }; | ||
| 112 | |||
| 113 | extern int msfconv(Fmt*); | ||
| 114 | |||
| 115 | #pragma varargck argpos error 1 | ||
| 116 | #pragma varargck argpos ctlprint 2 | ||
| 117 | #pragma varargck type "M" Msf | ||
| 118 | |||
| 119 | enum { /* state */ | ||
| 120 | Sunknown, | ||
| 121 | Splaying, | ||
| 122 | Spaused, | ||
| 123 | Scompleted, | ||
| 124 | Serror, | ||
| 125 | }; | ||
| 126 | |||
| 127 | typedef struct Cdstatus Cdstatus; | ||
| 128 | struct Cdstatus { | ||
| 129 | int state; | ||
| 130 | int track; | ||
| 131 | int index; | ||
| 132 | Msf abs; | ||
| 133 | Msf rel; | ||
| 134 | }; | ||
| 135 | |||
| 136 | typedef struct Drive Drive; | ||
| 137 | struct Drive { | ||
| 138 | Window *w; | ||
| 139 | Channel *cstatus; /* chan(Cdstatus) */ | ||
| 140 | Channel *ctocdisp; /* chan(Toc) */ | ||
| 141 | Channel *cdbreq; /* chan(Toc) */ | ||
| 142 | Channel *cdbreply; /* chan(Toc) */ | ||
| 143 | Scsi *scsi; | ||
| 144 | Toc toc; | ||
| 145 | Cdstatus status; | ||
| 146 | }; | ||
| 147 | |||
| 148 | int gettoc(Scsi*, Toc*); | ||
| 149 | void drawtoc(Window*, Drive*, Toc*); | ||
| 150 | void redrawtoc(Window*, Toc*); | ||
| 151 | void tocproc(void*); /* Drive* */ | ||
| 152 | void cddbproc(void*); /* Drive* */ | ||
| 153 | void cdstatusproc(void*); /* Drive* */ | ||
| 154 | |||
| 155 | extern int debug; | ||
| 156 | |||
| 157 | #define DPRINT if(debug)fprint | ||
| 158 | void acmeevent(Drive*, Window*, Event*); | ||
| 159 | |||
| 160 | int playtrack(Drive*, int, int); | ||
| 161 | int pause(Drive*); | ||
| 162 | int resume(Drive*); | ||
| 163 | int stop(Drive*); | ||
| 164 | int eject(Drive*); | ||
| 165 | int ingest(Drive*); | ||
| 166 | |||
| 167 | int markplay(Window*, ulong); | ||
| 168 | int setplaytime(Window*, char*); | ||
| 169 | void advancetrack(Drive*, Window*); | ||
| 170 | |||
| 171 | |||
| @@ -0,0 +1,347 @@ | |||
| 1 | #include "acd.h" | ||
| 2 | |||
| 3 | static int | ||
| 4 | iscmd(char *s, char *cmd) | ||
| 5 | { | ||
| 6 | int len; | ||
| 7 | |||
| 8 | len = strlen(cmd); | ||
| 9 | return strncmp(s, cmd, len)==0 && (s[len]=='\0' || s[len]==' ' || s[len]=='\t' || s[len]=='\n'); | ||
| 10 | } | ||
| 11 | |||
| 12 | static char* | ||
| 13 | skip(char *s, char *cmd) | ||
| 14 | { | ||
| 15 | s += strlen(cmd); | ||
| 16 | while(*s==' ' || *s=='\t' || *s=='\n') | ||
| 17 | s++; | ||
| 18 | return s; | ||
| 19 | } | ||
| 20 | |||
| 21 | //#define PLAYSTRING "/^[0-9:]+>" | ||
| 22 | //#define PLAYSTRINGSPACE "/^[0-9:]+> ?" | ||
| 23 | //#define INITSTRING "0:00> " | ||
| 24 | |||
| 25 | #define INITSTRING "> " | ||
| 26 | #define PLAYSTRING "/^>" | ||
| 27 | #define PLAYSTRINGSPACE "/^> ?" | ||
| 28 | |||
| 29 | /* | ||
| 30 | * find the playing string, leave in addr | ||
| 31 | * if q0, q1 are non-nil, set them to the addr of the string. | ||
| 32 | */ | ||
| 33 | int | ||
| 34 | findplay(Window *w, char *s, ulong *q0, ulong *q1) | ||
| 35 | { | ||
| 36 | char xbuf[25]; | ||
| 37 | if(w->data < 0) | ||
| 38 | w->data = winopenfile(w, "data"); | ||
| 39 | |||
| 40 | if(!winsetaddr(w, "#0", 1) || !winsetaddr(w, s, 1)) | ||
| 41 | return 0; | ||
| 42 | |||
| 43 | seek(w->addr, 0, 0); | ||
| 44 | if(read(w->addr, xbuf, 24) != 24) | ||
| 45 | return 0; | ||
| 46 | |||
| 47 | xbuf[24] = 0; | ||
| 48 | if(q0) | ||
| 49 | *q0 = atoi(xbuf); | ||
| 50 | if(q1) | ||
| 51 | *q1 = atoi(xbuf+12); | ||
| 52 | |||
| 53 | return 1; | ||
| 54 | } | ||
| 55 | |||
| 56 | /* | ||
| 57 | * find the playing string and replace the time | ||
| 58 | */ | ||
| 59 | int | ||
| 60 | setplaytime(Window *w, char *new) | ||
| 61 | { | ||
| 62 | char buf[40]; | ||
| 63 | ulong q0, q1; | ||
| 64 | |||
| 65 | return 1; | ||
| 66 | if(!findplay(w, PLAYSTRING, &q0, &q1)) | ||
| 67 | return 0; | ||
| 68 | |||
| 69 | q1--; /* > */ | ||
| 70 | sprint(buf, "#%lud,#%lud", q0, q1); | ||
| 71 | DPRINT(2, "setaddr %s\n", buf); | ||
| 72 | if(!winsetaddr(w, buf, 1)) | ||
| 73 | return 0; | ||
| 74 | |||
| 75 | if(write(w->data, new, strlen(new)) != strlen(new)) | ||
| 76 | return 0; | ||
| 77 | |||
| 78 | return 1; | ||
| 79 | } | ||
| 80 | |||
| 81 | /* | ||
| 82 | * find the playing string, and remove it. | ||
| 83 | * return the string at the beginning of hte next line in buf | ||
| 84 | * (presumably a track number). | ||
| 85 | */ | ||
| 86 | static int | ||
| 87 | unmarkplay(Window *w, char *buf, int n, ulong *q0, ulong *q1, ulong *qbegin) | ||
| 88 | { | ||
| 89 | char xbuf[24]; | ||
| 90 | |||
| 91 | if(!findplay(w, PLAYSTRINGSPACE, q0, q1)) | ||
| 92 | return 0; | ||
| 93 | |||
| 94 | if(write(w->data, "", 0) < 0 || !winsetaddr(w, "+1+#0", 1)) | ||
| 95 | return 0; | ||
| 96 | |||
| 97 | if(qbegin) { | ||
| 98 | seek(w->addr, 0, 0); | ||
| 99 | if(read(w->addr, xbuf, 24) != 24) | ||
| 100 | return 0; | ||
| 101 | *qbegin = atoi(xbuf); | ||
| 102 | } | ||
| 103 | |||
| 104 | if(buf) { | ||
| 105 | if((n = read(w->data, buf, n-1)) < 0) | ||
| 106 | return 0; | ||
| 107 | |||
| 108 | buf[n] = '\0'; | ||
| 109 | } | ||
| 110 | |||
| 111 | return 1; | ||
| 112 | } | ||
| 113 | |||
| 114 | int | ||
| 115 | markplay(Window *w, ulong q0) | ||
| 116 | { | ||
| 117 | char buf[20]; | ||
| 118 | |||
| 119 | if(w->data < 0) | ||
| 120 | w->data = winopenfile(w, "data"); | ||
| 121 | |||
| 122 | sprint(buf, "#%lud", q0); | ||
| 123 | DPRINT(2, "addr %s\n", buf); | ||
| 124 | if(!winsetaddr(w, buf, 1) || !winsetaddr(w, "-0", 1)) | ||
| 125 | return 0; | ||
| 126 | if(write(w->data, INITSTRING, strlen(INITSTRING)) != strlen(INITSTRING)) | ||
| 127 | return 0; | ||
| 128 | return 1; | ||
| 129 | } | ||
| 130 | |||
| 131 | /* return 1 if handled, 0 otherwise */ | ||
| 132 | int | ||
| 133 | cdcommand(Window *w, Drive *d, char *s) | ||
| 134 | { | ||
| 135 | s = skip(s, ""); | ||
| 136 | |||
| 137 | if(iscmd(s, "Del")){ | ||
| 138 | if(windel(w, 0)) | ||
| 139 | threadexitsall(nil); | ||
| 140 | return 1; | ||
| 141 | } | ||
| 142 | if(iscmd(s, "Stop")){ | ||
| 143 | unmarkplay(w, nil, 0, nil, nil, nil); | ||
| 144 | stop(d); | ||
| 145 | return 1; | ||
| 146 | } | ||
| 147 | if(iscmd(s, "Eject")){ | ||
| 148 | unmarkplay(w, nil, 0, nil, nil, nil); | ||
| 149 | eject(d); | ||
| 150 | return 1; | ||
| 151 | } | ||
| 152 | if(iscmd(s, "Ingest")){ | ||
| 153 | unmarkplay(w, nil, 0, nil, nil, nil); | ||
| 154 | ingest(d); | ||
| 155 | return 1; | ||
| 156 | } | ||
| 157 | if(iscmd(s, "Pause")){ | ||
| 158 | pause(d); | ||
| 159 | return 1; | ||
| 160 | } | ||
| 161 | if(iscmd(s, "Resume")){ | ||
| 162 | resume(d); | ||
| 163 | return 1; | ||
| 164 | } | ||
| 165 | return 0; | ||
| 166 | } | ||
| 167 | |||
| 168 | void | ||
| 169 | drawtoc(Window *w, Drive *d, Toc *t) | ||
| 170 | { | ||
| 171 | int i, playing; | ||
| 172 | |||
| 173 | if(w->data < 0) | ||
| 174 | w->data = winopenfile(w, "data"); | ||
| 175 | if(!winsetaddr(w, ",", 1)) | ||
| 176 | return; | ||
| 177 | |||
| 178 | fprint(w->data, "Title\n\n"); | ||
| 179 | playing = -1; | ||
| 180 | if(d->status.state == Splaying || d->status.state == Spaused) | ||
| 181 | playing = d->status.track-t->track0; | ||
| 182 | |||
| 183 | for(i=0; i<t->ntrack; i++) | ||
| 184 | fprint(w->data, "%s%d/ Track %d\n", i==playing ? "> " : "", i+1, i+1); | ||
| 185 | fprint(w->data, ""); | ||
| 186 | } | ||
| 187 | |||
| 188 | void | ||
| 189 | redrawtoc(Window *w, Toc *t) | ||
| 190 | { | ||
| 191 | int i; | ||
| 192 | char old[50]; | ||
| 193 | |||
| 194 | if(w->data < 0) | ||
| 195 | w->data = winopenfile(w, "data"); | ||
| 196 | if(t->title) { | ||
| 197 | if(winsetaddr(w, "/Title", 1)) | ||
| 198 | write(w->data, t->title, strlen(t->title)); | ||
| 199 | } | ||
| 200 | for(i=0; i<t->ntrack; i++) { | ||
| 201 | if(t->track[i].title) { | ||
| 202 | sprint(old, "/Track %d", i+1); | ||
| 203 | if(winsetaddr(w, old, 1)) | ||
| 204 | write(w->data, t->track[i].title, strlen(t->track[i].title)); | ||
| 205 | } | ||
| 206 | } | ||
| 207 | } | ||
| 208 | |||
| 209 | void | ||
| 210 | advancetrack(Drive *d, Window *w) | ||
| 211 | { | ||
| 212 | int n; | ||
| 213 | ulong q0, q1, qnext; | ||
| 214 | char buf[20]; | ||
| 215 | |||
| 216 | q0 = q1 = 0; | ||
| 217 | if(!unmarkplay(w, buf, sizeof(buf), &q0, &q1, &qnext)) { | ||
| 218 | DPRINT(2, "unmark: %r\n"); | ||
| 219 | return; | ||
| 220 | } | ||
| 221 | |||
| 222 | DPRINT(2, "buf: %s\n", buf); | ||
| 223 | if(strncmp(buf, "repeat", 6) == 0) { | ||
| 224 | if(!winsetaddr(w, "#0", 1) || !findplay(w, "/^[0-9]+\\/", &qnext, nil)) { | ||
| 225 | DPRINT(2, "set/find: %r\n"); | ||
| 226 | return; | ||
| 227 | } | ||
| 228 | if(w->data < 0) | ||
| 229 | w->data = winopenfile(w, "data"); | ||
| 230 | if((n = read(w->data, buf, sizeof(buf)-1)) <= 0) { | ||
| 231 | DPRINT(2, "read %d: %r\n", n); | ||
| 232 | return; | ||
| 233 | } | ||
| 234 | buf[n] = 0; | ||
| 235 | DPRINT(2, "buf: %s\n", buf); | ||
| 236 | } | ||
| 237 | |||
| 238 | if((n = atoi(buf)) == 0) | ||
| 239 | return; | ||
| 240 | |||
| 241 | if(!markplay(w, qnext)) | ||
| 242 | DPRINT(2, "err: %r"); | ||
| 243 | |||
| 244 | playtrack(d, n-1, n-1); | ||
| 245 | } | ||
| 246 | |||
| 247 | void | ||
| 248 | acmeevent(Drive *d, Window *w, Event *e) | ||
| 249 | { | ||
| 250 | Event *ea, *e2, *eq; | ||
| 251 | char *s, *t, *buf; | ||
| 252 | int n, na; | ||
| 253 | ulong q0, q1; | ||
| 254 | |||
| 255 | switch(e->c1){ /* origin of action */ | ||
| 256 | default: | ||
| 257 | Unknown: | ||
| 258 | fprint(2, "unknown message %c%c\n", e->c1, e->c2); | ||
| 259 | break; | ||
| 260 | |||
| 261 | case 'E': /* write to body or tag; can't affect us */ | ||
| 262 | break; | ||
| 263 | |||
| 264 | case 'F': /* generated by our actions; ignore */ | ||
| 265 | break; | ||
| 266 | |||
| 267 | case 'K': /* type away; we don't care */ | ||
| 268 | break; | ||
| 269 | |||
| 270 | case 'M': /* mouse event */ | ||
| 271 | switch(e->c2){ /* type of action */ | ||
| 272 | case 'x': /* mouse: button 2 in tag */ | ||
| 273 | case 'X': /* mouse: button 2 in body */ | ||
| 274 | ea = nil; | ||
| 275 | // e2 = nil; | ||
| 276 | s = e->b; | ||
| 277 | if(e->flag & 2){ /* null string with non-null expansion */ | ||
| 278 | e2 = recvp(w->cevent); | ||
| 279 | if(e->nb==0) | ||
| 280 | s = e2->b; | ||
| 281 | } | ||
| 282 | if(e->flag & 8){ /* chorded argument */ | ||
| 283 | ea = recvp(w->cevent); /* argument */ | ||
| 284 | na = ea->nb; | ||
| 285 | recvp(w->cevent); /* ignore origin */ | ||
| 286 | }else | ||
| 287 | na = 0; | ||
| 288 | |||
| 289 | /* append chorded arguments */ | ||
| 290 | if(na){ | ||
| 291 | t = emalloc(strlen(s)+1+na+1); | ||
| 292 | sprint(t, "%s %s", s, ea->b); | ||
| 293 | s = t; | ||
| 294 | } | ||
| 295 | /* if it's a known command, do it */ | ||
| 296 | /* if it's a long message, it can't be for us anyway */ | ||
| 297 | DPRINT(2, "exec: %s\n", s); | ||
| 298 | if(!cdcommand(w, d, s)) /* send it back */ | ||
| 299 | winwriteevent(w, e); | ||
| 300 | if(na) | ||
| 301 | free(s); | ||
| 302 | break; | ||
| 303 | |||
| 304 | case 'l': /* mouse: button 3 in tag */ | ||
| 305 | case 'L': /* mouse: button 3 in body */ | ||
| 306 | // buf = nil; | ||
| 307 | eq = e; | ||
| 308 | if(e->flag & 2){ | ||
| 309 | e2 = recvp(w->cevent); | ||
| 310 | eq = e2; | ||
| 311 | } | ||
| 312 | s = eq->b; | ||
| 313 | if(eq->q1>eq->q0 && eq->nb==0){ | ||
| 314 | buf = emalloc((eq->q1-eq->q0)*UTFmax+1); | ||
| 315 | winread(w, eq->q0, eq->q1, buf); | ||
| 316 | s = buf; | ||
| 317 | } | ||
| 318 | DPRINT(2, "load %s\n", s); | ||
| 319 | if((n = atoi(s)) != 0) { | ||
| 320 | DPRINT(2, "mark %d\n", n); | ||
| 321 | q0 = q1 = 0; | ||
| 322 | unmarkplay(w, nil, 0, &q0, &q1, nil); | ||
| 323 | |||
| 324 | /* adjust eq->q* for deletion */ | ||
| 325 | if(eq->q0 > q1) { | ||
| 326 | eq->q0 -= (q1-q0); | ||
| 327 | eq->q1 -= (q1-q0); | ||
| 328 | } | ||
| 329 | if(!markplay(w, eq->q0)) | ||
| 330 | DPRINT(2, "err: %r\n"); | ||
| 331 | |||
| 332 | playtrack(d, n-1, n-1); | ||
| 333 | } else | ||
| 334 | winwriteevent(w, e); | ||
| 335 | break; | ||
| 336 | |||
| 337 | case 'i': /* mouse: text inserted in tag */ | ||
| 338 | case 'I': /* mouse: text inserted in body */ | ||
| 339 | case 'd': /* mouse: text deleted from tag */ | ||
| 340 | case 'D': /* mouse: text deleted from body */ | ||
| 341 | break; | ||
| 342 | |||
| 343 | default: | ||
| 344 | goto Unknown; | ||
| 345 | } | ||
| 346 | } | ||
| 347 | } | ||
| @@ -0,0 +1,206 @@ | |||
| 1 | <html><html> | ||
| 2 | <head> | ||
| 3 | <title>::freedb.org::</title> | ||
| 4 | </head> | ||
| 5 | |||
| 6 | <body bgcolor="#FFFFFF" text="#000000" link="#101070" vlink="#101070"> | ||
| 7 | |||
| 8 | <center> | ||
| 9 | |||
| 10 | <table cellpadding=0 cellspacing=0 border=0 width="99%" align=center><tr><td align=left> | ||
| 11 | <a href="/"> | ||
| 12 | <table border=0> | ||
| 13 | <td bgcolor="#ffffff"> | ||
| 14 | <table border=0 width=100% cellpadding=0 cellspacing=0> | ||
| 15 | <td bgcolor=#101070> | ||
| 16 | <table border=0> | ||
| 17 | <td bgcolor=#ffffff><font face="Arial,Helvetica,Lucida" color="#101070" size=8><b>freedb</b></td> | ||
| 18 | <td bgcolor=#101070><font face="Arial,Helvetica,Lucida" color="#ffffff" size=8><b>.org</b></td> | ||
| 19 | </table> | ||
| 20 | </td> | ||
| 21 | <tr> | ||
| 22 | <td align=right><font face="Arial,Helvetica,Lucida" color="#101070" size=2><b>a free approach to cddbp | ||
| 23 | </table> | ||
| 24 | </td> | ||
| 25 | </table> | ||
| 26 | </a> | ||
| 27 | </td><td align=right width=100%> | ||
| 28 | <form action="search.php" method=post> | ||
| 29 | <font face=Arial,Helvetica size=2><input type=name name=query width=20 size=20 length=20> | ||
| 30 | </td> | ||
| 31 | <td align=right> <input type=image src=images/menu/english/search.gif border=0 align=middle></td> | ||
| 32 | </form> | ||
| 33 | |||
| 34 | </td></tr></table><br> | ||
| 35 | <table cellpadding=0 cellspacing=0 border=0 width="99%" bgcolor=101070><tr><td> | ||
| 36 | <table cellpadding=5 cellspacing=1 border=0 width="100%" bgcolor=FFFFFF><tr><td> | ||
| 37 | <font face=Lucida,Verdana,Arial,Helvetica size=2>freedb.org - a free approach to cddbp</td></tr></table></td></tr></table><P> | ||
| 38 | |||
| 39 | <table width="99%" align=center cellpadding=0 cellspacing=0 border=0><tr> | ||
| 40 | <td valign=top rowspan=5> | ||
| 41 | |||
| 42 | <table border=0><tr><td> | ||
| 43 | |||
| 44 | <table width="115" border="0" cellpadding="0" cellspacing="0"><tr valign="top" bgcolor="#101070"> | ||
| 45 | <td bgcolor="#FFFFFF"><img src="themes/SlashOcean/pix.gif" width="3" height="3"></td> | ||
| 46 | <td><img src="themes/SlashOcean/cl.gif" width="7" height="10"></td> | ||
| 47 | <td><font face="verdana,helvetica,arial" size="1" color="#ffffff"><B>Main Menu</B></font></td> | ||
| 48 | <td align="right"><img src="themes/SlashOcean/cr.gif" width="7" height="10" alt=""></td> | ||
| 49 | <td bgcolor="#FFFFFF" align="right"><img src="themes/SlashOcean/pix.gif" width="3" height="3"></td> | ||
| 50 | </tr></table> | ||
| 51 | <table width="100%" border="0" cellpadding="0" cellspacing="0"> | ||
| 52 | <tr bgcolor="#101070"><td colspan="3"><img src="themes/SlashOcean/pix.gif" width="1" height="1"></td></tr> | ||
| 53 | <tr bgcolor="#ffffff"> | ||
| 54 | <td background="themes/SlashOcean/sl.gif"><img src="themes/SlashOcean/pix.gif" width="3" height="3" alt=""></td> | ||
| 55 | <td width="100%"> | ||
| 56 | <table width="100%" border="0" cellpadding="5" cellspacing="0"><tr> | ||
| 57 | <td><font face="verdana,helvetica,arial" size="1"> | ||
| 58 | <li><a href=index.php>Home</a> | ||
| 59 | <li><a href=topics.php>News-Topics</a> | ||
| 60 | <li><a href=sections.php?op=listarticles&secid=1>About</a> | ||
| 61 | <li><a href=sections.php?op=listarticles&secid=2>Developers</a> | ||
| 62 | <li><a href=sections.php?op=listarticles&secid=3>Applications</a> | ||
| 63 | <li><a href=sections.php?op=listarticles&secid=7>Download</a> | ||
| 64 | <li><a href=forum/index.php>Forum</a> | ||
| 65 | <li><a href=http://freedb.music.sk/search/>Web-based Search</a> | ||
| 66 | <li><a href=links.php>Web Links</a> | ||
| 67 | <li><a href=user.php>Your Account</a> | ||
| 68 | <li><a href=submit.php>Submit News</a> | ||
| 69 | |||
| 70 | </font></td> | ||
| 71 | </tr></table> | ||
| 72 | |||
| 73 | |||
| 74 | </td><td background="themes/SlashOcean/sr.gif" align="right"><img src="themes/SlashOcean/pix.gif" width="3" height="3" alt=""></td> | ||
| 75 | </tr> | ||
| 76 | <tr bgcolor="#101070"><td colspan="3"><img src="themes/SlashOcean/pix.gif" width="1" height="1"></td></tr> | ||
| 77 | </table> | ||
| 78 | </td> | ||
| 79 | |||
| 80 | |||
| 81 | |||
| 82 | |||
| 83 | |||
| 84 | |||
| 85 | </tr></td></table> | ||
| 86 | <br> | ||
| 87 | <table border=0><tr><td> | ||
| 88 | |||
| 89 | <table width="115" border="0" cellpadding="0" cellspacing="0"><tr valign="top" bgcolor="#101070"> | ||
| 90 | <td bgcolor="#FFFFFF"><img src="themes/SlashOcean/pix.gif" width="3" height="3"></td> | ||
| 91 | <td><img src="themes/SlashOcean/cl.gif" width="7" height="10"></td> | ||
| 92 | <td><font face="verdana,helvetica,arial" size="1" color="#ffffff"><B>FAQ</B></font></td> | ||
| 93 | <td align="right"><img src="themes/SlashOcean/cr.gif" width="7" height="10" alt=""></td> | ||
| 94 | <td bgcolor="#FFFFFF" align="right"><img src="themes/SlashOcean/pix.gif" width="3" height="3"></td> | ||
| 95 | </tr></table> | ||
| 96 | <table width="100%" border="0" cellpadding="0" cellspacing="0"> | ||
| 97 | <tr bgcolor="#101070"><td colspan="3"><img src="themes/SlashOcean/pix.gif" width="1" height="1"></td></tr> | ||
| 98 | <tr bgcolor="#ffffff"> | ||
| 99 | <td background="themes/SlashOcean/sl.gif"><img src="themes/SlashOcean/pix.gif" width="3" height="3" alt=""></td> | ||
| 100 | <td width="100%"> | ||
| 101 | <table width="100%" border="0" cellpadding="5" cellspacing="0"><tr> | ||
| 102 | <td><font face="verdana,helvetica,arial" size="1"> | ||
| 103 | Our FAQ can be found <a href="http://freedb.freedb.org/sections.php?op=viewarticle&artid=26">here</a>.<br> | ||
| 104 | Please read the FAQ before asking questions via email. </font></td> | ||
| 105 | </tr></table> | ||
| 106 | |||
| 107 | |||
| 108 | </td><td background="themes/SlashOcean/sr.gif" align="right"><img src="themes/SlashOcean/pix.gif" width="3" height="3" alt=""></td> | ||
| 109 | </tr> | ||
| 110 | <tr bgcolor="#101070"><td colspan="3"><img src="themes/SlashOcean/pix.gif" width="1" height="1"></td></tr> | ||
| 111 | </table> | ||
| 112 | </td> | ||
| 113 | |||
| 114 | </tr></td></table> | ||
| 115 | <br> | ||
| 116 | <table border=0><tr><td> | ||
| 117 | |||
| 118 | <table width="115" border="0" cellpadding="0" cellspacing="0"><tr valign="top" bgcolor="#101070"> | ||
| 119 | <td bgcolor="#FFFFFF"><img src="themes/SlashOcean/pix.gif" width="3" height="3"></td> | ||
| 120 | <td><img src="themes/SlashOcean/cl.gif" width="7" height="10"></td> | ||
| 121 | <td><font face="verdana,helvetica,arial" size="1" color="#ffffff"><B>Contact</B></font></td> | ||
| 122 | <td align="right"><img src="themes/SlashOcean/cr.gif" width="7" height="10" alt=""></td> | ||
| 123 | <td bgcolor="#FFFFFF" align="right"><img src="themes/SlashOcean/pix.gif" width="3" height="3"></td> | ||
| 124 | </tr></table> | ||
| 125 | <table width="100%" border="0" cellpadding="0" cellspacing="0"> | ||
| 126 | <tr bgcolor="#101070"><td colspan="3"><img src="themes/SlashOcean/pix.gif" width="1" height="1"></td></tr> | ||
| 127 | <tr bgcolor="#ffffff"> | ||
| 128 | <td background="themes/SlashOcean/sl.gif"><img src="themes/SlashOcean/pix.gif" width="3" height="3" alt=""></td> | ||
| 129 | <td width="100%"> | ||
| 130 | <table width="100%" border="0" cellpadding="5" cellspacing="0"><tr> | ||
| 131 | <td><font face="verdana,helvetica,arial" size="1"> | ||
| 132 | General questions:<br> | ||
| 133 | <a href="mailto:info@freedb.org">info@freedb.org</a><hr> | ||
| 134 | Databaseupdates:<br> | ||
| 135 | <a href="mailto:updates@freedb.org">updates@freedb.org</a><br> | ||
| 136 | (<b>NOT</b> for submission!)<hr> | ||
| 137 | Please keep in mind that we are NOT the Nero-Support and please do not send CD-submits to the adresses above.<br> | ||
| 138 | Submits have to go to:<br> | ||
| 139 | <a href="mailto:freedb-submit@freedb.org">freedb-submit@freedb.org</a> </font></td> | ||
| 140 | </tr></table> | ||
| 141 | |||
| 142 | |||
| 143 | </td><td background="themes/SlashOcean/sr.gif" align="right"><img src="themes/SlashOcean/pix.gif" width="3" height="3" alt=""></td> | ||
| 144 | </tr> | ||
| 145 | <tr bgcolor="#101070"><td colspan="3"><img src="themes/SlashOcean/pix.gif" width="1" height="1"></td></tr> | ||
| 146 | </table> | ||
| 147 | </td> | ||
| 148 | |||
| 149 | </tr></td></table> | ||
| 150 | <br> | ||
| 151 | <table border=0><tr><td> | ||
| 152 | |||
| 153 | <table width="115" border="0" cellpadding="0" cellspacing="0"><tr valign="top" bgcolor="#101070"> | ||
| 154 | <td bgcolor="#FFFFFF"><img src="themes/SlashOcean/pix.gif" width="3" height="3"></td> | ||
| 155 | <td><img src="themes/SlashOcean/cl.gif" width="7" height="10"></td> | ||
| 156 | <td><font face="verdana,helvetica,arial" size="1" color="#ffffff"><B>Downloads</B></font></td> | ||
| 157 | <td align="right"><img src="themes/SlashOcean/cr.gif" width="7" height="10" alt=""></td> | ||
| 158 | <td bgcolor="#FFFFFF" align="right"><img src="themes/SlashOcean/pix.gif" width="3" height="3"></td> | ||
| 159 | </tr></table> | ||
| 160 | <table width="100%" border="0" cellpadding="0" cellspacing="0"> | ||
| 161 | <tr bgcolor="#101070"><td colspan="3"><img src="themes/SlashOcean/pix.gif" width="1" height="1"></td></tr> | ||
| 162 | <tr bgcolor="#ffffff"> | ||
| 163 | <td background="themes/SlashOcean/sl.gif"><img src="themes/SlashOcean/pix.gif" width="3" height="3" alt=""></td> | ||
| 164 | <td width="100%"> | ||
| 165 | <table width="100%" border="0" cellpadding="5" cellspacing="0"><tr> | ||
| 166 | <td><font face="verdana,helvetica,arial" size="1"> | ||
| 167 | The link to the database downloads is <a href="/sections.php?op=viewarticle&artid=12">here</a> </font></td> | ||
| 168 | </tr></table> | ||
| 169 | |||
| 170 | |||
| 171 | </td><td background="themes/SlashOcean/sr.gif" align="right"><img src="themes/SlashOcean/pix.gif" width="3" height="3" alt=""></td> | ||
| 172 | </tr> | ||
| 173 | <tr bgcolor="#101070"><td colspan="3"><img src="themes/SlashOcean/pix.gif" width="1" height="1"></td></tr> | ||
| 174 | </table> | ||
| 175 | </td> | ||
| 176 | |||
| 177 | |||
| 178 | </tr></td></table> | ||
| 179 | <td> </td><td valign="top" width="100%"> | ||
| 180 | |||
| 181 | <!-- columna de inicio --> | ||
| 182 | <center> | ||
| 183 | <table border=0 cellpadding=1 cellspacing=0 width=100% bgcolor=000000><tr><td> | ||
| 184 | <table border=0 cellpadding=8 cellspacing=0 width=100% bgcolor=FFFFFF> | ||
| 185 | <tr><td align=left><font face=Arial,Helvetica size=3> | ||
| 186 | <b>Database-format specification</b><br> | ||
| 187 | <font size=2> | ||
| 188 | <br><br> | ||
| 189 | Due to problems with using backslashes on our Webpage, we cannot display the database-format specification directly here.<br> | ||
| 190 | But you can find it <a href="http://www.freedb.org/software/old/DBFORMAT">here</a> as a text-document. | ||
| 191 | </tr></td> | ||
| 192 | <tr><td align=center><font face=Arial,Helvetica> | ||
| 193 | | ||
| 194 | </tr></td> | ||
| 195 | </table></tr></td></table></center></td><td> </td> | ||
| 196 | |||
| 197 | |||
| 198 | </tr></table></td></tr></table><br><br> | ||
| 199 | |||
| 200 | <font face=Arial,Helvetica size=1><center> | ||
| 201 | <br> | ||
| 202 | <br> | ||
| 203 | <br> | ||
| 204 | <br> | ||
| 205 | </body> | ||
| 206 | </html> | ||
| @@ -0,0 +1,197 @@ | |||
| 1 | #include "acd.h" | ||
| 2 | #include <ctype.h> | ||
| 3 | |||
| 4 | /* see CDDBPROTO */ | ||
| 5 | static ulong | ||
| 6 | cddb_sum(int n) | ||
| 7 | { | ||
| 8 | int ret; | ||
| 9 | ret = 0; | ||
| 10 | while(n > 0) { | ||
| 11 | ret += n%10; | ||
| 12 | n /= 10; | ||
| 13 | } | ||
| 14 | return ret; | ||
| 15 | } | ||
| 16 | |||
| 17 | static ulong | ||
| 18 | diskid(Toc *t) | ||
| 19 | { | ||
| 20 | int i, n, tmp; | ||
| 21 | Msf *ms, *me; | ||
| 22 | |||
| 23 | n = 0; | ||
| 24 | for(i=0; i < t->ntrack; i++) | ||
| 25 | n += cddb_sum(t->track[i].start.m*60+t->track[i].start.s); | ||
| 26 | |||
| 27 | ms = &t->track[0].start; | ||
| 28 | me = &t->track[t->ntrack].start; | ||
| 29 | tmp = (me->m*60+me->s) - (ms->m*60+ms->s); | ||
| 30 | |||
| 31 | /* | ||
| 32 | * the spec says n%0xFF rather than n&0xFF. it's unclear which is correct. | ||
| 33 | * most CDs are in the database under both entries. | ||
| 34 | */ | ||
| 35 | return ((n & 0xFF) << 24 | (tmp << 8) | t->ntrack); | ||
| 36 | } | ||
| 37 | |||
| 38 | static void | ||
| 39 | append(char **d, char *s) | ||
| 40 | { | ||
| 41 | char *r; | ||
| 42 | if (*d == nil) | ||
| 43 | *d = estrdup(s); | ||
| 44 | else { | ||
| 45 | r = emalloc(strlen(*d) + strlen(s) + 1); | ||
| 46 | strcpy(r, *d); | ||
| 47 | strcat(r, s); | ||
| 48 | free(*d); | ||
| 49 | *d = r; | ||
| 50 | } | ||
| 51 | } | ||
| 52 | |||
| 53 | static int | ||
| 54 | cddbfilltoc(Toc *t) | ||
| 55 | { | ||
| 56 | int fd; | ||
| 57 | int i; | ||
| 58 | char *p, *q; | ||
| 59 | Biobuf bin; | ||
| 60 | Msf *m; | ||
| 61 | char *f[10]; | ||
| 62 | int nf; | ||
| 63 | char *id, *categ; | ||
| 64 | char gottrack[MTRACK]; | ||
| 65 | int gottitle; | ||
| 66 | |||
| 67 | fd = dial("tcp!freedb.freedb.org!888", 0, 0, 0); | ||
| 68 | if(fd < 0) { | ||
| 69 | fprint(2, "cannot dial: %r\n"); | ||
| 70 | return -1; | ||
| 71 | } | ||
| 72 | Binit(&bin, fd, OREAD); | ||
| 73 | |||
| 74 | if((p=Brdline(&bin, '\n')) == nil || atoi(p)/100 != 2) { | ||
| 75 | died: | ||
| 76 | close(fd); | ||
| 77 | Bterm(&bin); | ||
| 78 | fprint(2, "error talking to server\n"); | ||
| 79 | if(p) { | ||
| 80 | p[Blinelen(&bin)-1] = 0; | ||
| 81 | fprint(2, "server says: %s\n", p); | ||
| 82 | } | ||
| 83 | return -1; | ||
| 84 | } | ||
| 85 | |||
| 86 | fprint(fd, "cddb hello gre plan9 9cd 1.0\r\n"); | ||
| 87 | if((p = Brdline(&bin, '\n')) == nil || atoi(p)/100 != 2) | ||
| 88 | goto died; | ||
| 89 | |||
| 90 | fprint(fd, "cddb query %8.8lux %d", diskid(t), t->ntrack); | ||
| 91 | DPRINT(2, "cddb query %8.8lux %d", diskid(t), t->ntrack); | ||
| 92 | for(i=0; i<t->ntrack; i++) { | ||
| 93 | m = &t->track[i].start; | ||
| 94 | fprint(fd, " %d", (m->m*60+m->s)*75+m->f); | ||
| 95 | DPRINT(2, " %d", (m->m*60+m->s)*75+m->f); | ||
| 96 | } | ||
| 97 | m = &t->track[t->ntrack-1].end; | ||
| 98 | fprint(fd, " %d\r\n", m->m*60+m->s); | ||
| 99 | DPRINT(2, " %d\r\n", m->m*60+m->s); | ||
| 100 | |||
| 101 | if((p = Brdline(&bin, '\n')) == nil || atoi(p)/100 != 2) | ||
| 102 | goto died; | ||
| 103 | p[Blinelen(&bin)-1] = 0; | ||
| 104 | DPRINT(2, "cddb: %s\n", p); | ||
| 105 | nf = tokenize(p, f, nelem(f)); | ||
| 106 | if(nf < 1) | ||
| 107 | goto died; | ||
| 108 | |||
| 109 | switch(atoi(f[0])) { | ||
| 110 | case 200: /* exact match */ | ||
| 111 | if(nf < 3) | ||
| 112 | goto died; | ||
| 113 | categ = f[1]; | ||
| 114 | id = f[2]; | ||
| 115 | break; | ||
| 116 | case 211: /* close matches */ | ||
| 117 | if((p = Brdline(&bin, '\n')) == nil) | ||
| 118 | goto died; | ||
| 119 | if(p[0] == '.') /* no close matches? */ | ||
| 120 | goto died; | ||
| 121 | p[Blinelen(&bin)-1] = '\0'; | ||
| 122 | |||
| 123 | /* accept first match */ | ||
| 124 | nf = tokenize(p, f, nelem(f)); | ||
| 125 | if(nf < 2) | ||
| 126 | goto died; | ||
| 127 | categ = f[0]; | ||
| 128 | id = f[1]; | ||
| 129 | |||
| 130 | /* snarf rest of buffer */ | ||
| 131 | while(p[0] != '.') { | ||
| 132 | if((p = Brdline(&bin, '\n')) == nil) | ||
| 133 | goto died; | ||
| 134 | p[Blinelen(&bin)-1] = '\0'; | ||
| 135 | DPRINT(2, "cddb: %s\n", p); | ||
| 136 | } | ||
| 137 | break; | ||
| 138 | case 202: /* no match */ | ||
| 139 | default: | ||
| 140 | goto died; | ||
| 141 | } | ||
| 142 | |||
| 143 | /* fetch results for this cd */ | ||
| 144 | fprint(fd, "cddb read %s %s\r\n", categ, id); | ||
| 145 | |||
| 146 | memset(gottrack, 0, sizeof(gottrack)); | ||
| 147 | gottitle = 0; | ||
| 148 | do { | ||
| 149 | if((p = Brdline(&bin, '\n')) == nil) | ||
| 150 | goto died; | ||
| 151 | q = p+Blinelen(&bin)-1; | ||
| 152 | while(isspace(*q)) | ||
| 153 | *q-- = 0; | ||
| 154 | DPRINT(2, "cddb %s\n", p); | ||
| 155 | if(strncmp(p, "DTITLE=", 7) == 0) { | ||
| 156 | if (gottitle) | ||
| 157 | append(&t->title, p + 7); | ||
| 158 | else | ||
| 159 | t->title = estrdup(p+7); | ||
| 160 | gottitle = 1; | ||
| 161 | } else if(strncmp(p, "TTITLE", 6) == 0 && isdigit(p[6])) { | ||
| 162 | i = atoi(p+6); | ||
| 163 | if(i < t->ntrack) { | ||
| 164 | p += 6; | ||
| 165 | while(isdigit(*p)) | ||
| 166 | p++; | ||
| 167 | if(*p == '=') | ||
| 168 | p++; | ||
| 169 | |||
| 170 | if (gottrack[i]) | ||
| 171 | append(&t->track[i].title, p); | ||
| 172 | else | ||
| 173 | t->track[i].title = estrdup(p); | ||
| 174 | gottrack[i] = 1; | ||
| 175 | } | ||
| 176 | } | ||
| 177 | } while(*p != '.'); | ||
| 178 | |||
| 179 | fprint(fd, "quit\r\n"); | ||
| 180 | close(fd); | ||
| 181 | Bterm(&bin); | ||
| 182 | |||
| 183 | return 0; | ||
| 184 | } | ||
| 185 | |||
| 186 | void | ||
| 187 | cddbproc(void *v) | ||
| 188 | { | ||
| 189 | Drive *d; | ||
| 190 | Toc t; | ||
| 191 | |||
| 192 | threadsetname("cddbproc"); | ||
| 193 | d = v; | ||
| 194 | while(recv(d->cdbreq, &t)) | ||
| 195 | if(cddbfilltoc(&t) == 0) | ||
| 196 | send(d->cdbreply, &t); | ||
| 197 | } | ||
| @@ -0,0 +1,894 @@ | |||
| 1 | <html><html> | ||
| 2 | <head> | ||
| 3 | <title>::freedb.org::</title> | ||
| 4 | </head> | ||
| 5 | |||
| 6 | <body bgcolor="#FFFFFF" text="#000000" link="#101070" vlink="#101070"> | ||
| 7 | |||
| 8 | <center> | ||
| 9 | |||
| 10 | <table cellpadding=0 cellspacing=0 border=0 width="99%" align=center><tr><td align=left> | ||
| 11 | <a href="/"> | ||
| 12 | <table border=0> | ||
| 13 | <td bgcolor="#ffffff"> | ||
| 14 | <table border=0 width=100% cellpadding=0 cellspacing=0> | ||
| 15 | <td bgcolor=#101070> | ||
| 16 | <table border=0> | ||
| 17 | <td bgcolor=#ffffff><font face="Arial,Helvetica,Lucida" color="#101070" size=8><b>freedb</b></td> | ||
| 18 | <td bgcolor=#101070><font face="Arial,Helvetica,Lucida" color="#ffffff" size=8><b>.org</b></td> | ||
| 19 | </table> | ||
| 20 | </td> | ||
| 21 | <tr> | ||
| 22 | <td align=right><font face="Arial,Helvetica,Lucida" color="#101070" size=2><b>a free approach to cddbp | ||
| 23 | </table> | ||
| 24 | </td> | ||
| 25 | </table> | ||
| 26 | </a> | ||
| 27 | </td><td align=right width=100%> | ||
| 28 | <form action="search.php" method=post> | ||
| 29 | <font face=Arial,Helvetica size=2><input type=name name=query width=20 size=20 length=20> | ||
| 30 | </td> | ||
| 31 | <td align=right> <input type=image src=images/menu/english/search.gif border=0 align=middle></td> | ||
| 32 | </form> | ||
| 33 | |||
| 34 | </td></tr></table><br> | ||
| 35 | <table cellpadding=0 cellspacing=0 border=0 width="99%" bgcolor=101070><tr><td> | ||
| 36 | <table cellpadding=5 cellspacing=1 border=0 width="100%" bgcolor=FFFFFF><tr><td> | ||
| 37 | <font face=Lucida,Verdana,Arial,Helvetica size=2>freedb.org - a free approach to cddbp</td></tr></table></td></tr></table><P> | ||
| 38 | |||
| 39 | <table width="99%" align=center cellpadding=0 cellspacing=0 border=0><tr> | ||
| 40 | <td valign=top rowspan=5> | ||
| 41 | |||
| 42 | <table border=0><tr><td> | ||
| 43 | |||
| 44 | <table width="115" border="0" cellpadding="0" cellspacing="0"><tr valign="top" bgcolor="#101070"> | ||
| 45 | <td bgcolor="#FFFFFF"><img src="themes/SlashOcean/pix.gif" width="3" height="3"></td> | ||
| 46 | <td><img src="themes/SlashOcean/cl.gif" width="7" height="10"></td> | ||
| 47 | <td><font face="verdana,helvetica,arial" size="1" color="#ffffff"><B>Main Menu</B></font></td> | ||
| 48 | <td align="right"><img src="themes/SlashOcean/cr.gif" width="7" height="10" alt=""></td> | ||
| 49 | <td bgcolor="#FFFFFF" align="right"><img src="themes/SlashOcean/pix.gif" width="3" height="3"></td> | ||
| 50 | </tr></table> | ||
| 51 | <table width="100%" border="0" cellpadding="0" cellspacing="0"> | ||
| 52 | <tr bgcolor="#101070"><td colspan="3"><img src="themes/SlashOcean/pix.gif" width="1" height="1"></td></tr> | ||
| 53 | <tr bgcolor="#ffffff"> | ||
| 54 | <td background="themes/SlashOcean/sl.gif"><img src="themes/SlashOcean/pix.gif" width="3" height="3" alt=""></td> | ||
| 55 | <td width="100%"> | ||
| 56 | <table width="100%" border="0" cellpadding="5" cellspacing="0"><tr> | ||
| 57 | <td><font face="verdana,helvetica,arial" size="1"> | ||
| 58 | <li><a href=index.php>Home</a> | ||
| 59 | <li><a href=topics.php>News-Topics</a> | ||
| 60 | <li><a href=sections.php?op=listarticles&secid=1>About</a> | ||
| 61 | <li><a href=sections.php?op=listarticles&secid=2>Developers</a> | ||
| 62 | <li><a href=sections.php?op=listarticles&secid=3>Applications</a> | ||
| 63 | <li><a href=sections.php?op=listarticles&secid=7>Download</a> | ||
| 64 | <li><a href=forum/index.php>Forum</a> | ||
| 65 | <li><a href=http://freedb.music.sk/search/>Web-based Search</a> | ||
| 66 | <li><a href=links.php>Web Links</a> | ||
| 67 | <li><a href=user.php>Your Account</a> | ||
| 68 | <li><a href=submit.php>Submit News</a> | ||
| 69 | |||
| 70 | </font></td> | ||
| 71 | </tr></table> | ||
| 72 | |||
| 73 | |||
| 74 | </td><td background="themes/SlashOcean/sr.gif" align="right"><img src="themes/SlashOcean/pix.gif" width="3" height="3" alt=""></td> | ||
| 75 | </tr> | ||
| 76 | <tr bgcolor="#101070"><td colspan="3"><img src="themes/SlashOcean/pix.gif" width="1" height="1"></td></tr> | ||
| 77 | </table> | ||
| 78 | </td> | ||
| 79 | |||
| 80 | |||
| 81 | |||
| 82 | |||
| 83 | |||
| 84 | |||
| 85 | </tr></td></table> | ||
| 86 | <br> | ||
| 87 | <table border=0><tr><td> | ||
| 88 | |||
| 89 | <table width="115" border="0" cellpadding="0" cellspacing="0"><tr valign="top" bgcolor="#101070"> | ||
| 90 | <td bgcolor="#FFFFFF"><img src="themes/SlashOcean/pix.gif" width="3" height="3"></td> | ||
| 91 | <td><img src="themes/SlashOcean/cl.gif" width="7" height="10"></td> | ||
| 92 | <td><font face="verdana,helvetica,arial" size="1" color="#ffffff"><B>FAQ</B></font></td> | ||
| 93 | <td align="right"><img src="themes/SlashOcean/cr.gif" width="7" height="10" alt=""></td> | ||
| 94 | <td bgcolor="#FFFFFF" align="right"><img src="themes/SlashOcean/pix.gif" width="3" height="3"></td> | ||
| 95 | </tr></table> | ||
| 96 | <table width="100%" border="0" cellpadding="0" cellspacing="0"> | ||
| 97 | <tr bgcolor="#101070"><td colspan="3"><img src="themes/SlashOcean/pix.gif" width="1" height="1"></td></tr> | ||
| 98 | <tr bgcolor="#ffffff"> | ||
| 99 | <td background="themes/SlashOcean/sl.gif"><img src="themes/SlashOcean/pix.gif" width="3" height="3" alt=""></td> | ||
| 100 | <td width="100%"> | ||
| 101 | <table width="100%" border="0" cellpadding="5" cellspacing="0"><tr> | ||
| 102 | <td><font face="verdana,helvetica,arial" size="1"> | ||
| 103 | Our FAQ can be found <a href="http://freedb.freedb.org/sections.php?op=viewarticle&artid=26">here</a>.<br> | ||
| 104 | Please read the FAQ before asking questions via email. </font></td> | ||
| 105 | </tr></table> | ||
| 106 | |||
| 107 | |||
| 108 | </td><td background="themes/SlashOcean/sr.gif" align="right"><img src="themes/SlashOcean/pix.gif" width="3" height="3" alt=""></td> | ||
| 109 | </tr> | ||
| 110 | <tr bgcolor="#101070"><td colspan="3"><img src="themes/SlashOcean/pix.gif" width="1" height="1"></td></tr> | ||
| 111 | </table> | ||
| 112 | </td> | ||
| 113 | |||
| 114 | </tr></td></table> | ||
| 115 | <br> | ||
| 116 | <table border=0><tr><td> | ||
| 117 | |||
| 118 | <table width="115" border="0" cellpadding="0" cellspacing="0"><tr valign="top" bgcolor="#101070"> | ||
| 119 | <td bgcolor="#FFFFFF"><img src="themes/SlashOcean/pix.gif" width="3" height="3"></td> | ||
| 120 | <td><img src="themes/SlashOcean/cl.gif" width="7" height="10"></td> | ||
| 121 | <td><font face="verdana,helvetica,arial" size="1" color="#ffffff"><B>Contact</B></font></td> | ||
| 122 | <td align="right"><img src="themes/SlashOcean/cr.gif" width="7" height="10" alt=""></td> | ||
| 123 | <td bgcolor="#FFFFFF" align="right"><img src="themes/SlashOcean/pix.gif" width="3" height="3"></td> | ||
| 124 | </tr></table> | ||
| 125 | <table width="100%" border="0" cellpadding="0" cellspacing="0"> | ||
| 126 | <tr bgcolor="#101070"><td colspan="3"><img src="themes/SlashOcean/pix.gif" width="1" height="1"></td></tr> | ||
| 127 | <tr bgcolor="#ffffff"> | ||
| 128 | <td background="themes/SlashOcean/sl.gif"><img src="themes/SlashOcean/pix.gif" width="3" height="3" alt=""></td> | ||
| 129 | <td width="100%"> | ||
| 130 | <table width="100%" border="0" cellpadding="5" cellspacing="0"><tr> | ||
| 131 | <td><font face="verdana,helvetica,arial" size="1"> | ||
| 132 | General questions:<br> | ||
| 133 | <a href="mailto:info@freedb.org">info@freedb.org</a><hr> | ||
| 134 | Databaseupdates:<br> | ||
| 135 | <a href="mailto:updates@freedb.org">updates@freedb.org</a><br> | ||
| 136 | (<b>NOT</b> for submission!)<hr> | ||
| 137 | Please keep in mind that we are NOT the Nero-Support and please do not send CD-submits to the adresses above.<br> | ||
| 138 | Submits have to go to:<br> | ||
| 139 | <a href="mailto:freedb-submit@freedb.org">freedb-submit@freedb.org</a> </font></td> | ||
| 140 | </tr></table> | ||
| 141 | |||
| 142 | |||
| 143 | </td><td background="themes/SlashOcean/sr.gif" align="right"><img src="themes/SlashOcean/pix.gif" width="3" height="3" alt=""></td> | ||
| 144 | </tr> | ||
| 145 | <tr bgcolor="#101070"><td colspan="3"><img src="themes/SlashOcean/pix.gif" width="1" height="1"></td></tr> | ||
| 146 | </table> | ||
| 147 | </td> | ||
| 148 | |||
| 149 | </tr></td></table> | ||
| 150 | <br> | ||
| 151 | <table border=0><tr><td> | ||
| 152 | |||
| 153 | <table width="115" border="0" cellpadding="0" cellspacing="0"><tr valign="top" bgcolor="#101070"> | ||
| 154 | <td bgcolor="#FFFFFF"><img src="themes/SlashOcean/pix.gif" width="3" height="3"></td> | ||
| 155 | <td><img src="themes/SlashOcean/cl.gif" width="7" height="10"></td> | ||
| 156 | <td><font face="verdana,helvetica,arial" size="1" color="#ffffff"><B>Downloads</B></font></td> | ||
| 157 | <td align="right"><img src="themes/SlashOcean/cr.gif" width="7" height="10" alt=""></td> | ||
| 158 | <td bgcolor="#FFFFFF" align="right"><img src="themes/SlashOcean/pix.gif" width="3" height="3"></td> | ||
| 159 | </tr></table> | ||
| 160 | <table width="100%" border="0" cellpadding="0" cellspacing="0"> | ||
| 161 | <tr bgcolor="#101070"><td colspan="3"><img src="themes/SlashOcean/pix.gif" width="1" height="1"></td></tr> | ||
| 162 | <tr bgcolor="#ffffff"> | ||
| 163 | <td background="themes/SlashOcean/sl.gif"><img src="themes/SlashOcean/pix.gif" width="3" height="3" alt=""></td> | ||
| 164 | <td width="100%"> | ||
| 165 | <table width="100%" border="0" cellpadding="5" cellspacing="0"><tr> | ||
| 166 | <td><font face="verdana,helvetica,arial" size="1"> | ||
| 167 | The link to the database downloads is <a href="/sections.php?op=viewarticle&artid=12">here</a> </font></td> | ||
| 168 | </tr></table> | ||
| 169 | |||
| 170 | |||
| 171 | </td><td background="themes/SlashOcean/sr.gif" align="right"><img src="themes/SlashOcean/pix.gif" width="3" height="3" alt=""></td> | ||
| 172 | </tr> | ||
| 173 | <tr bgcolor="#101070"><td colspan="3"><img src="themes/SlashOcean/pix.gif" width="1" height="1"></td></tr> | ||
| 174 | </table> | ||
| 175 | </td> | ||
| 176 | |||
| 177 | |||
| 178 | </tr></td></table> | ||
| 179 | <td> </td><td valign="top" width="100%"> | ||
| 180 | |||
| 181 | <!-- columna de inicio --> | ||
| 182 | <center> | ||
| 183 | <table border=0 cellpadding=1 cellspacing=0 width=100% bgcolor=000000><tr><td> | ||
| 184 | <table border=0 cellpadding=8 cellspacing=0 width=100% bgcolor=FFFFFF> | ||
| 185 | <tr><td align=left><font face=Arial,Helvetica size=3> | ||
| 186 | <b>CDDB-protocol documentation</b><br> | ||
| 187 | <font size=2> | ||
| 188 | <br><br> | ||
| 189 | <pre> | ||
| 190 | CDDB Protocol | ||
| 191 | |||
| 192 | By Steve Scherf and Ti Kan | ||
| 193 | -------------------------- | ||
| 194 | |||
| 195 | Revision: $Id: CDDBPROTO,v 1.6 1997/05/14 07:53:52 steve Exp steve $ | ||
| 196 | |||
| 197 | |||
| 198 | Notation: | ||
| 199 | -> : client to server | ||
| 200 | <- : server to client | ||
| 201 | |||
| 202 | terminating marker: `.' character in the beginning of a line | ||
| 203 | |||
| 204 | |||
| 205 | Server response code (three digit code): | ||
| 206 | |||
| 207 | First digit: | ||
| 208 | 1xx Informative message | ||
| 209 | 2xx Command OK | ||
| 210 | 3xx Command OK so far, continue | ||
| 211 | 4xx Command OK, but cannot be performed for some specified reasons | ||
| 212 | 5xx Command unimplemented, incorrect, or program error | ||
| 213 | |||
| 214 | Second digit: | ||
| 215 | x0x Ready for further commands | ||
| 216 | x1x More server-to-client output follows (until terminating marker) | ||
| 217 | x2x More client-to-server input follows (until terminating marker) | ||
| 218 | x3x Connection will close | ||
| 219 | |||
| 220 | Third digit: | ||
| 221 | xx[0-9] Command-specific code | ||
| 222 | |||
| 223 | |||
| 224 | CDDB Protocol Level 1: | ||
| 225 | ---------------------- | ||
| 226 | |||
| 227 | Server sign-on banner: | ||
| 228 | ---------------------- | ||
| 229 | <- code hostname CDDBP server version ready at date | ||
| 230 | |||
| 231 | code: | ||
| 232 | 200 OK, read/write allowed | ||
| 233 | 201 OK, read only | ||
| 234 | 432 No connections allowed: permission denied | ||
| 235 | 433 No connections allowed: X users allowed, Y currently active | ||
| 236 | 434 No connections allowed: system load too high | ||
| 237 | hostname: | ||
| 238 | Server host name. Example: xyz.fubar.com | ||
| 239 | version: | ||
| 240 | Version number of server software. Example: v1.0PL0 | ||
| 241 | date: | ||
| 242 | Current date and time. Example: Wed Mar 13 00:41:34 1996 | ||
| 243 | |||
| 244 | |||
| 245 | Initial client-server handshake: | ||
| 246 | -------------------------------- | ||
| 247 | Note: This handshake must occur before other cddb commands | ||
| 248 | are accepted by the server. | ||
| 249 | |||
| 250 | Client command: | ||
| 251 | -> cddb hello username hostname clientname version | ||
| 252 | |||
| 253 | username: | ||
| 254 | Login name of user. Example: johndoe | ||
| 255 | hostname: | ||
| 256 | Host name of client. Example: abc.fubar.com | ||
| 257 | clientname: | ||
| 258 | The name of the connecting client. Example: xmcd, cda, EasyCD, | ||
| 259 | et cetera. Do not use the name of another client which already | ||
| 260 | exists. | ||
| 261 | version: | ||
| 262 | Version number of client software. Example: v1.0PL0 | ||
| 263 | |||
| 264 | Server response: | ||
| 265 | <- code hello and welcome username@hostname running clientname version | ||
| 266 | |||
| 267 | code: | ||
| 268 | 200 Handshake successful | ||
| 269 | 431 Handshake not successful, closing connection | ||
| 270 | 402 Already shook hands | ||
| 271 | |||
| 272 | |||
| 273 | CDDB query: | ||
| 274 | ----------- | ||
| 275 | Client command: | ||
| 276 | -> cddb query discid ntrks off1 off2 ... nsecs | ||
| 277 | |||
| 278 | discid: | ||
| 279 | CD disc ID number. Example: f50a3b13 | ||
| 280 | ntrks: | ||
| 281 | Total number of tracks on CD. | ||
| 282 | off1, off2, ...: | ||
| 283 | Frame offset of the starting location of each track. | ||
| 284 | nsecs: | ||
| 285 | Total playing length of CD in seconds. | ||
| 286 | |||
| 287 | Server response: | ||
| 288 | <- code categ discid dtitle | ||
| 289 | or | ||
| 290 | <- code close matches found | ||
| 291 | <- categ discid dtitle | ||
| 292 | <- categ discid dtitle | ||
| 293 | <- (more matches...) | ||
| 294 | <- . | ||
| 295 | |||
| 296 | code: | ||
| 297 | 200 Found exact match | ||
| 298 | 211 Found inexact matches, list follows (until terminating marker) | ||
| 299 | 202 No match found | ||
| 300 | 403 Database entry is corrupt | ||
| 301 | 409 No handshake | ||
| 302 | categ: | ||
| 303 | CD category. Example: rock | ||
| 304 | discid: | ||
| 305 | CD disc ID number of the found entry. Example: f50a3b13 | ||
| 306 | dtitle: | ||
| 307 | The Disc Artist and Disc Title (The DTITLE line). For example: | ||
| 308 | Pink Floyd / The Dark Side of the Moon | ||
| 309 | |||
| 310 | |||
| 311 | CDDB read: | ||
| 312 | ---------- | ||
| 313 | Client command: | ||
| 314 | -> cddb read categ discid | ||
| 315 | |||
| 316 | categ: | ||
| 317 | CD category. Example: rock | ||
| 318 | discid: | ||
| 319 | CD disc ID number. Example: f50a3b13 | ||
| 320 | |||
| 321 | Server response: | ||
| 322 | <- code categ discid | ||
| 323 | <- # xmcd 2.0 CD database file | ||
| 324 | <- # ... | ||
| 325 | <- (CDDB data...) | ||
| 326 | <- . | ||
| 327 | or | ||
| 328 | <- code categ discid No such CD entry in database | ||
| 329 | |||
| 330 | code: | ||
| 331 | 210 OK, CDDB database entry follows (until terminating marker) | ||
| 332 | 401 Specified CDDB entry not found. | ||
| 333 | 402 Server error. | ||
| 334 | 403 Database entry is corrupt. | ||
| 335 | 409 No handshake. | ||
| 336 | categ: | ||
| 337 | CD category. Example: rock | ||
| 338 | discid: | ||
| 339 | CD disc ID number. Example: f50a3b13 | ||
| 340 | |||
| 341 | |||
| 342 | CDDB search: (command not yet implemented in freedb-serversoftware!) | ||
| 343 | ------------ | ||
| 344 | Client command: | ||
| 345 | -> cddb srch key search_type ... search_type | ||
| 346 | |||
| 347 | key: | ||
| 348 | Pseudo-regular expression to match. Expressions should meet the | ||
| 349 | following description: | ||
| 350 | |||
| 351 | - No white space. | ||
| 352 | - Printable characters only. | ||
| 353 | - Case is ignored. | ||
| 354 | search_type: | ||
| 355 | CDDB fields to search through. Example: title | ||
| 356 | Supported types: artist, title, extd, ext, trk | ||
| 357 | categ: | ||
| 358 | CD category. Example: rock | ||
| 359 | |||
| 360 | Server response: | ||
| 361 | <- code matches found | ||
| 362 | <- categ discid dtitle | ||
| 363 | <- categ discid dtitle | ||
| 364 | <- (more matches...) | ||
| 365 | <- . | ||
| 366 | |||
| 367 | code: | ||
| 368 | 210 OK, matches found, list follows (until terminating marker) | ||
| 369 | 401 No match found. | ||
| 370 | 409 No handshake. | ||
| 371 | categ: | ||
| 372 | CD category. Example: rock | ||
| 373 | dtitle: | ||
| 374 | The Disc Artist and Disc Title (The DTITLE line). For example: | ||
| 375 | Pink Floyd / The Dark Side of the Moon | ||
| 376 | |||
| 377 | |||
| 378 | CDDB write: | ||
| 379 | ----------- | ||
| 380 | Client command: | ||
| 381 | -> cddb write categ discid | ||
| 382 | |||
| 383 | categ: | ||
| 384 | CD category. Example: rock | ||
| 385 | discid: | ||
| 386 | CD disc ID number. Example: f50a3b13 | ||
| 387 | |||
| 388 | Server response: | ||
| 389 | <- code categ discid | ||
| 390 | |||
| 391 | code: | ||
| 392 | 320 OK, input CDDB data (until terminating marker) | ||
| 393 | 401 Permission denied. | ||
| 394 | 402 Server file system full/file access failed. | ||
| 395 | 409 No handshake. | ||
| 396 | 501 Entry rejected: reason for rejection. | ||
| 397 | categ: | ||
| 398 | CD category. Example: rock | ||
| 399 | discid: | ||
| 400 | CD disc ID number. Example: f50a3b13 | ||
| 401 | |||
| 402 | Client data: | ||
| 403 | -> # xmcd 2.0 CD database file | ||
| 404 | -> # ... | ||
| 405 | -> (CDDB data) | ||
| 406 | -> . | ||
| 407 | |||
| 408 | Server response: | ||
| 409 | <- code message | ||
| 410 | |||
| 411 | code: | ||
| 412 | 200 CDDB entry accepted | ||
| 413 | 401 CDDB entry rejected: reason why | ||
| 414 | message: | ||
| 415 | Message string to indicate write status: | ||
| 416 | CDDB entry accepted, or CDDB entry rejected. | ||
| 417 | |||
| 418 | |||
| 419 | Help information: | ||
| 420 | ----------------- | ||
| 421 | Client command: | ||
| 422 | -> help | ||
| 423 | or | ||
| 424 | -> help cmd | ||
| 425 | |||
| 426 | cmd: | ||
| 427 | CDDB command. Example: quit | ||
| 428 | |||
| 429 | or | ||
| 430 | |||
| 431 | -> help cmd subcmd | ||
| 432 | |||
| 433 | cmd: | ||
| 434 | CDDB command. Example: cddb | ||
| 435 | subcmd: | ||
| 436 | CDDB command argument. Example: query | ||
| 437 | |||
| 438 | Server response: | ||
| 439 | <- code Help information follows | ||
| 440 | <- (help data ...) | ||
| 441 | <- . | ||
| 442 | or | ||
| 443 | <- code no help information available | ||
| 444 | |||
| 445 | code: | ||
| 446 | 210 OK, help information follows (until terminating marker) | ||
| 447 | 401 No help information available | ||
| 448 | |||
| 449 | |||
| 450 | Log statistics: | ||
| 451 | --------------- | ||
| 452 | Client command: | ||
| 453 | -> log [[-l lines] [start date [end date]] | [day [days]] | [get"]] | ||
| 454 | |||
| 455 | lines: | ||
| 456 | The maximum number of lines to print for each data list in the | ||
| 457 | log statistics. | ||
| 458 | start date: | ||
| 459 | The date after which statistics should be calculated. Date is | ||
| 460 | of the format: hh[mm[ss[MM[DD[[CC]YY]]]]] | ||
| 461 | |||
| 462 | E.g.: 201200053196 for 8:12 PM on May 31, 1996. | ||
| 463 | 20120005312096 for 8:12 PM on May 31, 2096. | ||
| 464 | 080530 for today at at 8:15 and 30 seconds. | ||
| 465 | |||
| 466 | If the century ("CC") is omitted, a reasonable guess is made. If | ||
| 467 | this argument is omitted, all messages are considered. | ||
| 468 | end date: | ||
| 469 | The date after which statistics should not be calculated. If | ||
| 470 | omitted, the end date is assumed to be the current date. | ||
| 471 | day: | ||
| 472 | The string "day". This solitary argument will cause a log search | ||
| 473 | of messages generated within the last day. | ||
| 474 | days: | ||
| 475 | A positive numerical argument which modifies the number of days' | ||
| 476 | messages to searh. If this argument is left out, the default is 1. | ||
| 477 | get: | ||
| 478 | The string "get". This solitary argument will cause the server | ||
| 479 | to send the contents of the log file. | ||
| 480 | |||
| 481 | Server response: | ||
| 482 | <- code Log summary follows | ||
| 483 | <- (log stats) | ||
| 484 | <- . | ||
| 485 | or | ||
| 486 | <- code Log follows | ||
| 487 | <- (log stats) | ||
| 488 | <- . | ||
| 489 | |||
| 490 | code: | ||
| 491 | 210 OK, log summary follows (until terminating marker) | ||
| 492 | 211 OK, log follows (until terminating marker) | ||
| 493 | 401 Permission denied | ||
| 494 | 402 No log information available | ||
| 495 | 501 Invalid start/end date | ||
| 496 | |||
| 497 | |||
| 498 | Message of the day: | ||
| 499 | ------------------ | ||
| 500 | Client command: | ||
| 501 | -> motd | ||
| 502 | |||
| 503 | Server response: | ||
| 504 | <- code Last modified: date MOTD follows (until terminating marker) | ||
| 505 | <- (message text) | ||
| 506 | <- . | ||
| 507 | |||
| 508 | code: | ||
| 509 | 210 Last modified: 05/31/96 06:31:14 MOTD follows (until terminating marker) | ||
| 510 | 401 No message of the day available | ||
| 511 | date: | ||
| 512 | The date the text of the message of the day was modified. The date | ||
| 513 | appears in the following format: | ||
| 514 | |||
| 515 | 05/31/96 06:31:14 | ||
| 516 | |||
| 517 | This value may be used by client software as a message timestamp | ||
| 518 | for purposes of determining if it has already been displayed. This | ||
| 519 | format was chosen because it is more easily parsed than the standard | ||
| 520 | ctime() format. | ||
| 521 | |||
| 522 | |||
| 523 | Server protocol level: | ||
| 524 | ---------------------- | ||
| 525 | Client command: | ||
| 526 | -> proto [level] | ||
| 527 | |||
| 528 | level: | ||
| 529 | The (numerical) protocol level to set the server to. | ||
| 530 | |||
| 531 | Server response: | ||
| 532 | <- code CDDB protocol level: current cur_level, supported supported_level | ||
| 533 | or | ||
| 534 | <- code OK, protocol version now: cur_level | ||
| 535 | |||
| 536 | code: | ||
| 537 | 200 CDDB protocol level: current cur_level, supported supp_level | ||
| 538 | 201 OK, protocol version now: cur_level | ||
| 539 | 501 Illegal protocol level. | ||
| 540 | 502 Protocol level already cur_level. | ||
| 541 | cur_level: | ||
| 542 | The current protocol level at which the server is running. | ||
| 543 | supported_level: | ||
| 544 | The maximum supported protocol level. | ||
| 545 | |||
| 546 | |||
| 547 | Server sites: | ||
| 548 | -------------- | ||
| 549 | Client command: | ||
| 550 | -> sites | ||
| 551 | |||
| 552 | Server response: | ||
| 553 | <- code OK, site information follows (until terminating `.') | ||
| 554 | <- (data) | ||
| 555 | <- . | ||
| 556 | |||
| 557 | code: | ||
| 558 | 210 Ok, site information follows | ||
| 559 | 401 No site information available. | ||
| 560 | |||
| 561 | The data format is as follows: | ||
| 562 | site port latitude longitude description | ||
| 563 | |||
| 564 | The fields are as follows: | ||
| 565 | site: | ||
| 566 | The Internet address of the remote site. | ||
| 567 | port: | ||
| 568 | The port at which the server resides on that site. | ||
| 569 | latitude: | ||
| 570 | The latitude of the server site. The format is as follows: | ||
| 571 | CDDD.MM | ||
| 572 | Where "C" is the compass direction (N, S), "DDD" is the | ||
| 573 | degrees, and "MM" is the minutes. | ||
| 574 | longitude: | ||
| 575 | The longitude of the server site. Format is as above, except | ||
| 576 | the compass direction must be one of (E, W). | ||
| 577 | description: | ||
| 578 | A short description of the geographical location of the site. | ||
| 579 | |||
| 580 | Example: | ||
| 581 | cddb.moonsoft.com 888 N037.23 W122.01 Fremont, CA USA | ||
| 582 | |||
| 583 | |||
| 584 | Server status: | ||
| 585 | -------------- | ||
| 586 | Client command: | ||
| 587 | -> stat | ||
| 588 | |||
| 589 | Server response: | ||
| 590 | <- code OK, status information follows (until terminating `.') | ||
| 591 | <- (data) | ||
| 592 | <- . | ||
| 593 | |||
| 594 | code: | ||
| 595 | 210 Ok, status information follows | ||
| 596 | |||
| 597 | The possible data is as follows: | ||
| 598 | current proto: <current_level> | ||
| 599 | An integer representing the server's current operating protocol | ||
| 600 | level. | ||
| 601 | max proto: <max_level> | ||
| 602 | The maximum supported protocol level. | ||
| 603 | gets: <yes | no> | ||
| 604 | Whether or not the client is allowed to get log information, | ||
| 605 | according to the string "yes" or "no". | ||
| 606 | updates: <yes | no> | ||
| 607 | Whether or not the client is allowed to initiate a database | ||
| 608 | update, according to the string "yes" or "no". | ||
| 609 | posting: <yes | no> | ||
| 610 | Whether or not the client is allowed to post new entries, | ||
| 611 | according to the string "yes" or "no". | ||
| 612 | quotes: <yes | no> | ||
| 613 | Whether or not quoted arguments are enabled, according to | ||
| 614 | the string "yes" or "no". | ||
| 615 | current users: <num_users> | ||
| 616 | The number of users currently connected to the server. | ||
| 617 | max users: <num_max_users> | ||
| 618 | The number of users that can concurrently connect to the server. | ||
| 619 | strip ext: <yes | no> | ||
| 620 | Whether or not extended data is stripped by the server before | ||
| 621 | presented to the user. | ||
| 622 | Database entries: <num_db_entries> | ||
| 623 | The total number of entries in the database. | ||
| 624 | Database entries by category: | ||
| 625 | This field is followed by a list of catgories and the number | ||
| 626 | of entries in that category. Each entry is of the following | ||
| 627 | format: | ||
| 628 | |||
| 629 | <white space>catgory: <num_db_entries> | ||
| 630 | |||
| 631 | The list of entries is terminated by the first line that does | ||
| 632 | not begin with white space. | ||
| 633 | |||
| 634 | Pending file transmissions: | ||
| 635 | This field is followed by a list of sites that are fed new | ||
| 636 | database entries at periodic intervals, and the number of | ||
| 637 | entries that have yet to be transmitted to that site. | ||
| 638 | Each entry is of the following format: | ||
| 639 | |||
| 640 | <white space>site: <num_db_entries> | ||
| 641 | |||
| 642 | The list of entries is terminated by the first line that does | ||
| 643 | not begin with white space. | ||
| 644 | |||
| 645 | This list may grow as needed, so clients must expect possible | ||
| 646 | unrecognizable data. Also, additional fields may be added to | ||
| 647 | the currently existing lines, although no existing fields will | ||
| 648 | be removed or change position. | ||
| 649 | |||
| 650 | |||
| 651 | Server version: | ||
| 652 | --------------- | ||
| 653 | Client command: | ||
| 654 | -> ver | ||
| 655 | |||
| 656 | Server response: | ||
| 657 | <- code servername version copyright | ||
| 658 | or | ||
| 659 | <- code Version information follows | ||
| 660 | |||
| 661 | code: | ||
| 662 | 200 Version information. | ||
| 663 | 211 OK, version information follows (until terminating marker) | ||
| 664 | version: | ||
| 665 | Server version. Example: v1.0PL0 | ||
| 666 | copyright: | ||
| 667 | Copyright string. Example: Copyright (c) 1996 Steve Scherf | ||
| 668 | |||
| 669 | |||
| 670 | Database update: | ||
| 671 | ---------------- | ||
| 672 | Client command: | ||
| 673 | -> update | ||
| 674 | |||
| 675 | Server response: | ||
| 676 | <- code Updating the database. | ||
| 677 | or | ||
| 678 | <- code Permission denied. | ||
| 679 | or | ||
| 680 | <- code Unable to update the database. | ||
| 681 | |||
| 682 | code: | ||
| 683 | 200 Updating the database. | ||
| 684 | 401 Permission denied. | ||
| 685 | 402 Unable to update the database. | ||
| 686 | |||
| 687 | |||
| 688 | Server users: | ||
| 689 | ------------- | ||
| 690 | Client command: | ||
| 691 | -> whom | ||
| 692 | |||
| 693 | Server response: | ||
| 694 | <- code User list follows | ||
| 695 | |||
| 696 | code: | ||
| 697 | 210 OK, user list follows (until terminating marker) | ||
| 698 | 401 No user information available. | ||
| 699 | |||
| 700 | |||
| 701 | Client sign-off: | ||
| 702 | ---------------- | ||
| 703 | Client command: | ||
| 704 | -> quit | ||
| 705 | |||
| 706 | Server response: | ||
| 707 | <- code hostname closing connection. Goodbye. | ||
| 708 | |||
| 709 | code: | ||
| 710 | 230 OK, goodbye. | ||
| 711 | hostname: | ||
| 712 | Server host name. Example: xyz.fubar.com | ||
| 713 | |||
| 714 | |||
| 715 | General errors: | ||
| 716 | --------------- | ||
| 717 | |||
| 718 | Server response: | ||
| 719 | <- code error | ||
| 720 | code: | ||
| 721 | 402 Server error. | ||
| 722 | 408 CGI environment error. | ||
| 723 | 500 Command syntax error, command unknown, command unimplemented. | ||
| 724 | 530 Server error, server timeout. | ||
| 725 | |||
| 726 | |||
| 727 | Reserved errors: | ||
| 728 | ---------------- | ||
| 729 | |||
| 730 | The following error codes are reserved, and will never be returned as a | ||
| 731 | response to a CDDB protocol command. They are intended to be used internally | ||
| 732 | by clients that have a need for generating pseudo-responses. | ||
| 733 | |||
| 734 | 600-699 | ||
| 735 | |||
| 736 | |||
| 737 | CDDB Protocol Level 2: | ||
| 738 | ---------------------- | ||
| 739 | |||
| 740 | In all respects, protocol level 2 is the same as level 1, with the exceptions | ||
| 741 | listed below. | ||
| 742 | |||
| 743 | Arguments to commands may be surrounded by double quotes. All characters | ||
| 744 | within the quotes, including white space, are included in the argument. All | ||
| 745 | white space is replaced by the `_' (2Dh) character by the server. White space | ||
| 746 | is defined as ` ' (20h) and `^I' (control-I, or 09h). | ||
| 747 | |||
| 748 | Arguments containing quotes that should not be interpreted with the special | ||
| 749 | meaning described above should be escaped with a preceding backslash character, | ||
| 750 | or '' (5Ch). If an actual backslash appears in an argument, it should be | ||
| 751 | escaped with a preceding backslash. In both cases, the preceding backslash | ||
| 752 | will be removed from the input before being interpreted. | ||
| 753 | |||
| 754 | |||
| 755 | CDDB Protocol Level 3: | ||
| 756 | ---------------------- | ||
| 757 | |||
| 758 | Protocol level 3 is the same as level 2, with the exception listed below. | ||
| 759 | |||
| 760 | The output of the "sites" command has changed to meet the folowing description: | ||
| 761 | |||
| 762 | The data format is as follows: | ||
| 763 | site protocol port address latitude longitude description | ||
| 764 | |||
| 765 | The fields are as follows: | ||
| 766 | site: | ||
| 767 | The Internet address of the remote site. | ||
| 768 | protocol: | ||
| 769 | The transfer protocol used to access the site. | ||
| 770 | port: | ||
| 771 | The port at which the server resides on that site. | ||
| 772 | address: | ||
| 773 | Any additional addressing information needed to access the | ||
| 774 | server. For example, for HTTP protocol servers, this would be | ||
| 775 | the path to the CDDB server CGI script. This field will be | ||
| 776 | "-" if no additional addressing information is needed. | ||
| 777 | latitude: | ||
| 778 | The latitude of the server site. The format is as follows: | ||
| 779 | CDDD.MM | ||
| 780 | Where "C" is the compass direction (N, S), "DDD" is the | ||
| 781 | degrees, and "MM" is the minutes. | ||
| 782 | longitude: | ||
| 783 | The longitude of the server site. Format is as above, except | ||
| 784 | the compass direction must be one of (E, W). | ||
| 785 | description: | ||
| 786 | A short description of the geographical location of the site. | ||
| 787 | |||
| 788 | Example: | ||
| 789 | cddb.moonsoft.com cddbp 888 - N037.23 W122.01 Fremont, CA USA | ||
| 790 | cddb.moonsoft.com http 80 /~cddb/cddb.cgi N037.23 W122.01 Fremont,CA USA | ||
| 791 | |||
| 792 | Note that a site may appear once for each type of protocol it supports for | ||
| 793 | accessing the server. | ||
| 794 | |||
| 795 | |||
| 796 | Addendum A: Proper use of CDDBP: | ||
| 797 | -------------------------------- | ||
| 798 | |||
| 799 | There are a few guidelines that must be followed in order to make proper use | ||
| 800 | of CDDBP: | ||
| 801 | |||
| 802 | - When handshaking with the server via the "cddb hello" command, the client | ||
| 803 | must specify its own name and version, not that of some other client (such | ||
| 804 | as xmcd). Also, the "username" and "hostname" must be that of the actual | ||
| 805 | user running the program, not some hardwired value. | ||
| 806 | |||
| 807 | - Before performing a "cddb read", the client program MUST perform a | ||
| 808 | "cddb query". Failure to do so may result in the client program receiving | ||
| 809 | incorrect CDDB data from the server. Also, without performing a query, the | ||
| 810 | client program will not benefit from close matches in the event of the | ||
| 811 | lack of an exact match in the database. | ||
| 812 | |||
| 813 | - For accounting purposes, it is best if client programs only perform a single | ||
| 814 | "cddb query" for a particular disc before performing a "cddb read" for that | ||
| 815 | disc. | ||
| 816 | |||
| 817 | |||
| 818 | Addendum B: CDDBP under HTTP: | ||
| 819 | ----------------------------- | ||
| 820 | |||
| 821 | Accessing a server as a CGI script is done in much the same way as through | ||
| 822 | direct interaction. The command set is identical, though the method of | ||
| 823 | communication is through CDDBP commands encapsulated in the HTTP protocol. | ||
| 824 | The only limitation is that a single command may be executed per connection, | ||
| 825 | since HTTP is not truly interactive. For the server to be accessed in this | ||
| 826 | way, it must reside on the target host at a known URL which is accessible by | ||
| 827 | the host HTTP server. The client program must connect to the HTTP server on | ||
| 828 | the target host and issue an HTTP command with the appropriate CDDBP command | ||
| 829 | encapsulated within. | ||
| 830 | |||
| 831 | Commands may be submitted to servers in CGI mode using either the "GET" or | ||
| 832 | "POST" HTTP commands. Both methods are supported, and there is no real | ||
| 833 | difference between how both are to be used other than the syntactical | ||
| 834 | difference between the two methods. The "POST" method may provide the ability | ||
| 835 | to issue longer commands, though, depending on the architecture of the system | ||
| 836 | on which the server resides. | ||
| 837 | |||
| 838 | The server command must be sent as part of the "Request-URI" in the case | ||
| 839 | of the "GET" method, and as the "Entity-Body" in the case of the "POST" | ||
| 840 | method. In both cases, the command must be of the following form: | ||
| 841 | |||
| 842 | cmd=server+command&hello=joe+my.host.com+clientname+version&proto=1 | ||
| 843 | |||
| 844 | Where the text following the "cmd=" represents the CDDBP command to be | ||
| 845 | executed, the text following the "hello=" represents the arguments to | ||
| 846 | the "cddb hello" command that is implied by this operation, and the | ||
| 847 | text following the "proto=" represents the argument to the "proto" command | ||
| 848 | that is implied by this operation. | ||
| 849 | |||
| 850 | The "+" characters in the input represent spaces, and will be translated | ||
| 851 | by the server before performing the request. Special characters may be | ||
| 852 | represented by the sequence "%XX" where "XX" is a two-digit hex number | ||
| 853 | corresponding to the ASCII (ISO-8859-1) sequence of that character. The | ||
| 854 | "&" characters denote separations between the command, hello and proto | ||
| 855 | arguments. Newlines and carriage returns must not appear anywhere in the | ||
| 856 | string except at the end. | ||
| 857 | |||
| 858 | All CDDBP commands are supported under HTTP, except for "cddb hello", | ||
| 859 | "cddb write", "proto" and "quit". | ||
| 860 | |||
| 861 | For example, should user "joe" on system "my.host.com" be running xmcd 2.1, | ||
| 862 | a read request for his currenly playing CD might look like this: | ||
| 863 | |||
| 864 | cmd=cddb+read+rock+12345678&hello=joe+my.host.com+xmcd+2.1&proto=1 | ||
| 865 | |||
| 866 | The server will perform the implied "proto" and "cddb hello" commands, | ||
| 867 | and then perform the requested "cddb read" command. | ||
| 868 | |||
| 869 | Server response to the command is encapsulated in the HTTP server response, | ||
| 870 | and appears in the "Entity-Body" exactly as it would appear using the CDDBP | ||
| 871 | protocol. Note that the HTTP response "Entity-Header" is not guaranteed to | ||
| 872 | contain a "Content-Length" field, so clients should be prepared to accept | ||
| 873 | variable length input. This is no different from operation under CDDBP. The | ||
| 874 | header will always contain a Mime "Content-Type" field which describes the | ||
| 875 | body of data as "text/plain". | ||
| 876 | |||
| 877 | For more detailed information on HTTP and Mime, see RFC 1945 and RFC 1521. | ||
| 878 | </pre> | ||
| 879 | </tr></td> | ||
| 880 | <tr><td align=center><font face=Arial,Helvetica> | ||
| 881 | | ||
| 882 | </tr></td> | ||
| 883 | </table></tr></td></table></center></td><td> </td> | ||
| 884 | |||
| 885 | |||
| 886 | </tr></table></td></tr></table><br><br> | ||
| 887 | |||
| 888 | <font face=Arial,Helvetica size=1><center> | ||
| 889 | <br> | ||
| 890 | <br> | ||
| 891 | <br> | ||
| 892 | <br> | ||
| 893 | </body> | ||
| 894 | </html> | ||
| @@ -0,0 +1,159 @@ | |||
| 1 | |||
| 2 | CDDB DISCID | ||
| 3 | ----------- | ||
| 4 | |||
| 5 | Both forms of CDDB access require that the software compute a "disc | ||
| 6 | ID" which is an identifier that is used to access the CDDB. The disc | ||
| 7 | ID is a 8-digit hexadecimal (base-16) number, computed using data from | ||
| 8 | a CD's Table-of-Contents (TOC) in MSF (Minute Second Frame) form. The | ||
| 9 | algorithm is listed below in Appendix A. | ||
| 10 | |||
| 11 | It is crucial that your software compute the disc ID correctly. If it | ||
| 12 | does not generate the correct disc ID, it will not be compatible with CDDB. | ||
| 13 | Moreover, if your software submits CDDB entries with bad disc IDs to the | ||
| 14 | CDDB archives, it could compromise the integrity of the CDDB. | ||
| 15 | |||
| 16 | [...] | ||
| 17 | |||
| 18 | APPENDIX A - CDDB DISCID ALGORITHM | ||
| 19 | ---------------------------------- | ||
| 20 | |||
| 21 | The following is a C code example that illustrates how to generate the | ||
| 22 | CDDB disc ID. [...] A text description | ||
| 23 | of the algorithm follows, which should contain the necessary information | ||
| 24 | to code the algorithm in any programming language. | ||
| 25 | |||
| 26 | |||
| 27 | struct toc { | ||
| 28 | int min; | ||
| 29 | int sec; | ||
| 30 | int frame; | ||
| 31 | }; | ||
| 32 | |||
| 33 | struct toc cdtoc[100]; | ||
| 34 | |||
| 35 | int | ||
| 36 | read_cdtoc_from_drive(void) | ||
| 37 | { | ||
| 38 | /* Do whatever is appropriate to read the TOC of the CD | ||
| 39 | * into the cdtoc[] structure array. | ||
| 40 | */ | ||
| 41 | return (tot_trks); | ||
| 42 | } | ||
| 43 | |||
| 44 | int | ||
| 45 | cddb_sum(int n) | ||
| 46 | { | ||
| 47 | int ret; | ||
| 48 | |||
| 49 | /* For backward compatibility this algorithm must not change */ | ||
| 50 | |||
| 51 | ret = 0; | ||
| 52 | |||
| 53 | while (n > 0) { | ||
| 54 | ret = ret + (n % 10); | ||
| 55 | n = n / 10; | ||
| 56 | } | ||
| 57 | |||
| 58 | return (ret); | ||
| 59 | } | ||
| 60 | |||
| 61 | unsigned long | ||
| 62 | cddb_discid(int tot_trks) | ||
| 63 | { | ||
| 64 | int i, | ||
| 65 | t = 0, | ||
| 66 | n = 0; | ||
| 67 | |||
| 68 | /* For backward compatibility this algorithm must not change */ | ||
| 69 | |||
| 70 | i = 0; | ||
| 71 | |||
| 72 | while (i < tot_trks) { | ||
| 73 | n = n + cddb_sum((cdtoc[i].min * 60) + cdtoc[i].sec); | ||
| 74 | i++; | ||
| 75 | } | ||
| 76 | |||
| 77 | t = ((cdtoc[tot_trks].min * 60) + cdtoc[tot_trks].sec) - | ||
| 78 | ((cdtoc[0].min * 60) + cdtoc[0].sec); | ||
| 79 | |||
| 80 | return ((n % 0xff) << 24 | t << 8 | tot_trks); | ||
| 81 | } | ||
| 82 | |||
| 83 | main() | ||
| 84 | { | ||
| 85 | int tot_trks; | ||
| 86 | |||
| 87 | tot_trks = read_cdtoc_from_drive(); | ||
| 88 | printf("The discid is %08x", cddb_discid(tot_trks)); | ||
| 89 | } | ||
| 90 | |||
| 91 | |||
| 92 | This code assumes that your compiler and architecture support 32-bit | ||
| 93 | integers. | ||
| 94 | |||
| 95 | The cddb_discid function computes the discid based on the CD's TOC data | ||
| 96 | in MSF form. The frames are ignored for this purpose. The function is | ||
| 97 | passed a parameter of tot_trks (which is the total number of tracks on | ||
| 98 | the CD), and returns the discid integer number. | ||
| 99 | |||
| 100 | It is assumed that cdtoc[] is an array of data structures (records) | ||
| 101 | containing the fields min, sec and frame, which are the minute, second | ||
| 102 | and frame offsets (the starting location) of each track. This | ||
| 103 | information is read from the TOC of the CD. There are actually | ||
| 104 | tot_trks + 1 "active" elements in the array, the last one being the | ||
| 105 | offset of the lead-out (also known as track 0xAA). | ||
| 106 | |||
| 107 | The function loops through each track in the TOC, and for each track | ||
| 108 | it takes the (M * 60) + S (total offset in seconds) of the track and | ||
| 109 | feeds it to cddb_sum() function, which simply adds the value of each digit | ||
| 110 | in the decimal string representation of the number. A running sum of this | ||
| 111 | result for each track is kept in the variable n. | ||
| 112 | |||
| 113 | At the end of the loop: | ||
| 114 | 1. t is calculated by subtracting the (M * 60) + S offset of the lead-out | ||
| 115 | minus the (M * 60) + S offset of first track (yielding the length of | ||
| 116 | the disc in seconds). | ||
| 117 | |||
| 118 | 2. The result of (n modulo FFh) is left-shifted by 24 bits. | ||
| 119 | |||
| 120 | 3. t is left shifted by 8. | ||
| 121 | |||
| 122 | The bitwise-OR operation of result 2., 3. and the tot_trks number is | ||
| 123 | used as the discid. | ||
| 124 | |||
| 125 | The discid is represented in hexadecimal form for the purpose of | ||
| 126 | xmcd cddb file names and the DISCID= field in the xmcd cddb file itself. | ||
| 127 | If the hexadecimal string is less than 8 characters long, it is | ||
| 128 | zero-padded to 8 characters (i.e., 3a8f07 becomes 003a8f07). All | ||
| 129 | alpha characters in the string should be in lower case, where | ||
| 130 | applicable. | ||
| 131 | |||
| 132 | Important note for clients using the MS-Windows MCI interface: | ||
| 133 | |||
| 134 | The Windows MCI interface does not provide the MSF location of the | ||
| 135 | lead-out. Thus, you must compute the lead-out location by taking the | ||
| 136 | starting position of the last track and add the length of the last track | ||
| 137 | to it. However, the MCI interface returns the length of the last track | ||
| 138 | as ONE FRAME SHORT of the actual length found in the CD's TOC. In most | ||
| 139 | cases this does not affect the disc ID generated, because we truncate | ||
| 140 | the frame count when computing the disc ID anyway. However, if the | ||
| 141 | lead-out track has an actual a frame count of 0, the computed quantity | ||
| 142 | (based on the MSF data returned from the MCI interface) would result in | ||
| 143 | the seconds being one short and the frame count be 74. For example, | ||
| 144 | a CD with the last track at an offset of 48m 32s 12f and having a | ||
| 145 | track length of 2m 50s 63f has a lead-out offset of 51m 23s 0f. Windows | ||
| 146 | MCI incorrectly reports the length as 2m 50s 62f, which would yield a | ||
| 147 | lead-out offset of 51m 22s 74f, which causes the resulting truncated | ||
| 148 | disc length to be off by one second. This will cause an incorrect disc | ||
| 149 | ID to be generated. You should thus add one frame to the length of the | ||
| 150 | last track when computing the location of the lead-out. | ||
| 151 | |||
| 152 | The easiest way for Windows clients to compute the lead-out given information | ||
| 153 | in MSF format is like this: | ||
| 154 | |||
| 155 | (offset_minutes * 60 * 75) + (offset_seconds * 75) + offset_frames + | ||
| 156 | (length_minutes * 60 * 75) + (length_seconds * 75) + length_frames + 1 = X | ||
| 157 | |||
| 158 | Where X is the offset of the lead-out in frames. To find the lead-out in | ||
| 159 | seconds, simply divide by 75 and discard the remainder. | ||
| @@ -0,0 +1,220 @@ | |||
| 1 | <html><html> | ||
| 2 | <head> | ||
| 3 | <title>::freedb.org::</title> | ||
| 4 | </head> | ||
| 5 | |||
| 6 | <body bgcolor="#FFFFFF" text="#000000" link="#101070" vlink="#101070"> | ||
| 7 | |||
| 8 | <center> | ||
| 9 | |||
| 10 | <table cellpadding=0 cellspacing=0 border=0 width="99%" align=center><tr><td align=left> | ||
| 11 | <a href="/"> | ||
| 12 | <table border=0> | ||
| 13 | <td bgcolor="#ffffff"> | ||
| 14 | <table border=0 width=100% cellpadding=0 cellspacing=0> | ||
| 15 | <td bgcolor=#101070> | ||
| 16 | <table border=0> | ||
| 17 | <td bgcolor=#ffffff><font face="Arial,Helvetica,Lucida" color="#101070" size=8><b>freedb</b></td> | ||
| 18 | <td bgcolor=#101070><font face="Arial,Helvetica,Lucida" color="#ffffff" size=8><b>.org</b></td> | ||
| 19 | </table> | ||
| 20 | </td> | ||
| 21 | <tr> | ||
| 22 | <td align=right><font face="Arial,Helvetica,Lucida" color="#101070" size=2><b>a free approach to cddbp | ||
| 23 | </table> | ||
| 24 | </td> | ||
| 25 | </table> | ||
| 26 | </a> | ||
| 27 | </td><td align=right width=100%> | ||
| 28 | <form action="search.php" method=post> | ||
| 29 | <font face=Arial,Helvetica size=2><input type=name name=query width=20 size=20 length=20> | ||
| 30 | </td> | ||
| 31 | <td align=right> <input type=image src=images/menu/english/search.gif border=0 align=middle></td> | ||
| 32 | </form> | ||
| 33 | |||
| 34 | </td></tr></table><br> | ||
| 35 | <table cellpadding=0 cellspacing=0 border=0 width="99%" bgcolor=101070><tr><td> | ||
| 36 | <table cellpadding=5 cellspacing=1 border=0 width="100%" bgcolor=FFFFFF><tr><td> | ||
| 37 | <font face=Lucida,Verdana,Arial,Helvetica size=2>freedb.org - a free approach to cddbp</td></tr></table></td></tr></table><P> | ||
| 38 | |||
| 39 | <table width="99%" align=center cellpadding=0 cellspacing=0 border=0><tr> | ||
| 40 | <td valign=top rowspan=5> | ||
| 41 | |||
| 42 | <table border=0><tr><td> | ||
| 43 | |||
| 44 | <table width="115" border="0" cellpadding="0" cellspacing="0"><tr valign="top" bgcolor="#101070"> | ||
| 45 | <td bgcolor="#FFFFFF"><img src="themes/SlashOcean/pix.gif" width="3" height="3"></td> | ||
| 46 | <td><img src="themes/SlashOcean/cl.gif" width="7" height="10"></td> | ||
| 47 | <td><font face="verdana,helvetica,arial" size="1" color="#ffffff"><B>Main Menu</B></font></td> | ||
| 48 | <td align="right"><img src="themes/SlashOcean/cr.gif" width="7" height="10" alt=""></td> | ||
| 49 | <td bgcolor="#FFFFFF" align="right"><img src="themes/SlashOcean/pix.gif" width="3" height="3"></td> | ||
| 50 | </tr></table> | ||
| 51 | <table width="100%" border="0" cellpadding="0" cellspacing="0"> | ||
| 52 | <tr bgcolor="#101070"><td colspan="3"><img src="themes/SlashOcean/pix.gif" width="1" height="1"></td></tr> | ||
| 53 | <tr bgcolor="#ffffff"> | ||
| 54 | <td background="themes/SlashOcean/sl.gif"><img src="themes/SlashOcean/pix.gif" width="3" height="3" alt=""></td> | ||
| 55 | <td width="100%"> | ||
| 56 | <table width="100%" border="0" cellpadding="5" cellspacing="0"><tr> | ||
| 57 | <td><font face="verdana,helvetica,arial" size="1"> | ||
| 58 | <li><a href=index.php>Home</a> | ||
| 59 | <li><a href=topics.php>News-Topics</a> | ||
| 60 | <li><a href=sections.php?op=listarticles&secid=1>About</a> | ||
| 61 | <li><a href=sections.php?op=listarticles&secid=2>Developers</a> | ||
| 62 | <li><a href=sections.php?op=listarticles&secid=3>Applications</a> | ||
| 63 | <li><a href=sections.php?op=listarticles&secid=7>Download</a> | ||
| 64 | <li><a href=forum/index.php>Forum</a> | ||
| 65 | <li><a href=http://freedb.music.sk/search/>Web-based Search</a> | ||
| 66 | <li><a href=links.php>Web Links</a> | ||
| 67 | <li><a href=user.php>Your Account</a> | ||
| 68 | <li><a href=submit.php>Submit News</a> | ||
| 69 | |||
| 70 | </font></td> | ||
| 71 | </tr></table> | ||
| 72 | |||
| 73 | |||
| 74 | </td><td background="themes/SlashOcean/sr.gif" align="right"><img src="themes/SlashOcean/pix.gif" width="3" height="3" alt=""></td> | ||
| 75 | </tr> | ||
| 76 | <tr bgcolor="#101070"><td colspan="3"><img src="themes/SlashOcean/pix.gif" width="1" height="1"></td></tr> | ||
| 77 | </table> | ||
| 78 | </td> | ||
| 79 | |||
| 80 | |||
| 81 | |||
| 82 | |||
| 83 | |||
| 84 | |||
| 85 | </tr></td></table> | ||
| 86 | <br> | ||
| 87 | <table border=0><tr><td> | ||
| 88 | |||
| 89 | <table width="115" border="0" cellpadding="0" cellspacing="0"><tr valign="top" bgcolor="#101070"> | ||
| 90 | <td bgcolor="#FFFFFF"><img src="themes/SlashOcean/pix.gif" width="3" height="3"></td> | ||
| 91 | <td><img src="themes/SlashOcean/cl.gif" width="7" height="10"></td> | ||
| 92 | <td><font face="verdana,helvetica,arial" size="1" color="#ffffff"><B>FAQ</B></font></td> | ||
| 93 | <td align="right"><img src="themes/SlashOcean/cr.gif" width="7" height="10" alt=""></td> | ||
| 94 | <td bgcolor="#FFFFFF" align="right"><img src="themes/SlashOcean/pix.gif" width="3" height="3"></td> | ||
| 95 | </tr></table> | ||
| 96 | <table width="100%" border="0" cellpadding="0" cellspacing="0"> | ||
| 97 | <tr bgcolor="#101070"><td colspan="3"><img src="themes/SlashOcean/pix.gif" width="1" height="1"></td></tr> | ||
| 98 | <tr bgcolor="#ffffff"> | ||
| 99 | <td background="themes/SlashOcean/sl.gif"><img src="themes/SlashOcean/pix.gif" width="3" height="3" alt=""></td> | ||
| 100 | <td width="100%"> | ||
| 101 | <table width="100%" border="0" cellpadding="5" cellspacing="0"><tr> | ||
| 102 | <td><font face="verdana,helvetica,arial" size="1"> | ||
| 103 | Our FAQ can be found <a href="http://freedb.freedb.org/sections.php?op=viewarticle&artid=26">here</a>.<br> | ||
| 104 | Please read the FAQ before asking questions via email. </font></td> | ||
| 105 | </tr></table> | ||
| 106 | |||
| 107 | |||
| 108 | </td><td background="themes/SlashOcean/sr.gif" align="right"><img src="themes/SlashOcean/pix.gif" width="3" height="3" alt=""></td> | ||
| 109 | </tr> | ||
| 110 | <tr bgcolor="#101070"><td colspan="3"><img src="themes/SlashOcean/pix.gif" width="1" height="1"></td></tr> | ||
| 111 | </table> | ||
| 112 | </td> | ||
| 113 | |||
| 114 | </tr></td></table> | ||
| 115 | <br> | ||
| 116 | <table border=0><tr><td> | ||
| 117 | |||
| 118 | <table width="115" border="0" cellpadding="0" cellspacing="0"><tr valign="top" bgcolor="#101070"> | ||
| 119 | <td bgcolor="#FFFFFF"><img src="themes/SlashOcean/pix.gif" width="3" height="3"></td> | ||
| 120 | <td><img src="themes/SlashOcean/cl.gif" width="7" height="10"></td> | ||
| 121 | <td><font face="verdana,helvetica,arial" size="1" color="#ffffff"><B>Contact</B></font></td> | ||
| 122 | <td align="right"><img src="themes/SlashOcean/cr.gif" width="7" height="10" alt=""></td> | ||
| 123 | <td bgcolor="#FFFFFF" align="right"><img src="themes/SlashOcean/pix.gif" width="3" height="3"></td> | ||
| 124 | </tr></table> | ||
| 125 | <table width="100%" border="0" cellpadding="0" cellspacing="0"> | ||
| 126 | <tr bgcolor="#101070"><td colspan="3"><img src="themes/SlashOcean/pix.gif" width="1" height="1"></td></tr> | ||
| 127 | <tr bgcolor="#ffffff"> | ||
| 128 | <td background="themes/SlashOcean/sl.gif"><img src="themes/SlashOcean/pix.gif" width="3" height="3" alt=""></td> | ||
| 129 | <td width="100%"> | ||
| 130 | <table width="100%" border="0" cellpadding="5" cellspacing="0"><tr> | ||
| 131 | <td><font face="verdana,helvetica,arial" size="1"> | ||
| 132 | General questions:<br> | ||
| 133 | <a href="mailto:info@freedb.org">info@freedb.org</a><hr> | ||
| 134 | Databaseupdates:<br> | ||
| 135 | <a href="mailto:updates@freedb.org">updates@freedb.org</a><br> | ||
| 136 | (<b>NOT</b> for submission!)<hr> | ||
| 137 | Please keep in mind that we are NOT the Nero-Support and please do not send CD-submits to the adresses above.<br> | ||
| 138 | Submits have to go to:<br> | ||
| 139 | <a href="mailto:freedb-submit@freedb.org">freedb-submit@freedb.org</a> </font></td> | ||
| 140 | </tr></table> | ||
| 141 | |||
| 142 | |||
| 143 | </td><td background="themes/SlashOcean/sr.gif" align="right"><img src="themes/SlashOcean/pix.gif" width="3" height="3" alt=""></td> | ||
| 144 | </tr> | ||
| 145 | <tr bgcolor="#101070"><td colspan="3"><img src="themes/SlashOcean/pix.gif" width="1" height="1"></td></tr> | ||
| 146 | </table> | ||
| 147 | </td> | ||
| 148 | |||
| 149 | </tr></td></table> | ||
| 150 | <br> | ||
| 151 | <table border=0><tr><td> | ||
| 152 | |||
| 153 | <table width="115" border="0" cellpadding="0" cellspacing="0"><tr valign="top" bgcolor="#101070"> | ||
| 154 | <td bgcolor="#FFFFFF"><img src="themes/SlashOcean/pix.gif" width="3" height="3"></td> | ||
| 155 | <td><img src="themes/SlashOcean/cl.gif" width="7" height="10"></td> | ||
| 156 | <td><font face="verdana,helvetica,arial" size="1" color="#ffffff"><B>Downloads</B></font></td> | ||
| 157 | <td align="right"><img src="themes/SlashOcean/cr.gif" width="7" height="10" alt=""></td> | ||
| 158 | <td bgcolor="#FFFFFF" align="right"><img src="themes/SlashOcean/pix.gif" width="3" height="3"></td> | ||
| 159 | </tr></table> | ||
| 160 | <table width="100%" border="0" cellpadding="0" cellspacing="0"> | ||
| 161 | <tr bgcolor="#101070"><td colspan="3"><img src="themes/SlashOcean/pix.gif" width="1" height="1"></td></tr> | ||
| 162 | <tr bgcolor="#ffffff"> | ||
| 163 | <td background="themes/SlashOcean/sl.gif"><img src="themes/SlashOcean/pix.gif" width="3" height="3" alt=""></td> | ||
| 164 | <td width="100%"> | ||
| 165 | <table width="100%" border="0" cellpadding="5" cellspacing="0"><tr> | ||
| 166 | <td><font face="verdana,helvetica,arial" size="1"> | ||
| 167 | The link to the database downloads is <a href="/sections.php?op=viewarticle&artid=12">here</a> </font></td> | ||
| 168 | </tr></table> | ||
| 169 | |||
| 170 | |||
| 171 | </td><td background="themes/SlashOcean/sr.gif" align="right"><img src="themes/SlashOcean/pix.gif" width="3" height="3" alt=""></td> | ||
| 172 | </tr> | ||
| 173 | <tr bgcolor="#101070"><td colspan="3"><img src="themes/SlashOcean/pix.gif" width="1" height="1"></td></tr> | ||
| 174 | </table> | ||
| 175 | </td> | ||
| 176 | |||
| 177 | |||
| 178 | </tr></td></table> | ||
| 179 | <td> </td><td valign="top" width="100%"> | ||
| 180 | |||
| 181 | <!-- columna de inicio --> | ||
| 182 | <center> | ||
| 183 | <table border=0 cellpadding=1 cellspacing=0 width=100% bgcolor=000000><tr><td> | ||
| 184 | <table border=0 cellpadding=8 cellspacing=0 width=100% bgcolor=FFFFFF> | ||
| 185 | <tr><td align=left><font face=Arial,Helvetica size=3> | ||
| 186 | <b>Mailinglists</b><br> | ||
| 187 | <font size=2> | ||
| 188 | <br><br> | ||
| 189 | There are a couple of mailinglists available: | ||
| 190 | |||
| 191 | <h4>fdb-apps@freedb.org</h4> | ||
| 192 | |||
| 193 | This mailinglist is intended for all developers that want to | ||
| 194 | exchange tips and tricks, codesnippets and so on. Subcribe | ||
| 195 | to this list by sending an email to<br> | ||
| 196 | <a href="mailto:fdb-apps-request@freedb.org">fdb-apps-request@freedb.org</a><br> | ||
| 197 | with the word "subscribe" in the body of the email. | ||
| 198 | <h4>fdb-dev@freedb.org</h4> | ||
| 199 | |||
| 200 | This list is for anyone interested in developing the freedb.org | ||
| 201 | server software. Subcribe | ||
| 202 | to this list by sending an email to<br> | ||
| 203 | <a href="mailto:fdb-dev-request@freedb.org">fdb-dev-request@freedb.org</a><br> | ||
| 204 | with the word "subscribe" in the body of the email. | ||
| 205 | </tr></td> | ||
| 206 | <tr><td align=center><font face=Arial,Helvetica> | ||
| 207 | | ||
| 208 | </tr></td> | ||
| 209 | </table></tr></td></table></center></td><td> </td> | ||
| 210 | |||
| 211 | |||
| 212 | </tr></table></td></tr></table><br><br> | ||
| 213 | |||
| 214 | <font face=Arial,Helvetica size=1><center> | ||
| 215 | <br> | ||
| 216 | <br> | ||
| 217 | <br> | ||
| 218 | <br> | ||
| 219 | </body> | ||
| 220 | </html> | ||
| @@ -0,0 +1,135 @@ | |||
| 1 | #include "acd.h" | ||
| 2 | |||
| 3 | int debug; | ||
| 4 | |||
| 5 | void | ||
| 6 | usage(void) | ||
| 7 | { | ||
| 8 | fprint(2, "usage: acd dev\n"); | ||
| 9 | threadexitsall("usage"); | ||
| 10 | } | ||
| 11 | |||
| 12 | Alt | ||
| 13 | mkalt(Channel *c, void *v, int op) | ||
| 14 | { | ||
| 15 | Alt a; | ||
| 16 | |||
| 17 | memset(&a, 0, sizeof(a)); | ||
| 18 | a.c = c; | ||
| 19 | a.v = v; | ||
| 20 | a.op = op; | ||
| 21 | return a; | ||
| 22 | } | ||
| 23 | |||
| 24 | void | ||
| 25 | freetoc(Toc *t) | ||
| 26 | { | ||
| 27 | int i; | ||
| 28 | |||
| 29 | free(t->title); | ||
| 30 | for(i=0; i<t->ntrack; i++) | ||
| 31 | free(t->track[i].title); | ||
| 32 | } | ||
| 33 | |||
| 34 | void | ||
| 35 | eventwatcher(Drive *d) | ||
| 36 | { | ||
| 37 | enum { STATUS, WEVENT, TOCDISP, DBREQ, DBREPLY, NALT }; | ||
| 38 | Alt alts[NALT+1]; | ||
| 39 | Toc nt, tdb; | ||
| 40 | Event *e; | ||
| 41 | Window *w; | ||
| 42 | Cdstatus s; | ||
| 43 | char buf[40]; | ||
| 44 | |||
| 45 | w = d->w; | ||
| 46 | |||
| 47 | alts[STATUS] = mkalt(d->cstatus, &s, CHANRCV); | ||
| 48 | alts[WEVENT] = mkalt(w->cevent, &e, CHANRCV); | ||
| 49 | alts[TOCDISP] = mkalt(d->ctocdisp, &nt, CHANRCV); | ||
| 50 | alts[DBREQ] = mkalt(d->cdbreq, &tdb, CHANNOP); | ||
| 51 | alts[DBREPLY] = mkalt(d->cdbreply, &nt, CHANRCV); | ||
| 52 | alts[NALT] = mkalt(nil, nil, CHANEND); | ||
| 53 | for(;;) { | ||
| 54 | switch(alt(alts)) { | ||
| 55 | case STATUS: | ||
| 56 | //DPRINT(2, "s..."); | ||
| 57 | d->status = s; | ||
| 58 | if(s.state == Scompleted) { | ||
| 59 | s.state = Sunknown; | ||
| 60 | advancetrack(d, w); | ||
| 61 | } | ||
| 62 | //DPRINT(2, "status %d %d %d %M %M\n", s.state, s.track, s.index, s.abs, s.rel); | ||
| 63 | sprint(buf, "%d:%2.2d", s.rel.m, s.rel.s); | ||
| 64 | setplaytime(w, buf); | ||
| 65 | break; | ||
| 66 | case WEVENT: | ||
| 67 | //DPRINT(2, "w..."); | ||
| 68 | acmeevent(d, w, e); | ||
| 69 | break; | ||
| 70 | case TOCDISP: | ||
| 71 | //DPRINT(2,"td..."); | ||
| 72 | freetoc(&d->toc); | ||
| 73 | d->toc = nt; | ||
| 74 | drawtoc(w, d, &d->toc); | ||
| 75 | tdb = nt; | ||
| 76 | alts[DBREQ].op = CHANSND; | ||
| 77 | break; | ||
| 78 | case DBREQ: /* sent */ | ||
| 79 | //DPRINT(2,"dreq..."); | ||
| 80 | alts[DBREQ].op = CHANNOP; | ||
| 81 | break; | ||
| 82 | case DBREPLY: | ||
| 83 | //DPRINT(2,"drep..."); | ||
| 84 | freetoc(&d->toc); | ||
| 85 | d->toc = nt; | ||
| 86 | redrawtoc(w, &d->toc); | ||
| 87 | break; | ||
| 88 | } | ||
| 89 | } | ||
| 90 | } | ||
| 91 | |||
| 92 | void | ||
| 93 | threadmain(int argc, char **argv) | ||
| 94 | { | ||
| 95 | Scsi *s; | ||
| 96 | Drive *d; | ||
| 97 | char buf[80]; | ||
| 98 | |||
| 99 | ARGBEGIN{ | ||
| 100 | case 'v': | ||
| 101 | debug++; | ||
| 102 | scsiverbose++; | ||
| 103 | }ARGEND | ||
| 104 | |||
| 105 | if(argc != 1) | ||
| 106 | usage(); | ||
| 107 | |||
| 108 | fmtinstall('M', msfconv); | ||
| 109 | |||
| 110 | if((s = openscsi(argv[0])) == nil) | ||
| 111 | error("opening scsi: %r"); | ||
| 112 | |||
| 113 | d = malloc(sizeof(*d)); | ||
| 114 | if(d == nil) | ||
| 115 | error("out of memory"); | ||
| 116 | memset(d, 0, sizeof d); | ||
| 117 | |||
| 118 | d->scsi = s; | ||
| 119 | d->w = newwindow(); | ||
| 120 | d->ctocdisp = chancreate(sizeof(Toc), 0); | ||
| 121 | d->cdbreq = chancreate(sizeof(Toc), 0); | ||
| 122 | d->cdbreply = chancreate(sizeof(Toc), 0); | ||
| 123 | d->cstatus = chancreate(sizeof(Cdstatus), 0); | ||
| 124 | |||
| 125 | proccreate(wineventproc, d->w, STACK); | ||
| 126 | proccreate(cddbproc, d, STACK); | ||
| 127 | proccreate(cdstatusproc, d, STACK); | ||
| 128 | |||
| 129 | cleanname(argv[0]); | ||
| 130 | snprint(buf, sizeof(buf), "%s/", argv[0]); | ||
| 131 | winname(d->w, buf); | ||
| 132 | |||
| 133 | wintagwrite(d->w, "Stop Pause Resume Eject Ingest ", 5+6+7+6+7); | ||
| 134 | eventwatcher(d); | ||
| 135 | } | ||
| @@ -0,0 +1,22 @@ | |||
| 1 | </$objtype/mkfile | ||
| 2 | |||
| 3 | TARG=acd | ||
| 4 | BIN=/acme/bin/$objtype | ||
| 5 | |||
| 6 | OFILES=\ | ||
| 7 | acme.$O\ | ||
| 8 | cddb.$O\ | ||
| 9 | main.$O\ | ||
| 10 | mmc.$O\ | ||
| 11 | util.$O\ | ||
| 12 | win.$O\ | ||
| 13 | |||
| 14 | HFILES=acd.h | ||
| 15 | |||
| 16 | UPDATE=\ | ||
| 17 | mkfile\ | ||
| 18 | $HFILES\ | ||
| 19 | ${OFILES:%.$O=%.c}\ | ||
| 20 | ${TARG:%=/acme/bin/386/%}\ | ||
| 21 | |||
| 22 | </sys/src/cmd/mkone | ||
| @@ -0,0 +1,303 @@ | |||
| 1 | #include "acd.h" | ||
| 2 | |||
| 3 | int | ||
| 4 | msfconv(Fmt *fp) | ||
| 5 | { | ||
| 6 | Msf m; | ||
| 7 | |||
| 8 | m = va_arg(fp->args, Msf); | ||
| 9 | fmtprint(fp, "%d.%d.%d", m.m, m.s, m.f); | ||
| 10 | return 0; | ||
| 11 | } | ||
| 12 | |||
| 13 | static int | ||
| 14 | status(Drive *d) | ||
| 15 | { | ||
| 16 | uchar cmd[12]; | ||
| 17 | |||
| 18 | memset(cmd, 0, sizeof cmd); | ||
| 19 | cmd[0] = 0xBD; | ||
| 20 | return scsi(d->scsi, cmd, sizeof cmd, nil, 0, Snone); | ||
| 21 | } | ||
| 22 | |||
| 23 | static int | ||
| 24 | playmsf(Drive *d, Msf start, Msf end) | ||
| 25 | { | ||
| 26 | uchar cmd[12]; | ||
| 27 | |||
| 28 | memset(cmd, 0, sizeof cmd); | ||
| 29 | cmd[0] = 0x47; | ||
| 30 | cmd[3] = start.m; | ||
| 31 | cmd[4] = start.s; | ||
| 32 | cmd[5] = start.f; | ||
| 33 | cmd[6] = end.m; | ||
| 34 | cmd[7] = end.s; | ||
| 35 | cmd[8] = end.f; | ||
| 36 | |||
| 37 | return scsi(d->scsi, cmd, sizeof cmd, nil, 0, Snone); | ||
| 38 | } | ||
| 39 | |||
| 40 | int | ||
| 41 | playtrack(Drive *d, int start, int end) | ||
| 42 | { | ||
| 43 | Toc *t; | ||
| 44 | |||
| 45 | t = &d->toc; | ||
| 46 | |||
| 47 | if(t->ntrack == 0) | ||
| 48 | return -1; | ||
| 49 | |||
| 50 | if(start < 0) | ||
| 51 | start = 0; | ||
| 52 | if(end >= t->ntrack) | ||
| 53 | end = t->ntrack-1; | ||
| 54 | if(end < start) | ||
| 55 | end = start; | ||
| 56 | |||
| 57 | return playmsf(d, t->track[start].start, t->track[end].end); | ||
| 58 | } | ||
| 59 | |||
| 60 | int | ||
| 61 | resume(Drive *d) | ||
| 62 | { | ||
| 63 | uchar cmd[12]; | ||
| 64 | |||
| 65 | memset(cmd, 0, sizeof cmd); | ||
| 66 | cmd[0] = 0x4B; | ||
| 67 | cmd[8] = 0x01; | ||
| 68 | return scsi(d->scsi, cmd, sizeof cmd, nil, 0, Snone); | ||
| 69 | } | ||
| 70 | |||
| 71 | int | ||
| 72 | pause(Drive *d) | ||
| 73 | { | ||
| 74 | uchar cmd[12]; | ||
| 75 | |||
| 76 | memset(cmd, 0, sizeof cmd); | ||
| 77 | cmd[0] = 0x4B; | ||
| 78 | return scsi(d->scsi, cmd, sizeof cmd, nil, 0, Snone); | ||
| 79 | } | ||
| 80 | |||
| 81 | int | ||
| 82 | stop(Drive *d) | ||
| 83 | { | ||
| 84 | uchar cmd[12]; | ||
| 85 | |||
| 86 | memset(cmd, 0, sizeof cmd); | ||
| 87 | cmd[0] = 0x4E; | ||
| 88 | return scsi(d->scsi, cmd, sizeof cmd, nil, 0, Snone); | ||
| 89 | } | ||
| 90 | |||
| 91 | int | ||
| 92 | eject(Drive *d) | ||
| 93 | { | ||
| 94 | uchar cmd[12]; | ||
| 95 | |||
| 96 | memset(cmd, 0, sizeof cmd); | ||
| 97 | cmd[0] = 0x1B; | ||
| 98 | cmd[1] = 1; | ||
| 99 | cmd[4] = 2; | ||
| 100 | return scsi(d->scsi, cmd, sizeof cmd, nil, 0, Snone); | ||
| 101 | } | ||
| 102 | |||
| 103 | int | ||
| 104 | ingest(Drive *d) | ||
| 105 | { | ||
| 106 | uchar cmd[12]; | ||
| 107 | |||
| 108 | memset(cmd, 0, sizeof cmd); | ||
| 109 | cmd[0] = 0x1B; | ||
| 110 | cmd[1] = 1; | ||
| 111 | cmd[4] = 3; | ||
| 112 | return scsi(d->scsi, cmd, sizeof cmd, nil, 0, Snone); | ||
| 113 | } | ||
| 114 | |||
| 115 | static Msf | ||
| 116 | rdmsf(uchar *p) | ||
| 117 | { | ||
| 118 | Msf msf; | ||
| 119 | |||
| 120 | msf.m = p[0]; | ||
| 121 | msf.s = p[1]; | ||
| 122 | msf.f = p[2]; | ||
| 123 | return msf; | ||
| 124 | } | ||
| 125 | |||
| 126 | static ulong | ||
| 127 | rdlba(uchar *p) | ||
| 128 | { | ||
| 129 | return (p[0]<<16) | (p[1]<<8) | p[2]; | ||
| 130 | } | ||
| 131 | |||
| 132 | /* not a Drive, so that we don't accidentally touch Drive.toc */ | ||
| 133 | int | ||
| 134 | gettoc(Scsi *s, Toc *t) | ||
| 135 | { | ||
| 136 | int i, n; | ||
| 137 | uchar cmd[12]; | ||
| 138 | uchar resp[1024]; | ||
| 139 | |||
| 140 | Again: | ||
| 141 | memset(t, 0, sizeof(*t)); | ||
| 142 | memset(cmd, 0, sizeof cmd); | ||
| 143 | cmd[0] = 0x43; | ||
| 144 | cmd[1] = 0x02; | ||
| 145 | cmd[7] = sizeof(resp)>>8; | ||
| 146 | cmd[8] = sizeof(resp); | ||
| 147 | |||
| 148 | s->changetime = 1; | ||
| 149 | /* scsi sets nchange, changetime */ | ||
| 150 | if(scsi(s, cmd, sizeof cmd, resp, sizeof(resp), Sread) < 4) | ||
| 151 | return -1; | ||
| 152 | |||
| 153 | if(s->changetime == 0) { | ||
| 154 | t->ntrack = 0; | ||
| 155 | werrstr("no media"); | ||
| 156 | return -1; | ||
| 157 | } | ||
| 158 | |||
| 159 | if(t->nchange == s->nchange && t->changetime != 0) | ||
| 160 | return 0; | ||
| 161 | |||
| 162 | t->nchange = s->nchange; | ||
| 163 | t->changetime = s->changetime; | ||
| 164 | |||
| 165 | if(t->ntrack > MTRACK) | ||
| 166 | t->ntrack = MTRACK; | ||
| 167 | |||
| 168 | DPRINT(2, "%d %d\n", resp[3], resp[2]); | ||
| 169 | t->ntrack = resp[3]-resp[2]+1; | ||
| 170 | t->track0 = resp[2]; | ||
| 171 | |||
| 172 | n = ((resp[0]<<8) | resp[1])+2; | ||
| 173 | if(n < 4+8*(t->ntrack+1)) { | ||
| 174 | werrstr("bad read0 %d %d", n, 4+8*(t->ntrack+1)); | ||
| 175 | return -1; | ||
| 176 | } | ||
| 177 | |||
| 178 | for(i=0; i<=t->ntrack; i++) /* <=: track[ntrack] = end */ | ||
| 179 | t->track[i].start = rdmsf(resp+4+i*8+5); | ||
| 180 | |||
| 181 | for(i=0; i<t->ntrack; i++) | ||
| 182 | t->track[i].end = t->track[i+1].start; | ||
| 183 | |||
| 184 | memset(cmd, 0, sizeof cmd); | ||
| 185 | cmd[0] = 0x43; | ||
| 186 | cmd[7] = sizeof(resp)>>8; | ||
| 187 | cmd[8] = sizeof(resp); | ||
| 188 | if(scsi(s, cmd, sizeof cmd, resp, sizeof(resp), Sread) < 4) | ||
| 189 | return -1; | ||
| 190 | |||
| 191 | if(s->changetime != t->changetime || s->nchange != t->nchange) { | ||
| 192 | fprint(2, "disk changed underfoot; repeating\n"); | ||
| 193 | goto Again; | ||
| 194 | } | ||
| 195 | |||
| 196 | n = ((resp[0]<<8) | resp[1])+2; | ||
| 197 | if(n < 4+8*(t->ntrack+1)) { | ||
| 198 | werrstr("bad read"); | ||
| 199 | return -1; | ||
| 200 | } | ||
| 201 | |||
| 202 | for(i=0; i<=t->ntrack; i++) | ||
| 203 | t->track[i].bstart = rdlba(resp+4+i*8+5); | ||
| 204 | |||
| 205 | for(i=0; i<t->ntrack; i++) | ||
| 206 | t->track[i].bend = t->track[i+1].bstart; | ||
| 207 | |||
| 208 | return 0; | ||
| 209 | } | ||
| 210 | |||
| 211 | static void | ||
| 212 | dumptoc(Toc *t) | ||
| 213 | { | ||
| 214 | int i; | ||
| 215 | |||
| 216 | fprint(1, "%d tracks\n", t->ntrack); | ||
| 217 | for(i=0; i<t->ntrack; i++) | ||
| 218 | print("%d. %M-%M (%lud-%lud)\n", i+1, | ||
| 219 | t->track[i].start, t->track[i].end, | ||
| 220 | t->track[i].bstart, t->track[i].bend); | ||
| 221 | } | ||
| 222 | |||
| 223 | static void | ||
| 224 | ping(Drive *d) | ||
| 225 | { | ||
| 226 | uchar cmd[12]; | ||
| 227 | |||
| 228 | memset(cmd, 0, sizeof cmd); | ||
| 229 | cmd[0] = 0x43; | ||
| 230 | scsi(d->scsi, cmd, sizeof(cmd), nil, 0, Snone); | ||
| 231 | } | ||
| 232 | |||
| 233 | static int | ||
| 234 | playstatus(Drive *d, Cdstatus *stat) | ||
| 235 | { | ||
| 236 | uchar cmd[12], resp[16]; | ||
| 237 | |||
| 238 | memset(cmd, 0, sizeof cmd); | ||
| 239 | cmd[0] = 0x42; | ||
| 240 | cmd[1] = 0x02; | ||
| 241 | cmd[2] = 0x40; | ||
| 242 | cmd[3] = 0x01; | ||
| 243 | cmd[7] = sizeof(resp)>>8; | ||
| 244 | cmd[8] = sizeof(resp); | ||
| 245 | if(scsi(d->scsi, cmd, sizeof(cmd), resp, sizeof(resp), Sread) < 0) | ||
| 246 | return -1; | ||
| 247 | |||
| 248 | switch(resp[1]){ | ||
| 249 | case 0x11: | ||
| 250 | stat->state = Splaying; | ||
| 251 | break; | ||
| 252 | case 0x12: | ||
| 253 | stat->state = Spaused; | ||
| 254 | break; | ||
| 255 | case 0x13: | ||
| 256 | stat->state = Scompleted; | ||
| 257 | break; | ||
| 258 | case 0x14: | ||
| 259 | stat->state = Serror; | ||
| 260 | break; | ||
| 261 | case 0x00: /* not supported */ | ||
| 262 | case 0x15: /* no current status to return */ | ||
| 263 | default: | ||
| 264 | stat->state = Sunknown; | ||
| 265 | break; | ||
| 266 | } | ||
| 267 | |||
| 268 | stat->track = resp[6]; | ||
| 269 | stat->index = resp[7]; | ||
| 270 | stat->abs = rdmsf(resp+9); | ||
| 271 | stat->rel = rdmsf(resp+13); | ||
| 272 | return 0; | ||
| 273 | } | ||
| 274 | |||
| 275 | void | ||
| 276 | cdstatusproc(void *v) | ||
| 277 | { | ||
| 278 | Drive *d; | ||
| 279 | Toc t; | ||
| 280 | Cdstatus s; | ||
| 281 | |||
| 282 | t.changetime = ~0; | ||
| 283 | t.nchange = ~0; | ||
| 284 | |||
| 285 | threadsetname("cdstatusproc"); | ||
| 286 | d = v; | ||
| 287 | DPRINT(2, "cdstatus %d\n", getpid()); | ||
| 288 | for(;;) { | ||
| 289 | ping(d); | ||
| 290 | //DPRINT(2, "d %d %d t %d %d\n", d->scsi->changetime, d->scsi->nchange, t.changetime, t.nchange); | ||
| 291 | if(playstatus(d, &s) == 0) | ||
| 292 | send(d->cstatus, &s); | ||
| 293 | if(d->scsi->changetime != t.changetime || d->scsi->nchange != t.nchange) { | ||
| 294 | if(gettoc(d->scsi, &t) == 0) { | ||
| 295 | DPRINT(2, "sendtoc...\n"); | ||
| 296 | if(debug) dumptoc(&t); | ||
| 297 | send(d->ctocdisp, &t); | ||
| 298 | } else | ||
| 299 | DPRINT(2, "error: %r\n"); | ||
| 300 | } | ||
| 301 | sleep(1000); | ||
| 302 | } | ||
| 303 | } | ||
| @@ -0,0 +1,32 @@ | |||
| 1 | acd is composed of four procs | ||
| 2 | |||
| 3 | wineventproc (win.c:/^wineventproc) | ||
| 4 | reads acme window events, sends them along w->cevent. | ||
| 5 | |||
| 6 | cdstatusproc (mmc.c:/^cdstatusproc) | ||
| 7 | reads cd status once per second, sending | ||
| 8 | status updates to d->cstatus. | ||
| 9 | detects disk changes, sends new tocs to d->ctocdisp. | ||
| 10 | |||
| 11 | cddbproc (cddb.c:/^cddbproc) | ||
| 12 | reads tocs from d->cdbreq, if it finds | ||
| 13 | translations in the cddb, sends new tocs to d->cdbreply. | ||
| 14 | |||
| 15 | eventwatcher (main.c:/^eventwatcher) | ||
| 16 | the main event loop. | ||
| 17 | reads status from d->cstatus. | ||
| 18 | reads events from w->cevent. | ||
| 19 | reads new tocs to display from d->ctocdisp. | ||
| 20 | sends new tocs to translate to d->cdbreq. | ||
| 21 | reads new translated tocs from d->cdbreply. | ||
| 22 | |||
| 23 | an interesting bug in the original design: | ||
| 24 | both cdstatusproc and the eventwatcher proc | ||
| 25 | issue scsi commands. (the eventwatcher responds to | ||
| 26 | things such as Play, Stop, etc., as well as advancing the track.) | ||
| 27 | |||
| 28 | the sd(3) driver did not expect overlapped commands, | ||
| 29 | and crashed. | ||
| 30 | |||
| 31 | this has been fixed by making the scsi(2) commands threadsafe, | ||
| 32 | and making the sd(3) driver more robust. | ||
| @@ -0,0 +1,220 @@ | |||
| 1 | CDDB SUBMISSION | ||
| 2 | --------------- | ||
| 3 | |||
| 4 | Your software may allow users to enter CDDB data and then submit them | ||
| 5 | to the freedb archive. | ||
| 6 | There are two methods of submission: <a href="#email">via e-mail</a> or <a href="#http">via http</a> using submit.cgi | ||
| 7 | |||
| 8 | <a name="email"></a>1. Submission via e-mail | ||
| 9 | ------------------------ | ||
| 10 | |||
| 11 | Your software has to send the entry to the | ||
| 12 | following address: | ||
| 13 | |||
| 14 | freedb-submit@freedb.org | ||
| 15 | |||
| 16 | You may implement a button or somesuch in your software's user-interface | ||
| 17 | to facilitate this. The destination e-mail address should be made | ||
| 18 | user-configurable. | ||
| 19 | |||
| 20 | There should be one e-mail message per freedb entry. The mail Subject | ||
| 21 | line should be in the form "cddb category discid". For example: | ||
| 22 | |||
| 23 | Subject: cddb rock 850f970b | ||
| 24 | |||
| 25 | The body of the e-mail message should be in the format of a CDDB file | ||
| 26 | entry as described <a href="http://freedb.freedb.org/software/old/DBFORMAT">here</a>. The messages should contain only | ||
| 27 | plain ASCII text. Do not attach encoded information or add special | ||
| 28 | escape sequences. | ||
| 29 | |||
| 30 | Note that the disc ID specified in the mail Subject line should | ||
| 31 | also appear in the list of disc IDs in the DISCID= field of the | ||
| 32 | CDDB file entry. If not, it is considered an error and the submission | ||
| 33 | will be rejected. | ||
| 34 | |||
| 35 | You should only allow categories that are currently supported by the | ||
| 36 | freedb (blues, classical, country, data, folk, jazz, misc, newage, | ||
| 37 | reggae, rock, soundtrack). Submissions specifying unsupported | ||
| 38 | categories will be rejected. | ||
| 39 | |||
| 40 | Please do not allow a user to submit CD database entries that | ||
| 41 | have completely unfilled contents (i.e., blank information in the | ||
| 42 | disc artist/title as well as the track titles, or filled with | ||
| 43 | useless default information like "track 1", "track 2", etc.). | ||
| 44 | While the current CD database server checks and rejects submissions | ||
| 45 | that have a blank DTITLE line, it doesn't (and can't feasibly) check | ||
| 46 | the track titles effectively, nor can it check any of these fields | ||
| 47 | if they are filled with a default string. If it were, it would | ||
| 48 | have to be hacked to know about the default strings of every possible | ||
| 49 | client. | ||
| 50 | |||
| 51 | Thus, please design your client with this in mind. This is a somewhat | ||
| 52 | tricky thing to do, as some CDs contain blank tracks with no titles | ||
| 53 | and you need to allow for that. An example minimum requirement | ||
| 54 | that a CD player client should meet is listed below: | ||
| 55 | |||
| 56 | 1. Don't allow the "send" or "submit" feature to be activated if | ||
| 57 | the CD database information form is not edited at all. | ||
| 58 | 2. Check that the disc artist/title contains something (that the user | ||
| 59 | typed in). | ||
| 60 | 3. Check that all of the tracks have a title filled in by the user | ||
| 61 | (some (but not all!) may be blank, but not the default string). | ||
| 62 | |||
| 63 | This should minimize the number of useless garbage being submitted | ||
| 64 | into the CD database. | ||
| 65 | |||
| 66 | Before you release your software, please be sure that it produces | ||
| 67 | submissions that adheres to the CDDB file format, and that the frame | ||
| 68 | offset, disc length, and disc ID information are correctly computed. | ||
| 69 | For testing, please make your software send submissions to the | ||
| 70 | following e-mail address (rather than the real submission site at | ||
| 71 | freedb-submit@freedb.org): | ||
| 72 | |||
| 73 | test-submit@freedb.org | ||
| 74 | |||
| 75 | The test address performs sanity checking on the CDDB submission and | ||
| 76 | sends back pass/fail confirmation, but does not actually deposit the | ||
| 77 | entry in the CD database. | ||
| 78 | |||
| 79 | <a name="http"></a>2. Submission via http | ||
| 80 | ---------------------- | ||
| 81 | |||
| 82 | For submit via http, your application has to transmit the entry to the | ||
| 83 | database through a CGI program at the following URL: | ||
| 84 | |||
| 85 | http://freedb.freedb.org/~cddb/submit.cgi | ||
| 86 | |||
| 87 | Submissions are made through the CGI program as follows. You must only use | ||
| 88 | the "POST" method of sending data; "GET" is not supported. There are several | ||
| 89 | HTTP "Entity-Header" fields that must be included in the data followed by a | ||
| 90 | blank line, followed by the "Entity-Body" (a.k.a the CDDB entry) in the | ||
| 91 | format described in Appendix B below. The required header fields are: | ||
| 92 | |||
| 93 | Category: CDDB_category | ||
| 94 | Discid: CDDB_discid | ||
| 95 | User-Email: user@domain | ||
| 96 | Submit-Mode: test_or_submit | ||
| 97 | Content-Length: length_of_CDDB_entry | ||
| 98 | |||
| 99 | Where: | ||
| 100 | |||
| 101 | - "CDDB_category" is one of the valid CDDB categories (blues, classical, | ||
| 102 | country, data, folk, jazz, misc, newage, reggae, rock, soundtrack). | ||
| 103 | Invalid categories will result in the entry being rejected. | ||
| 104 | |||
| 105 | - "CDDB_discid" is the 8-digit hex CDDB disc ID of the entry as described in | ||
| 106 | the "<a href="http://freedb.freedb.org/sections.php?op=viewarticle&artid=6">Discid howto</a>" section. This must be the same disc ID that appears | ||
| 107 | in the "DISCID=" section of the entry being submitted. If not, the entry | ||
| 108 | will be rejected. | ||
| 109 | |||
| 110 | - "user@domain" is the valid email address of the user submitting the entry. | ||
| 111 | This is required in case a submission failure notice must be sent to the | ||
| 112 | user. | ||
| 113 | |||
| 114 | - "test_or_submit" is the word "test" or "submit" (without the surrounding | ||
| 115 | quotes) to indicate whether the submission is a test submission or a real | ||
| 116 | submission to the database, respectively. See <a href="#testsubmission">below</a> for an explanation of | ||
| 117 | test submissions. | ||
| 118 | |||
| 119 | - "length_of_CDDB_entry" is the size in bytes of the CDDB entry being | ||
| 120 | submitted. This number does not include the length of the header or the | ||
| 121 | blank line separating the HTTP header and the CDDB entry. | ||
| 122 | |||
| 123 | There are several additional optional HTTP header fields that may also | ||
| 124 | be specified (but which are currently not used by the freedb): | ||
| 125 | |||
| 126 | Charset: character_set_of_CDDB_entry | ||
| 127 | X-Cddbd-Note: message for user | ||
| 128 | |||
| 129 | Where: | ||
| 130 | |||
| 131 | - "character_set_of_CDDB_entry" is one of ISO-8859-1 or US-ASCII (lower case | ||
| 132 | may be used if desired). This specifies to the CDDB server which character | ||
| 133 | set the CDDB entry has been encoded in. If your application knows the | ||
| 134 | user's character set, then you should specify it here. Only these two | ||
| 135 | character sets are supported currently. DO NOT specify the character set | ||
| 136 | if your application does not have any way of verifying the user's character | ||
| 137 | set (i.e. do not guess; it's better not to specify it at all). | ||
| 138 | |||
| 139 | - "message for user" is an arbitrary message to be included at the top of | ||
| 140 | any rejection notice that may be sent to the submitting user. | ||
| 141 | |||
| 142 | An example submission showing the HTTP command, "Entity-Header" and "Entity- | ||
| 143 | Body" follows: | ||
| 144 | |||
| 145 | POST /~cddb/submit.cgi HTTP/1.0 | ||
| 146 | Category: rock | ||
| 147 | Discid: 2a09310a | ||
| 148 | User-Email: joe@joeshost.joesdomain.com | ||
| 149 | Submit-Mode: submit | ||
| 150 | Charset: ISO-8859-1 | ||
| 151 | X-Cddbd-Note: Problems with Super CD Player? Send email to support@supercd.com. | ||
| 152 | Content-Length: 820 | ||
| 153 | |||
| 154 | # xmcd | ||
| 155 | # | ||
| 156 | # Track frame offsets: | ||
| 157 | [ data omitted in this example for brevity ] | ||
| 158 | PLAYORDER= | ||
| 159 | |||
| 160 | Note the blank line between the "Content-Length" header field and the | ||
| 161 | "# xmcd" which marks the beginning of the CDDB entry. | ||
| 162 | |||
| 163 | When your application submits an entry through the CGI program, it will | ||
| 164 | respond with a 3-digit response code indicating whether or not the entry has | ||
| 165 | been forwarded to the freedb server for inclusion in the database, followed | ||
| 166 | by a textual description of the response code. For example: | ||
| 167 | |||
| 168 | 200 OK, submission has been sent. | ||
| 169 | 400 Internal error: failed to forward submission. | ||
| 170 | 500 Missing required header information. | ||
| 171 | |||
| 172 | These are but a few of the possible responses. | ||
| 173 | See the description of the <a href="http://freedb.freedb.org/sections.php?op=viewarticle&artid=28">CDDB server protocol</a> for more information on | ||
| 174 | handling response codes. | ||
| 175 | |||
| 176 | The body of the freedb entry being submitted should be sent verbatim as | ||
| 177 | described in the <a href="http://freedb.freedb.org/software/old/DBFORMAT">database-format specification</a>. DO NOT encode the data in any | ||
| 178 | way before transmitting it; data must be sent as raw text. For example, | ||
| 179 | Windows programmers should not use the Windows URL encode function prior to | ||
| 180 | calling the submit CGI program. Doing so may lead to corrupt data being sent | ||
| 181 | and also possibly to rejected submissions. | ||
| 182 | |||
| 183 | You may implement a button or somesuch in your software's user interface | ||
| 184 | to initiate submissions. Rejected submissions are automatically returned | ||
| 185 | via email to the sender specified in the "User-Email" header field with an | ||
| 186 | explanation of the reason for the rejection. | ||
| 187 | |||
| 188 | Please do not allow a user to submit CD database entries that | ||
| 189 | have completely unfilled contents (i.e., blank information in the | ||
| 190 | disc artist/title as well as the track titles, or filled with | ||
| 191 | useless default information like "track 1", "track 2", etc.). | ||
| 192 | While the current CD database server checks and rejects submissions | ||
| 193 | that have a blank DTITLE line, it doesn't (and can't feasibly) check | ||
| 194 | the track titles effectively, nor can it check any of these fields | ||
| 195 | if they are filled with a default string. If it were, it would | ||
| 196 | have to be hacked to know about the default strings of every possible | ||
| 197 | client. | ||
| 198 | |||
| 199 | Thus, please design your client with this in mind. This is a somewhat | ||
| 200 | tricky thing to do, as some CDs contain blank tracks with no titles | ||
| 201 | and you need to allow for that. An example minimum requirement | ||
| 202 | that a CD player client should meet is listed below: | ||
| 203 | |||
| 204 | 1. Don't allow the "send" or "submit" feature to be activated if | ||
| 205 | the CD database information form is not edited at all. | ||
| 206 | 2. Check that the disc artist/title contains something (that the user | ||
| 207 | typed in). | ||
| 208 | 3. Check that all of the tracks have a title filled in by the user. | ||
| 209 | (some (but not all!) may be blank, but not the default string). | ||
| 210 | |||
| 211 | Before you release your software, please be sure that it produces | ||
| 212 | submissions that adhere to the CDDB file format, and that the frame | ||
| 213 | offset, disc length, and disc ID information are correctly computed. | ||
| 214 | For testing, please make your software send submissions with the | ||
| 215 | "Submit-Mode" HTTP header field set to "test". | ||
| 216 | |||
| 217 | <a name="testsubmission"></a>CDDB submissions sent in test mode will be sanity-checked by the freedb server | ||
| 218 | and pass/fail confirmation sent back to the submitter, but will not actually | ||
| 219 | be deposited in the CD database. Please DO NOT send submisions in "submit" | ||
| 220 | mode until you have tested your program with several different CD's. | ||
| @@ -0,0 +1,59 @@ | |||
| 1 | #include "acd.h" | ||
| 2 | |||
| 3 | Toc thetoc; | ||
| 4 | |||
| 5 | void | ||
| 6 | tocthread(void *v) | ||
| 7 | { | ||
| 8 | Drive *d; | ||
| 9 | |||
| 10 | threadsetname("tocthread"); | ||
| 11 | d = v; | ||
| 12 | DPRINT(2, "recv ctocdisp?..."); | ||
| 13 | while(recv(d->ctocdisp, &thetoc) == 1) { | ||
| 14 | DPRINT(2, "recv ctocdisp!..."); | ||
| 15 | drawtoc(d->w, &thetoc); | ||
| 16 | DPRINT(2, "send dbreq...\n"); | ||
| 17 | send(d->ctocdbreq, &thetoc); | ||
| 18 | } | ||
| 19 | } | ||
| 20 | |||
| 21 | void | ||
| 22 | freetoc(Toc *t) | ||
| 23 | { | ||
| 24 | int i; | ||
| 25 | |||
| 26 | free(t->title); | ||
| 27 | for(i=0; i<t->ntrack; i++) | ||
| 28 | free(t->track[i].title); | ||
| 29 | } | ||
| 30 | |||
| 31 | void | ||
| 32 | cddbthread(void *v) | ||
| 33 | { | ||
| 34 | Drive *d; | ||
| 35 | Toc t; | ||
| 36 | |||
| 37 | threadsetname("cddbthread"); | ||
| 38 | d = v; | ||
| 39 | while(recv(d->ctocdbreply, &t) == 1) { | ||
| 40 | if(thetoc.nchange == t.nchange) { | ||
| 41 | freetoc(&thetoc); | ||
| 42 | thetoc = t; | ||
| 43 | redrawtoc(d->w, &thetoc); | ||
| 44 | } | ||
| 45 | } | ||
| 46 | } | ||
| 47 | |||
| 48 | void | ||
| 49 | cdstatusthread(void *v) | ||
| 50 | { | ||
| 51 | Drive *d; | ||
| 52 | Cdstatus s; | ||
| 53 | |||
| 54 | d = v; | ||
| 55 | |||
| 56 | for(;;) | ||
| 57 | recv(d->cstat, &s); | ||
| 58 | |||
| 59 | } | ||
| @@ -0,0 +1,89 @@ | |||
| 1 | #include "acd.h" | ||
| 2 | |||
| 3 | void* | ||
| 4 | emalloc(uint n) | ||
| 5 | { | ||
| 6 | void *p; | ||
| 7 | |||
| 8 | p = malloc(n); | ||
| 9 | if(p == nil) | ||
| 10 | error("can't malloc: %r"); | ||
| 11 | memset(p, 0, n); | ||
| 12 | return p; | ||
| 13 | } | ||
| 14 | |||
| 15 | char* | ||
| 16 | estrdup(char *s) | ||
| 17 | { | ||
| 18 | char *t; | ||
| 19 | |||
| 20 | t = emalloc(strlen(s)+1); | ||
| 21 | strcpy(t, s); | ||
| 22 | return t; | ||
| 23 | } | ||
| 24 | |||
| 25 | char* | ||
| 26 | estrstrdup(char *s, char *t) | ||
| 27 | { | ||
| 28 | char *u; | ||
| 29 | |||
| 30 | u = emalloc(strlen(s)+strlen(t)+1); | ||
| 31 | strcpy(u, s); | ||
| 32 | strcat(u, t); | ||
| 33 | return u; | ||
| 34 | } | ||
| 35 | |||
| 36 | char* | ||
| 37 | eappend(char *s, char *sep, char *t) | ||
| 38 | { | ||
| 39 | char *u; | ||
| 40 | |||
| 41 | if(t == nil) | ||
| 42 | u = estrstrdup(s, sep); | ||
| 43 | else{ | ||
| 44 | u = emalloc(strlen(s)+strlen(sep)+strlen(t)+1); | ||
| 45 | strcpy(u, s); | ||
| 46 | strcat(u, sep); | ||
| 47 | strcat(u, t); | ||
| 48 | } | ||
| 49 | free(s); | ||
| 50 | return u; | ||
| 51 | } | ||
| 52 | |||
| 53 | char* | ||
| 54 | egrow(char *s, char *sep, char *t) | ||
| 55 | { | ||
| 56 | s = eappend(s, sep, t); | ||
| 57 | free(t); | ||
| 58 | return s; | ||
| 59 | } | ||
| 60 | |||
| 61 | void | ||
| 62 | error(char *fmt, ...) | ||
| 63 | { | ||
| 64 | int n; | ||
| 65 | va_list arg; | ||
| 66 | char buf[256]; | ||
| 67 | |||
| 68 | fprint(2, "Mail: "); | ||
| 69 | va_start(arg, fmt); | ||
| 70 | n = vsnprint(buf, sizeof buf, fmt, arg); | ||
| 71 | va_end(arg); | ||
| 72 | write(2, buf, n); | ||
| 73 | write(2, "\n", 1); | ||
| 74 | threadexitsall(fmt); | ||
| 75 | } | ||
| 76 | |||
| 77 | void | ||
| 78 | ctlprint(int fd, char *fmt, ...) | ||
| 79 | { | ||
| 80 | int n; | ||
| 81 | va_list arg; | ||
| 82 | char buf[256]; | ||
| 83 | |||
| 84 | va_start(arg, fmt); | ||
| 85 | n = vsnprint(buf, sizeof buf, fmt, arg); | ||
| 86 | va_end(arg); | ||
| 87 | if(write(fd, buf, n) != n) | ||
| 88 | error("control file write error: %r"); | ||
| 89 | } | ||
| @@ -0,0 +1,320 @@ | |||
| 1 | #include "acd.h" | ||
| 2 | |||
| 3 | Window* | ||
| 4 | newwindow(void) | ||
| 5 | { | ||
| 6 | char buf[12]; | ||
| 7 | Window *w; | ||
| 8 | |||
| 9 | w = emalloc(sizeof(Window)); | ||
| 10 | w->ctl = open("/mnt/wsys/new/ctl", ORDWR|OCEXEC); | ||
| 11 | if(w->ctl<0 || read(w->ctl, buf, 12)!=12) | ||
| 12 | error("can't open window ctl file: %r"); | ||
| 13 | ctlprint(w->ctl, "noscroll\n"); | ||
| 14 | w->id = atoi(buf); | ||
| 15 | w->event = winopenfile(w, "event"); | ||
| 16 | w->addr = -1; /* will be opened when needed */ | ||
| 17 | w->body = nil; | ||
| 18 | w->data = -1; | ||
| 19 | w->cevent = chancreate(sizeof(Event*), 0); | ||
| 20 | if(w->cevent == nil) | ||
| 21 | error("cevent is nil: %r"); | ||
| 22 | return w; | ||
| 23 | } | ||
| 24 | |||
| 25 | void | ||
| 26 | winsetdump(Window *w, char *dir, char *cmd) | ||
| 27 | { | ||
| 28 | if(dir != nil) | ||
| 29 | ctlprint(w->ctl, "dumpdir %s\n", dir); | ||
| 30 | if(cmd != nil) | ||
| 31 | ctlprint(w->ctl, "dump %s\n", cmd); | ||
| 32 | } | ||
| 33 | |||
| 34 | void | ||
| 35 | wineventproc(void *v) | ||
| 36 | { | ||
| 37 | Window *w; | ||
| 38 | int i; | ||
| 39 | |||
| 40 | threadsetname("wineventproc"); | ||
| 41 | w = v; | ||
| 42 | for(i=0; ; i++){ | ||
| 43 | if(i >= NEVENT) | ||
| 44 | i = 0; | ||
| 45 | wingetevent(w, &w->e[i]); | ||
| 46 | sendp(w->cevent, &w->e[i]); | ||
| 47 | } | ||
| 48 | } | ||
| 49 | |||
| 50 | int | ||
| 51 | winopenfile(Window *w, char *f) | ||
| 52 | { | ||
| 53 | char buf[64]; | ||
| 54 | int fd; | ||
| 55 | |||
| 56 | sprint(buf, "/mnt/wsys/%d/%s", w->id, f); | ||
| 57 | fd = open(buf, ORDWR|OCEXEC); | ||
| 58 | if(fd < 0) | ||
| 59 | error("can't open window file %s: %r", f); | ||
| 60 | return fd; | ||
| 61 | } | ||
| 62 | |||
| 63 | void | ||
| 64 | wintagwrite(Window *w, char *s, int n) | ||
| 65 | { | ||
| 66 | int fd; | ||
| 67 | |||
| 68 | fd = winopenfile(w, "tag"); | ||
| 69 | if(write(fd, s, n) != n) | ||
| 70 | error("tag write: %r"); | ||
| 71 | close(fd); | ||
| 72 | } | ||
| 73 | |||
| 74 | void | ||
| 75 | winname(Window *w, char *s) | ||
| 76 | { | ||
| 77 | ctlprint(w->ctl, "name %s\n", s); | ||
| 78 | } | ||
| 79 | |||
| 80 | void | ||
| 81 | winopenbody(Window *w, int mode) | ||
| 82 | { | ||
| 83 | char buf[256]; | ||
| 84 | |||
| 85 | sprint(buf, "/mnt/wsys/%d/body", w->id); | ||
| 86 | w->body = Bopen(buf, mode|OCEXEC); | ||
| 87 | if(w->body == nil) | ||
| 88 | error("can't open window body file: %r"); | ||
| 89 | } | ||
| 90 | |||
| 91 | void | ||
| 92 | winclosebody(Window *w) | ||
| 93 | { | ||
| 94 | if(w->body != nil){ | ||
| 95 | Bterm(w->body); | ||
| 96 | w->body = nil; | ||
| 97 | } | ||
| 98 | } | ||
| 99 | |||
| 100 | void | ||
| 101 | winwritebody(Window *w, char *s, int n) | ||
| 102 | { | ||
| 103 | if(w->body == nil) | ||
| 104 | winopenbody(w, OWRITE); | ||
| 105 | if(Bwrite(w->body, s, n) != n) | ||
| 106 | error("write error to window: %r"); | ||
| 107 | } | ||
| 108 | |||
| 109 | int | ||
| 110 | wingetec(Window *w) | ||
| 111 | { | ||
| 112 | if(w->nbuf == 0){ | ||
| 113 | w->nbuf = read(w->event, w->buf, sizeof w->buf); | ||
| 114 | if(w->nbuf <= 0){ | ||
| 115 | /* probably because window has exited, and only called by wineventproc, so just shut down */ | ||
| 116 | threadexits(nil); | ||
| 117 | } | ||
| 118 | w->bufp = w->buf; | ||
| 119 | } | ||
| 120 | w->nbuf--; | ||
| 121 | return *w->bufp++; | ||
| 122 | } | ||
| 123 | |||
| 124 | int | ||
| 125 | wingeten(Window *w) | ||
| 126 | { | ||
| 127 | int n, c; | ||
| 128 | |||
| 129 | n = 0; | ||
| 130 | while('0'<=(c=wingetec(w)) && c<='9') | ||
| 131 | n = n*10+(c-'0'); | ||
| 132 | if(c != ' ') | ||
| 133 | error("event number syntax"); | ||
| 134 | return n; | ||
| 135 | } | ||
| 136 | |||
| 137 | int | ||
| 138 | wingeter(Window *w, char *buf, int *nb) | ||
| 139 | { | ||
| 140 | Rune r; | ||
| 141 | int n; | ||
| 142 | |||
| 143 | r = wingetec(w); | ||
| 144 | buf[0] = r; | ||
| 145 | n = 1; | ||
| 146 | if(r >= Runeself) { | ||
| 147 | while(!fullrune(buf, n)) | ||
| 148 | buf[n++] = wingetec(w); | ||
| 149 | chartorune(&r, buf); | ||
| 150 | } | ||
| 151 | *nb = n; | ||
| 152 | return r; | ||
| 153 | } | ||
| 154 | |||
| 155 | void | ||
| 156 | wingetevent(Window *w, Event *e) | ||
| 157 | { | ||
| 158 | int i, nb; | ||
| 159 | |||
| 160 | e->c1 = wingetec(w); | ||
| 161 | e->c2 = wingetec(w); | ||
| 162 | e->q0 = wingeten(w); | ||
| 163 | e->q1 = wingeten(w); | ||
| 164 | e->flag = wingeten(w); | ||
| 165 | e->nr = wingeten(w); | ||
| 166 | if(e->nr > EVENTSIZE) | ||
| 167 | error("event string too long"); | ||
| 168 | e->nb = 0; | ||
| 169 | for(i=0; i<e->nr; i++){ | ||
| 170 | e->r[i] = wingeter(w, e->b+e->nb, &nb); | ||
| 171 | e->nb += nb; | ||
| 172 | } | ||
| 173 | e->r[e->nr] = 0; | ||
| 174 | e->b[e->nb] = 0; | ||
| 175 | if(wingetec(w) != '\n') | ||
| 176 | error("event syntax error"); | ||
| 177 | } | ||
| 178 | |||
| 179 | void | ||
| 180 | winwriteevent(Window *w, Event *e) | ||
| 181 | { | ||
| 182 | fprint(w->event, "%c%c%d %d\n", e->c1, e->c2, e->q0, e->q1); | ||
| 183 | } | ||
| 184 | |||
| 185 | static int | ||
| 186 | nrunes(char *s, int nb) | ||
| 187 | { | ||
| 188 | int i, n; | ||
| 189 | Rune r; | ||
| 190 | |||
| 191 | n = 0; | ||
| 192 | for(i=0; i<nb; n++) | ||
| 193 | i += chartorune(&r, s+i); | ||
| 194 | return n; | ||
| 195 | } | ||
| 196 | |||
| 197 | void | ||
| 198 | winread(Window *w, uint q0, uint q1, char *data) | ||
| 199 | { | ||
| 200 | int m, n, nr; | ||
| 201 | char buf[256]; | ||
| 202 | |||
| 203 | if(w->addr < 0) | ||
| 204 | w->addr = winopenfile(w, "addr"); | ||
| 205 | if(w->data < 0) | ||
| 206 | w->data = winopenfile(w, "data"); | ||
| 207 | m = q0; | ||
| 208 | while(m < q1){ | ||
| 209 | n = sprint(buf, "#%d", m); | ||
| 210 | if(write(w->addr, buf, n) != n) | ||
| 211 | error("error writing addr: %r"); | ||
| 212 | n = read(w->data, buf, sizeof buf); | ||
| 213 | if(n <= 0) | ||
| 214 | error("reading data: %r"); | ||
| 215 | nr = nrunes(buf, n); | ||
| 216 | while(m+nr >q1){ | ||
| 217 | do; while(n>0 && (buf[--n]&0xC0)==0x80); | ||
| 218 | --nr; | ||
| 219 | } | ||
| 220 | if(n == 0) | ||
| 221 | break; | ||
| 222 | memmove(data, buf, n); | ||
| 223 | data += n; | ||
| 224 | *data = 0; | ||
| 225 | m += nr; | ||
| 226 | } | ||
| 227 | } | ||
| 228 | |||
| 229 | void | ||
| 230 | windormant(Window *w) | ||
| 231 | { | ||
| 232 | if(w->addr >= 0){ | ||
| 233 | close(w->addr); | ||
| 234 | w->addr = -1; | ||
| 235 | } | ||
| 236 | if(w->body != nil){ | ||
| 237 | Bterm(w->body); | ||
| 238 | w->body = nil; | ||
| 239 | } | ||
| 240 | if(w->data >= 0){ | ||
| 241 | close(w->data); | ||
| 242 | w->data = -1; | ||
| 243 | } | ||
| 244 | } | ||
| 245 | |||
| 246 | |||
| 247 | int | ||
| 248 | windel(Window *w, int sure) | ||
| 249 | { | ||
| 250 | if(sure) | ||
| 251 | write(w->ctl, "delete\n", 7); | ||
| 252 | else if(write(w->ctl, "del\n", 4) != 4) | ||
| 253 | return 0; | ||
| 254 | /* event proc will die due to read error from event file */ | ||
| 255 | windormant(w); | ||
| 256 | close(w->ctl); | ||
| 257 | w->ctl = -1; | ||
| 258 | close(w->event); | ||
| 259 | w->event = -1; | ||
| 260 | return 1; | ||
| 261 | } | ||
| 262 | |||
| 263 | void | ||
| 264 | winclean(Window *w) | ||
| 265 | { | ||
| 266 | if(w->body) | ||
| 267 | Bflush(w->body); | ||
| 268 | ctlprint(w->ctl, "clean\n"); | ||
| 269 | } | ||
| 270 | |||
| 271 | int | ||
| 272 | winsetaddr(Window *w, char *addr, int errok) | ||
| 273 | { | ||
| 274 | if(w->addr < 0) | ||
| 275 | w->addr = winopenfile(w, "addr"); | ||
| 276 | if(write(w->addr, addr, strlen(addr)) < 0){ | ||
| 277 | if(!errok) | ||
| 278 | error("error writing addr(%s): %r", addr); | ||
| 279 | return 0; | ||
| 280 | } | ||
| 281 | return 1; | ||
| 282 | } | ||
| 283 | |||
| 284 | int | ||
| 285 | winselect(Window *w, char *addr, int errok) | ||
| 286 | { | ||
| 287 | if(winsetaddr(w, addr, errok)){ | ||
| 288 | ctlprint(w->ctl, "dot=addr\n"); | ||
| 289 | return 1; | ||
| 290 | } | ||
| 291 | return 0; | ||
| 292 | } | ||
| 293 | |||
| 294 | char* | ||
| 295 | winreadbody(Window *w, int *np) /* can't use readfile because acme doesn't report the length */ | ||
| 296 | { | ||
| 297 | char *s; | ||
| 298 | int m, na, n; | ||
| 299 | |||
| 300 | if(w->body != nil) | ||
| 301 | winclosebody(w); | ||
| 302 | winopenbody(w, OREAD); | ||
| 303 | s = nil; | ||
| 304 | na = 0; | ||
| 305 | n = 0; | ||
| 306 | for(;;){ | ||
| 307 | if(na < n+512){ | ||
| 308 | na += 1024; | ||
| 309 | s = realloc(s, na+1); | ||
| 310 | } | ||
| 311 | m = Bread(w->body, s+n, na-n); | ||
| 312 | if(m <= 0) | ||
| 313 | break; | ||
| 314 | n += m; | ||
| 315 | } | ||
| 316 | s[n] = 0; | ||
| 317 | winclosebody(w); | ||
| 318 | *np = n; | ||
| 319 | return s; | ||
| 320 | } | ||
| @@ -0,0 +1,584 @@ | |||
| 1 | #include <u.h> | ||
| 2 | #include <libc.h> | ||
| 3 | #include <bio.h> | ||
| 4 | #include <thread.h> | ||
| 5 | #include "win.h" | ||
| 6 | #include "adict.h" | ||
| 7 | |||
| 8 | char *prog = "adict"; | ||
| 9 | char *lprog = "/bin/adict"; | ||
| 10 | char *xprog = "/bin/dict"; | ||
| 11 | char *dict, *pattern, *curaddr[MAXMATCH], *curone, *args[6], buffer[80]; | ||
| 12 | char abuffer[80], fbuffer[80], pbuffer[80]; | ||
| 13 | int curindex, count, Eopen, Mopen; | ||
| 14 | Win Mwin, Ewin, Dwin; | ||
| 15 | |||
| 16 | void openwin(char*, char*, Win*, int); | ||
| 17 | void handle(Win*, int); | ||
| 18 | void rexec(void*); | ||
| 19 | void pexec(void*); | ||
| 20 | int getaddr(char*); | ||
| 21 | |||
| 22 | void | ||
| 23 | usage(void) | ||
| 24 | { | ||
| 25 | threadprint(2, "usage: %s [-d dictname] [pattern]\n", argv0); | ||
| 26 | threadexitsall(nil); | ||
| 27 | } | ||
| 28 | |||
| 29 | void | ||
| 30 | threadmain(int argc, char** argv) | ||
| 31 | { | ||
| 32 | ARGBEGIN{ | ||
| 33 | case 'd': | ||
| 34 | dict = strdup(ARGF()); | ||
| 35 | break; | ||
| 36 | default: | ||
| 37 | usage(); | ||
| 38 | }ARGEND | ||
| 39 | |||
| 40 | /* if running as other name, note that fact */ | ||
| 41 | if(access(argv0, AEXIST) == 0) | ||
| 42 | lprog = argv0; | ||
| 43 | |||
| 44 | switch(argc){ | ||
| 45 | case 1: | ||
| 46 | pattern = pbuffer; | ||
| 47 | strcpy(pattern,argv[0]); | ||
| 48 | if(dict == nil) | ||
| 49 | dict = "oed"; | ||
| 50 | break; | ||
| 51 | case 0: | ||
| 52 | break; | ||
| 53 | default: | ||
| 54 | usage(); | ||
| 55 | } | ||
| 56 | |||
| 57 | if ((dict == nil) && (pattern == nil)) | ||
| 58 | openwin(prog,"", &Dwin, Dictwin); | ||
| 59 | if (pattern == nil) | ||
| 60 | openwin(prog,"",&Ewin, Entrywin); | ||
| 61 | if ((count = getaddr(pattern)) <= 1) | ||
| 62 | openwin(prog,"Prev Next", &Ewin, Entrywin); | ||
| 63 | else | ||
| 64 | openwin(prog, "", &Mwin, Matchwin); | ||
| 65 | } | ||
| 66 | |||
| 67 | static int | ||
| 68 | procrexec(char *xprog, ...) | ||
| 69 | { | ||
| 70 | int fpipe[2]; | ||
| 71 | void *rexarg[4]; | ||
| 72 | Channel *c; | ||
| 73 | va_list va; | ||
| 74 | int i; | ||
| 75 | char *p; | ||
| 76 | |||
| 77 | pipe(fpipe); | ||
| 78 | va_start(va, xprog); | ||
| 79 | p = xprog; | ||
| 80 | for(i=0; p && i+1<nelem(args); i++){ | ||
| 81 | args[i] = p; | ||
| 82 | p = va_arg(va, char*); | ||
| 83 | } | ||
| 84 | args[i] = nil; | ||
| 85 | |||
| 86 | c = chancreate(sizeof(ulong), 0); | ||
| 87 | rexarg[0] = xprog; | ||
| 88 | rexarg[1] = args; | ||
| 89 | rexarg[2] = fpipe; | ||
| 90 | rexarg[3] = c; | ||
| 91 | |||
| 92 | proccreate(rexec, rexarg, 8192); | ||
| 93 | recvul(c); | ||
| 94 | chanfree(c); | ||
| 95 | close(fpipe[1]); | ||
| 96 | return fpipe[0]; | ||
| 97 | } | ||
| 98 | |||
| 99 | int | ||
| 100 | getaddr(char *pattern) | ||
| 101 | { | ||
| 102 | /* Get char offset into dictionary of matches. */ | ||
| 103 | |||
| 104 | int fd, i; | ||
| 105 | Biobuf inbuf; | ||
| 106 | char *bufptr; | ||
| 107 | char *obuf; | ||
| 108 | |||
| 109 | if (pattern == nil) { | ||
| 110 | curone = nil; | ||
| 111 | curindex = 0; | ||
| 112 | curaddr[curindex] = nil; | ||
| 113 | return 0; | ||
| 114 | } | ||
| 115 | |||
| 116 | sprint(buffer,"/%s/A", pattern); | ||
| 117 | fd = procrexec(xprog, "-d", dict, "-c", buffer, nil); | ||
| 118 | Binit(&inbuf, fd, OREAD); | ||
| 119 | i = 0; | ||
| 120 | curindex = 0; | ||
| 121 | while ((bufptr = Brdline(&inbuf, '\n')) != nil && (i < (MAXMATCH-1))) { | ||
| 122 | bufptr[Blinelen(&inbuf)-1] = 0; | ||
| 123 | obuf=bufptr; | ||
| 124 | while (bufptr[0] != '#' && bufptr[0] != 0) bufptr++; | ||
| 125 | if(bufptr[0] == 0) | ||
| 126 | print("whoops buf «%s»\n", obuf); | ||
| 127 | curaddr[i] = malloc(strlen(bufptr)); | ||
| 128 | strcpy(curaddr[i], bufptr); | ||
| 129 | i++; | ||
| 130 | } | ||
| 131 | curaddr[i] = nil; | ||
| 132 | if (i == MAXMATCH) | ||
| 133 | threadprint(2, "Too many matches!\n"); | ||
| 134 | Bterm(&inbuf); | ||
| 135 | close(fd); | ||
| 136 | |||
| 137 | curone = curaddr[curindex]; | ||
| 138 | return(i); | ||
| 139 | } | ||
| 140 | |||
| 141 | char* | ||
| 142 | getpattern(char *addr) | ||
| 143 | { | ||
| 144 | /* Get the pattern corresponding to an absolute address.*/ | ||
| 145 | int fd; | ||
| 146 | char *res, *t; | ||
| 147 | |||
| 148 | res = nil; | ||
| 149 | sprint(buffer,"%sh", addr); | ||
| 150 | fd = procrexec(xprog, "-d", dict, "-c", buffer, nil); | ||
| 151 | if (read(fd, pbuffer, 80) > 80) | ||
| 152 | threadprint(2, "Error in getting addres from dict.\n"); | ||
| 153 | else { | ||
| 154 | t = pbuffer; | ||
| 155 | /* remove trailing whitespace, newline */ | ||
| 156 | if (t != nil){ | ||
| 157 | while(*t != 0 && *t != '\n') | ||
| 158 | t++; | ||
| 159 | if(t == 0 && t > pbuffer) | ||
| 160 | t--; | ||
| 161 | while(t >= pbuffer && (*t==' ' || *t=='\n' || *t=='\t' || *t=='\r')) | ||
| 162 | *t-- = 0; | ||
| 163 | } | ||
| 164 | res = pbuffer; | ||
| 165 | } | ||
| 166 | close(fd); | ||
| 167 | return(res); | ||
| 168 | } | ||
| 169 | |||
| 170 | char* | ||
| 171 | chgaddr(int dir) | ||
| 172 | { | ||
| 173 | /* Increment or decrement the current address (curone). */ | ||
| 174 | |||
| 175 | int fd; | ||
| 176 | char *res, *t; | ||
| 177 | |||
| 178 | res = nil; | ||
| 179 | if (dir < 0) | ||
| 180 | sprint(buffer,"%s-a", curone); | ||
| 181 | else | ||
| 182 | sprint(buffer,"%s+a", curone); | ||
| 183 | fd = procrexec(xprog, "-d", dict, "-c", buffer, nil); | ||
| 184 | if (read(fd, abuffer, 80) > 80) | ||
| 185 | threadprint(2, "Error in getting addres from dict.\n"); | ||
| 186 | else { | ||
| 187 | res = abuffer; | ||
| 188 | while (*res != '#') res++; | ||
| 189 | t = res; | ||
| 190 | while ((*t != '\n') && (t != nil)) t++; | ||
| 191 | if (t != nil) *t = 0; | ||
| 192 | } | ||
| 193 | close(fd); | ||
| 194 | return(res); | ||
| 195 | } | ||
| 196 | |||
| 197 | void | ||
| 198 | dispdicts(Win *cwin) | ||
| 199 | { | ||
| 200 | /* Display available dictionaries in window. */ | ||
| 201 | |||
| 202 | int fd, nb, i; | ||
| 203 | char buf[1024], *t; | ||
| 204 | |||
| 205 | fd = procrexec(xprog, "-d", "?", nil); | ||
| 206 | wreplace(cwin, "0,$","",0); /* Clear window */ | ||
| 207 | while ((nb = read(fd, buf, 1024)) > 0) { | ||
| 208 | t = buf; | ||
| 209 | i = 0; | ||
| 210 | if (strncmp("Usage", buf, 5) == 0) { /* Remove first line. */ | ||
| 211 | while (t[0] != '\n') { | ||
| 212 | t++; | ||
| 213 | i++; | ||
| 214 | } | ||
| 215 | t++; | ||
| 216 | i++; | ||
| 217 | } | ||
| 218 | wwritebody(cwin, t, nb-i); | ||
| 219 | } | ||
| 220 | close(fd); | ||
| 221 | wclean(cwin); | ||
| 222 | } | ||
| 223 | |||
| 224 | void | ||
| 225 | dispentry(Win *cwin) | ||
| 226 | { | ||
| 227 | /* Display the current selection in window. */ | ||
| 228 | |||
| 229 | int fd, nb; | ||
| 230 | char buf[BUFSIZE]; | ||
| 231 | |||
| 232 | if (curone == nil) { | ||
| 233 | if (pattern != nil) { | ||
| 234 | sprint(buf,"Pattern not found.\n"); | ||
| 235 | wwritebody(cwin, buf, 19); | ||
| 236 | wclean(cwin); | ||
| 237 | } | ||
| 238 | return; | ||
| 239 | } | ||
| 240 | sprint(buffer,"%sp", curone); | ||
| 241 | fd = procrexec(xprog, "-d", dict, "-c", buffer, nil); | ||
| 242 | wreplace(cwin, "0,$","",0); /* Clear window */ | ||
| 243 | while ((nb = read(fd, buf, BUFSIZE)) > 0) { | ||
| 244 | wwritebody(cwin, buf, nb); | ||
| 245 | } | ||
| 246 | close(fd); | ||
| 247 | wclean(cwin); | ||
| 248 | } | ||
| 249 | |||
| 250 | void | ||
| 251 | dispmatches(Win *cwin) | ||
| 252 | { | ||
| 253 | /* Display the current matches. */ | ||
| 254 | |||
| 255 | int fd, nb; | ||
| 256 | char buf[BUFSIZE]; | ||
| 257 | |||
| 258 | sprint(buffer,"/%s/H", pattern); | ||
| 259 | fd = procrexec(xprog, "-d", dict, "-c", buffer, nil); | ||
| 260 | while ((nb = read(fd, buf, BUFSIZE)) > 0) | ||
| 261 | wwritebody(cwin, buf, nb); | ||
| 262 | close(fd); | ||
| 263 | wclean(cwin); | ||
| 264 | } | ||
| 265 | |||
| 266 | char* | ||
| 267 | format(char *s) | ||
| 268 | { | ||
| 269 | /* Format a string to be written in window tag. Acme doesn't like */ | ||
| 270 | /* non alpha-num's in the tag line. */ | ||
| 271 | |||
| 272 | char *t, *h; | ||
| 273 | |||
| 274 | t = fbuffer; | ||
| 275 | if (s == nil) { | ||
| 276 | *t = 0; | ||
| 277 | return t; | ||
| 278 | } | ||
| 279 | strcpy(t, s); | ||
| 280 | h = t; | ||
| 281 | while (*t != 0) { | ||
| 282 | if (!(((*t >= 'a') && (*t <= 'z')) || | ||
| 283 | ((*t >= 'A') && (*t <= 'Z')) || | ||
| 284 | ((*t >= '0') && (*t <= '9')))) | ||
| 285 | *t = '_'; | ||
| 286 | t++; | ||
| 287 | } | ||
| 288 | if (strlen(h) > MAXTAG) | ||
| 289 | h[MAXTAG] = 0; | ||
| 290 | if (strcmp(s,h) == 0) return s; | ||
| 291 | return h; | ||
| 292 | } | ||
| 293 | |||
| 294 | void | ||
| 295 | openwin(char *name, char *buttons, Win *twin, int wintype) | ||
| 296 | { | ||
| 297 | char buf[80]; | ||
| 298 | |||
| 299 | wnew(twin); | ||
| 300 | if (wintype == Dictwin) | ||
| 301 | sprint(buf,"%s",name); | ||
| 302 | else | ||
| 303 | if ((wintype == Entrywin) && (count > 1)) | ||
| 304 | sprint(buf,"%s/%s/%s/%d",name, dict, format(pattern), curindex+1); | ||
| 305 | else | ||
| 306 | sprint(buf,"%s/%s/%s",name, dict, format(pattern)); | ||
| 307 | wname(twin, buf); | ||
| 308 | wtagwrite(twin, buttons, strlen(buttons)); | ||
| 309 | wclean(twin); | ||
| 310 | wdormant(twin); | ||
| 311 | if (wintype == Dictwin) | ||
| 312 | dispdicts(twin); | ||
| 313 | if (wintype == Matchwin) { | ||
| 314 | Mopen = True; | ||
| 315 | dispmatches(twin); | ||
| 316 | } | ||
| 317 | if (wintype == Entrywin) { | ||
| 318 | Eopen = True; | ||
| 319 | dispentry(twin); | ||
| 320 | } | ||
| 321 | handle(twin, wintype); | ||
| 322 | } | ||
| 323 | |||
| 324 | void | ||
| 325 | vopenwin(void *v) | ||
| 326 | { | ||
| 327 | void **arg; | ||
| 328 | char *name, *buttons; | ||
| 329 | Win *twin; | ||
| 330 | int wintype; | ||
| 331 | |||
| 332 | arg = v; | ||
| 333 | name = arg[0]; | ||
| 334 | buttons = arg[1]; | ||
| 335 | twin = arg[2]; | ||
| 336 | wintype = (int)arg[3]; | ||
| 337 | sendul(arg[4], 0); | ||
| 338 | |||
| 339 | openwin(name, buttons, twin, wintype); | ||
| 340 | threadexits(nil); | ||
| 341 | } | ||
| 342 | |||
| 343 | void | ||
| 344 | procopenwin(char *name, char *buttons, Win *twin, int wintype) | ||
| 345 | { | ||
| 346 | void *arg[5]; | ||
| 347 | Channel *c; | ||
| 348 | |||
| 349 | c = chancreate(sizeof(ulong), 0); | ||
| 350 | arg[0] = name; | ||
| 351 | arg[1] = buttons; | ||
| 352 | arg[2] = twin; | ||
| 353 | arg[3] = (void*)wintype; | ||
| 354 | arg[4] = c; | ||
| 355 | proccreate(vopenwin, arg, 8192); | ||
| 356 | recvul(c); | ||
| 357 | chanfree(c); | ||
| 358 | } | ||
| 359 | |||
| 360 | void | ||
| 361 | rexec(void *v) | ||
| 362 | { | ||
| 363 | void **arg; | ||
| 364 | char *prog; | ||
| 365 | char **args; | ||
| 366 | int *fd; | ||
| 367 | Channel *c; | ||
| 368 | |||
| 369 | arg = v; | ||
| 370 | prog = arg[0]; | ||
| 371 | args = arg[1]; | ||
| 372 | fd = arg[2]; | ||
| 373 | c = arg[3]; | ||
| 374 | |||
| 375 | rfork(RFENVG|RFFDG); | ||
| 376 | dup(fd[1], 1); | ||
| 377 | close(fd[1]); | ||
| 378 | close(fd[0]); | ||
| 379 | procexec(c, prog, args); | ||
| 380 | threadprint(2, "Remote pipe execution failed: %s %r\n", prog); | ||
| 381 | abort(); | ||
| 382 | threadexits(nil); | ||
| 383 | } | ||
| 384 | |||
| 385 | void | ||
| 386 | pexec(void *v) | ||
| 387 | { | ||
| 388 | void **arg; | ||
| 389 | char *prog; | ||
| 390 | char **args; | ||
| 391 | Channel *c; | ||
| 392 | |||
| 393 | arg = v; | ||
| 394 | prog = arg[0]; | ||
| 395 | args = arg[1]; | ||
| 396 | c = arg[2]; | ||
| 397 | |||
| 398 | procexec(c, prog, args); | ||
| 399 | threadprint(2, "Remote execution failed: %s %r\n", prog); | ||
| 400 | abort(); | ||
| 401 | threadexits(nil); | ||
| 402 | } | ||
| 403 | |||
| 404 | void | ||
| 405 | procpexec(char *prog, char **args) | ||
| 406 | { | ||
| 407 | void *rexarg[4]; | ||
| 408 | Channel *c; | ||
| 409 | |||
| 410 | c = chancreate(sizeof(ulong), 0); | ||
| 411 | rexarg[0] = prog; | ||
| 412 | rexarg[1] = args; | ||
| 413 | rexarg[2] = c; | ||
| 414 | |||
| 415 | proccreate(pexec, rexarg, 8192); | ||
| 416 | recvul(c); | ||
| 417 | chanfree(c); | ||
| 418 | } | ||
| 419 | |||
| 420 | void | ||
| 421 | kill(void) | ||
| 422 | { | ||
| 423 | /* Kill all processes related to this one. */ | ||
| 424 | int fd; | ||
| 425 | |||
| 426 | sprint(buffer, "/proc/%d/notepg", getpid()); | ||
| 427 | fd = open(buffer, OWRITE); | ||
| 428 | rfork(RFNOTEG); | ||
| 429 | write(fd, "kill", 4); | ||
| 430 | } | ||
| 431 | |||
| 432 | int | ||
| 433 | command(char *com, Win *w, int wintype) | ||
| 434 | { | ||
| 435 | char *buf; | ||
| 436 | |||
| 437 | if (strncmp(com, "Del", 3) == 0) { | ||
| 438 | switch(wintype){ | ||
| 439 | case Entrywin: | ||
| 440 | if (wdel(w)) { | ||
| 441 | Eopen = False; | ||
| 442 | threadexits(nil); | ||
| 443 | } | ||
| 444 | break; | ||
| 445 | case Dictwin: | ||
| 446 | if (wdel(w)) | ||
| 447 | threadexits(nil); | ||
| 448 | break; | ||
| 449 | case Matchwin: | ||
| 450 | kill(); | ||
| 451 | if (Eopen) | ||
| 452 | if (~wdel(&Ewin)) /* Remove the entry window */ | ||
| 453 | wdel(&Ewin); | ||
| 454 | if (!wdel(w)) | ||
| 455 | wdel(w); | ||
| 456 | threadexits(nil); | ||
| 457 | break; | ||
| 458 | } | ||
| 459 | return True; | ||
| 460 | } | ||
| 461 | if (strncmp(com, "Next", 4) == 0){ | ||
| 462 | if (curone != nil) { | ||
| 463 | curone = chgaddr(1); | ||
| 464 | buf = getpattern(curone); | ||
| 465 | sprint(buffer,"%s/%s/%s", prog, dict, format(buf)); | ||
| 466 | wname(w, buffer); | ||
| 467 | dispentry(w); | ||
| 468 | } | ||
| 469 | return True; | ||
| 470 | } | ||
| 471 | if (strncmp(com, "Prev",4) == 0){ | ||
| 472 | if (curone != nil) { | ||
| 473 | curone = chgaddr(-1); | ||
| 474 | buf = getpattern(curone); | ||
| 475 | sprint(buffer,"%s/%s/%s", prog, dict, format(buf)); | ||
| 476 | wname(w, buffer); | ||
| 477 | dispentry(w); | ||
| 478 | } | ||
| 479 | return True; | ||
| 480 | } | ||
| 481 | if (strncmp(com, "Nmatch",6) == 0){ | ||
| 482 | if (curaddr[++curindex] == nil) | ||
| 483 | curindex = 0; | ||
| 484 | curone = curaddr[curindex]; | ||
| 485 | if (curone != nil) { | ||
| 486 | sprint(buffer,"%s/%s/%s/%d",prog,dict,format(pattern),curindex+1); | ||
| 487 | wname(w, buffer); | ||
| 488 | dispentry(w); | ||
| 489 | } | ||
| 490 | return True; | ||
| 491 | } | ||
| 492 | return False; | ||
| 493 | } | ||
| 494 | |||
| 495 | void | ||
| 496 | handle(Win *w, int wintype) | ||
| 497 | { | ||
| 498 | Event e, e2, ea, etoss; | ||
| 499 | char *s, *t, buf[80]; | ||
| 500 | int tmp, na; | ||
| 501 | |||
| 502 | while (True) { | ||
| 503 | wevent(w, &e); | ||
| 504 | switch(e.c2){ | ||
| 505 | default: | ||
| 506 | /* threadprint(2,"unknown message %c%c\n", e.c1, e.c2); */ | ||
| 507 | break; | ||
| 508 | case 'i': | ||
| 509 | /* threadprint(2,"'%s' inserted in tag at %d\n", e.b, e.q0);*/ | ||
| 510 | break; | ||
| 511 | case 'I': | ||
| 512 | /* threadprint(2,"'%s' inserted in body at %d\n", e.b, e.q0);*/ | ||
| 513 | break; | ||
| 514 | case 'd': | ||
| 515 | /* threadprint(2, "'%s' deleted in tag at %d\n", e.b, e.q0);*/ | ||
| 516 | break; | ||
| 517 | case 'D': | ||
| 518 | /* threadprint(2, "'%s' deleted in body at %d\n", e.b, e.q0);*/ | ||
| 519 | break; | ||
| 520 | case 'x': | ||
| 521 | case 'X': /* Execute command. */ | ||
| 522 | if (e.flag & 2) | ||
| 523 | wevent(w, &e2); | ||
| 524 | if(e.flag & 8){ | ||
| 525 | wevent(w, &ea); | ||
| 526 | wevent(w, &etoss); | ||
| 527 | na = ea.nb; | ||
| 528 | } else | ||
| 529 | na = 0; | ||
| 530 | s = e.b; | ||
| 531 | if ((e.flag & 2) && e.nb == 0) | ||
| 532 | s = e2.b; | ||
| 533 | if(na){ | ||
| 534 | t = malloc(strlen(s)+1+na+1); | ||
| 535 | snprint(t, strlen(s)+1+na+1, "%s %s", s, ea.b); | ||
| 536 | s = t; | ||
| 537 | } | ||
| 538 | /* if it's a long message, it can't be for us anyway */ | ||
| 539 | if(!command(s, w, wintype)) /* send it back */ | ||
| 540 | wwriteevent(w, &e); | ||
| 541 | if(na) | ||
| 542 | free(s); | ||
| 543 | break; | ||
| 544 | case 'l': | ||
| 545 | case 'L': /* Look for something. */ | ||
| 546 | if (e.flag & 2) | ||
| 547 | wevent(w, &e); | ||
| 548 | wclean(w); /* Set clean bit. */ | ||
| 549 | if (wintype == Dictwin) { | ||
| 550 | strcpy(buf, e.b); | ||
| 551 | args[0] = lprog; | ||
| 552 | args[1] = "-d"; | ||
| 553 | args[2] = buf; | ||
| 554 | args[3] = nil; | ||
| 555 | procpexec(lprog, args); /* New adict with chosen dict. */ | ||
| 556 | } | ||
| 557 | if (wintype == Entrywin) { | ||
| 558 | strcpy(buf, e.b); | ||
| 559 | args[0] = lprog; | ||
| 560 | args[1] = "-d"; | ||
| 561 | args[2] = dict; | ||
| 562 | args[3] = buf; | ||
| 563 | args[4] = nil; | ||
| 564 | procpexec(lprog, args); /* New adict with chosen pattern. */ | ||
| 565 | } | ||
| 566 | if (wintype == Matchwin) { | ||
| 567 | tmp = atoi(e.b) - 1; | ||
| 568 | if ((tmp >= 0) && (tmp < MAXMATCH) && (curaddr[tmp] != nil)) { | ||
| 569 | curindex = tmp; | ||
| 570 | curone = curaddr[curindex]; | ||
| 571 | /* Display selected match. */ | ||
| 572 | if (Eopen) { | ||
| 573 | sprint(buf,"%s/%s/%s/%d",prog,dict,format(pattern),curindex+1); | ||
| 574 | wname(&Ewin, buf); | ||
| 575 | dispentry(&Ewin); | ||
| 576 | } | ||
| 577 | else | ||
| 578 | procopenwin(prog,"Nmatch Prev Next", &Ewin, Entrywin); | ||
| 579 | } | ||
| 580 | } | ||
| 581 | break; | ||
| 582 | } | ||
| 583 | } | ||
| 584 | } | ||
| @@ -0,0 +1,315 @@ | |||
| 1 | #include <u.h> | ||
| 2 | #include <libc.h> | ||
| 3 | #include <bio.h> | ||
| 4 | #include <thread.h> | ||
| 5 | #include "win.h" | ||
| 6 | |||
| 7 | void* | ||
| 8 | erealloc(void *p, uint n) | ||
| 9 | { | ||
| 10 | p = realloc(p, n); | ||
| 11 | if(p == nil) | ||
| 12 | threadprint(2, "realloc failed: %r"); | ||
| 13 | return p; | ||
| 14 | } | ||
| 15 | |||
| 16 | void | ||
| 17 | wnew(Win *w) | ||
| 18 | { | ||
| 19 | char buf[12]; | ||
| 20 | |||
| 21 | w->ctl = open("/mnt/acme/new/ctl", ORDWR); | ||
| 22 | if(w->ctl<0 || read(w->ctl, buf, 12)!=12) | ||
| 23 | threadprint (2, "can't open window ctl file: %r"); | ||
| 24 | ctlwrite(w, "noscroll\n"); | ||
| 25 | w->winid = atoi(buf); | ||
| 26 | w->event = openfile(w, "event"); | ||
| 27 | w->addr = -1; /* will be opened when needed */ | ||
| 28 | w->body = nil; | ||
| 29 | w->data = -1; | ||
| 30 | } | ||
| 31 | |||
| 32 | int | ||
| 33 | openfile(Win *w, char *f) | ||
| 34 | { | ||
| 35 | char buf[64]; | ||
| 36 | int fd; | ||
| 37 | |||
| 38 | sprint(buf, "/mnt/acme/%d/%s", w->winid, f); | ||
| 39 | fd = open(buf, ORDWR|OCEXEC); | ||
| 40 | if(fd < 0) | ||
| 41 | threadprint (2,"can't open window %s file: %r", f); | ||
| 42 | return fd; | ||
| 43 | } | ||
| 44 | |||
| 45 | void | ||
| 46 | openbody(Win *w, int mode) | ||
| 47 | { | ||
| 48 | char buf[64]; | ||
| 49 | |||
| 50 | sprint(buf, "/mnt/acme/%d/body", w->winid); | ||
| 51 | w->body = Bopen(buf, mode|OCEXEC); | ||
| 52 | if(w->body == nil) | ||
| 53 | threadprint(2,"can't open window body file: %r"); | ||
| 54 | } | ||
| 55 | |||
| 56 | void | ||
| 57 | wwritebody(Win *w, char *s, int n) | ||
| 58 | { | ||
| 59 | if(w->body == nil) | ||
| 60 | openbody(w, OWRITE); | ||
| 61 | if(Bwrite(w->body, s, n) != n) | ||
| 62 | threadprint(2,"write error to window: %r"); | ||
| 63 | Bflush(w->body); | ||
| 64 | } | ||
| 65 | |||
| 66 | void | ||
| 67 | wreplace(Win *w, char *addr, char *repl, int nrepl) | ||
| 68 | { | ||
| 69 | if(w->addr < 0) | ||
| 70 | w->addr = openfile(w, "addr"); | ||
| 71 | if(w->data < 0) | ||
| 72 | w->data = openfile(w, "data"); | ||
| 73 | if(write(w->addr, addr, strlen(addr)) < 0){ | ||
| 74 | threadprint(2, "mail: warning: badd address %s:%r\n", addr); | ||
| 75 | return; | ||
| 76 | } | ||
| 77 | if(write(w->data, repl, nrepl) != nrepl) | ||
| 78 | threadprint(2, "writing data: %r"); | ||
| 79 | } | ||
| 80 | |||
| 81 | static int | ||
| 82 | nrunes(char *s, int nb) | ||
| 83 | { | ||
| 84 | int i, n; | ||
| 85 | Rune r; | ||
| 86 | |||
| 87 | n = 0; | ||
| 88 | for(i=0; i<nb; n++) | ||
| 89 | i += chartorune(&r, s+i); | ||
| 90 | return n; | ||
| 91 | } | ||
| 92 | |||
| 93 | void | ||
| 94 | wread(Win *w, uint q0, uint q1, char *data) | ||
| 95 | { | ||
| 96 | int m, n, nr; | ||
| 97 | char buf[256]; | ||
| 98 | |||
| 99 | if(w->addr < 0) | ||
| 100 | w->addr = openfile(w, "addr"); | ||
| 101 | if(w->data < 0) | ||
| 102 | w->data = openfile(w, "data"); | ||
| 103 | m = q0; | ||
| 104 | while(m < q1){ | ||
| 105 | n = sprint(buf, "#%d", m); | ||
| 106 | if(write(w->addr, buf, n) != n) | ||
| 107 | threadprint(2,"writing addr: %r"); | ||
| 108 | n = read(w->data, buf, sizeof buf); | ||
| 109 | if(n <= 0) | ||
| 110 | threadprint(2,"reading data: %r"); | ||
| 111 | nr = nrunes(buf, n); | ||
| 112 | while(m+nr >q1){ | ||
| 113 | do; while(n>0 && (buf[--n]&0xC0)==0x80); | ||
| 114 | --nr; | ||
| 115 | } | ||
| 116 | if(n == 0) | ||
| 117 | break; | ||
| 118 | memmove(data, buf, n); | ||
| 119 | data += n; | ||
| 120 | *data = 0; | ||
| 121 | m += nr; | ||
| 122 | } | ||
| 123 | } | ||
| 124 | |||
| 125 | void | ||
| 126 | wselect(Win *w, char *addr) | ||
| 127 | { | ||
| 128 | if(w->addr < 0) | ||
| 129 | w->addr = openfile(w, "addr"); | ||
| 130 | if(write(w->addr, addr, strlen(addr)) < 0) | ||
| 131 | threadprint(2,"writing addr"); | ||
| 132 | ctlwrite(w, "dot=addr\n"); | ||
| 133 | } | ||
| 134 | |||
| 135 | void | ||
| 136 | wtagwrite(Win *w, char *s, int n) | ||
| 137 | { | ||
| 138 | int fd; | ||
| 139 | |||
| 140 | fd = openfile(w, "tag"); | ||
| 141 | if(write(fd, s, n) != n) | ||
| 142 | threadprint(2,"tag write: %r"); | ||
| 143 | close(fd); | ||
| 144 | } | ||
| 145 | |||
| 146 | void | ||
| 147 | ctlwrite(Win *w, char *s) | ||
| 148 | { | ||
| 149 | int n; | ||
| 150 | |||
| 151 | n = strlen(s); | ||
| 152 | if(write(w->ctl, s, n) != n) | ||
| 153 | threadprint(2,"write error to ctl file: %r"); | ||
| 154 | } | ||
| 155 | |||
| 156 | int | ||
| 157 | wdel(Win *w) | ||
| 158 | { | ||
| 159 | if(write(w->ctl, "del\n", 4) != 4) | ||
| 160 | return False; | ||
| 161 | wdormant(w); | ||
| 162 | close(w->ctl); | ||
| 163 | w->ctl = -1; | ||
| 164 | close(w->event); | ||
| 165 | w->event = -1; | ||
| 166 | return True; | ||
| 167 | } | ||
| 168 | |||
| 169 | void | ||
| 170 | wname(Win *w, char *s) | ||
| 171 | { | ||
| 172 | char buf[128]; | ||
| 173 | |||
| 174 | sprint(buf, "name %s\n", s); | ||
| 175 | ctlwrite(w, buf); | ||
| 176 | } | ||
| 177 | |||
| 178 | void | ||
| 179 | wclean(Win *w) | ||
| 180 | { | ||
| 181 | if(w->body) | ||
| 182 | Bflush(w->body); | ||
| 183 | ctlwrite(w, "clean\n"); | ||
| 184 | } | ||
| 185 | |||
| 186 | void | ||
| 187 | wdormant(Win *w) | ||
| 188 | { | ||
| 189 | if(w->addr >= 0){ | ||
| 190 | close(w->addr); | ||
| 191 | w->addr = -1; | ||
| 192 | } | ||
| 193 | if(w->body != nil){ | ||
| 194 | Bterm(w->body); | ||
| 195 | w->body = nil; | ||
| 196 | } | ||
| 197 | if(w->data >= 0){ | ||
| 198 | close(w->data); | ||
| 199 | w->data = -1; | ||
| 200 | } | ||
| 201 | } | ||
| 202 | |||
| 203 | int | ||
| 204 | getec(Win *w) | ||
| 205 | { | ||
| 206 | if(w->nbuf == 0){ | ||
| 207 | w->nbuf = read(w->event, w->buf, sizeof w->buf); | ||
| 208 | if(w->nbuf <= 0) | ||
| 209 | threadprint(2,"event read error: %r"); | ||
| 210 | w->bufp = w->buf; | ||
| 211 | } | ||
| 212 | w->nbuf--; | ||
| 213 | return *w->bufp++; | ||
| 214 | } | ||
| 215 | |||
| 216 | int | ||
| 217 | geten(Win *w) | ||
| 218 | { | ||
| 219 | int n, c; | ||
| 220 | |||
| 221 | n = 0; | ||
| 222 | while('0'<=(c=getec(w)) && c<='9') | ||
| 223 | n = n*10+(c-'0'); | ||
| 224 | if(c != ' ') | ||
| 225 | threadprint(2, "event number syntax"); | ||
| 226 | return n; | ||
| 227 | } | ||
| 228 | |||
| 229 | int | ||
| 230 | geter(Win *w, char *buf, int *nb) | ||
| 231 | { | ||
| 232 | Rune r; | ||
| 233 | int n; | ||
| 234 | |||
| 235 | r = getec(w); | ||
| 236 | buf[0] = r; | ||
| 237 | n = 1; | ||
| 238 | if(r < Runeself) | ||
| 239 | goto Return; | ||
| 240 | while(!fullrune(buf, n)) | ||
| 241 | buf[n++] = getec(w); | ||
| 242 | chartorune(&r, buf); | ||
| 243 | Return: | ||
| 244 | *nb = n; | ||
| 245 | return r; | ||
| 246 | } | ||
| 247 | |||
| 248 | |||
| 249 | void | ||
| 250 | wevent(Win *w, Event *e) | ||
| 251 | { | ||
| 252 | int i, nb; | ||
| 253 | |||
| 254 | e->c1 = getec(w); | ||
| 255 | e->c2 = getec(w); | ||
| 256 | e->q0 = geten(w); | ||
| 257 | e->q1 = geten(w); | ||
| 258 | e->flag = geten(w); | ||
| 259 | e->nr = geten(w); | ||
| 260 | if(e->nr > EVENTSIZE) | ||
| 261 | threadprint(2, "wevent: event string too long"); | ||
| 262 | e->nb = 0; | ||
| 263 | for(i=0; i<e->nr; i++){ | ||
| 264 | e->r[i] = geter(w, e->b+e->nb, &nb); | ||
| 265 | e->nb += nb; | ||
| 266 | } | ||
| 267 | e->r[e->nr] = 0; | ||
| 268 | e->b[e->nb] = 0; | ||
| 269 | if(getec(w) != '\n') | ||
| 270 | threadprint(2, "wevent: event syntax 2"); | ||
| 271 | } | ||
| 272 | |||
| 273 | void | ||
| 274 | wslave(Win *w, Channel *ce) | ||
| 275 | { | ||
| 276 | Event e; | ||
| 277 | |||
| 278 | while(recv(ce, &e) >= 0) | ||
| 279 | wevent(w, &e); | ||
| 280 | } | ||
| 281 | |||
| 282 | void | ||
| 283 | wwriteevent(Win *w, Event *e) | ||
| 284 | { | ||
| 285 | threadprint(w->event, "%c%c%d %d\n", e->c1, e->c2, e->q0, e->q1); | ||
| 286 | } | ||
| 287 | |||
| 288 | int | ||
| 289 | wreadall(Win *w, char **sp) | ||
| 290 | { | ||
| 291 | char *s; | ||
| 292 | int m, na, n; | ||
| 293 | |||
| 294 | if(w->body != nil) | ||
| 295 | Bterm(w->body); | ||
| 296 | openbody(w, OREAD); | ||
| 297 | s = nil; | ||
| 298 | na = 0; | ||
| 299 | n = 0; | ||
| 300 | for(;;){ | ||
| 301 | if(na < n+512){ | ||
| 302 | na += 1024; | ||
| 303 | s = erealloc(s, na+1); | ||
| 304 | } | ||
| 305 | m = Bread(w->body, s+n, na-n); | ||
| 306 | if(m <= 0) | ||
| 307 | break; | ||
| 308 | n += m; | ||
| 309 | } | ||
| 310 | s[n] = 0; | ||
| 311 | Bterm(w->body); | ||
| 312 | w->body = nil; | ||
| 313 | *sp = s; | ||
| 314 | return n; | ||
| 315 | } | ||
| @@ -0,0 +1,591 @@ | |||
| 1 | #include <u.h> | ||
| 2 | #include <libc.h> | ||
| 3 | #include <bio.h> | ||
| 4 | #include <thread.h> | ||
| 5 | #include "win.h" | ||
| 6 | #include "adict.h" | ||
| 7 | |||
| 8 | enum | ||
| 9 | { | ||
| 10 | STACK = 8192, | ||
| 11 | }; | ||
| 12 | |||
| 13 | char *prog = "adict"; | ||
| 14 | char *lprog = "/bin/adict"; | ||
| 15 | char *xprog = "/bin/dict"; | ||
| 16 | char *dict, *pattern, *curaddr[MAXMATCH], *curone, *args[6], buffer[80]; | ||
| 17 | char abuffer[80], fbuffer[80], pbuffer[80]; | ||
| 18 | int curindex, count, Eopen, Mopen; | ||
| 19 | Win Mwin, Ewin, Dwin; | ||
| 20 | |||
| 21 | void openwin(char*, char*, Win*, int); | ||
| 22 | void handle(Win*, int); | ||
| 23 | void rexec(void*); | ||
| 24 | void pexec(void*); | ||
| 25 | int getaddr(char*); | ||
| 26 | |||
| 27 | void | ||
| 28 | usage(void) | ||
| 29 | { | ||
| 30 | fprint(2, "usage: %s [-d dictname] [pattern]\n", argv0); | ||
| 31 | threadexitsall(nil); | ||
| 32 | } | ||
| 33 | |||
| 34 | int mainstacksize = STACK; | ||
| 35 | |||
| 36 | void | ||
| 37 | threadmain(int argc, char** argv) | ||
| 38 | { | ||
| 39 | ARGBEGIN{ | ||
| 40 | case 'd': | ||
| 41 | dict = strdup(ARGF()); | ||
| 42 | break; | ||
| 43 | default: | ||
| 44 | usage(); | ||
| 45 | }ARGEND | ||
| 46 | |||
| 47 | /* if running as other name, note that fact */ | ||
| 48 | if(access(argv0, AEXIST) == 0) | ||
| 49 | lprog = argv0; | ||
| 50 | |||
| 51 | switch(argc){ | ||
| 52 | case 1: | ||
| 53 | pattern = pbuffer; | ||
| 54 | strcpy(pattern,argv[0]); | ||
| 55 | if(dict == nil) | ||
| 56 | dict = "pgw"; | ||
| 57 | break; | ||
| 58 | case 0: | ||
| 59 | break; | ||
| 60 | default: | ||
| 61 | usage(); | ||
| 62 | } | ||
| 63 | |||
| 64 | if ((dict == nil) && (pattern == nil)) | ||
| 65 | openwin(prog,"", &Dwin, Dictwin); | ||
| 66 | if (pattern == nil) | ||
| 67 | openwin(prog,"",&Ewin, Entrywin); | ||
| 68 | if ((count = getaddr(pattern)) <= 1) | ||
| 69 | openwin(prog,"Prev Next", &Ewin, Entrywin); | ||
| 70 | else | ||
| 71 | openwin(prog, "", &Mwin, Matchwin); | ||
| 72 | } | ||
| 73 | |||
| 74 | static int | ||
| 75 | procrexec(char *xprog, ...) | ||
| 76 | { | ||
| 77 | int fpipe[2]; | ||
| 78 | void *rexarg[4]; | ||
| 79 | Channel *c; | ||
| 80 | va_list va; | ||
| 81 | int i; | ||
| 82 | char *p; | ||
| 83 | |||
| 84 | pipe(fpipe); | ||
| 85 | va_start(va, xprog); | ||
| 86 | p = xprog; | ||
| 87 | for(i=0; p && i+1<nelem(args); i++){ | ||
| 88 | args[i] = p; | ||
| 89 | p = va_arg(va, char*); | ||
| 90 | } | ||
| 91 | args[i] = nil; | ||
| 92 | |||
| 93 | c = chancreate(sizeof(ulong), 0); | ||
| 94 | rexarg[0] = xprog; | ||
| 95 | rexarg[1] = args; | ||
| 96 | rexarg[2] = fpipe; | ||
| 97 | rexarg[3] = c; | ||
| 98 | |||
| 99 | proccreate(rexec, rexarg, STACK); | ||
| 100 | recvul(c); | ||
| 101 | chanfree(c); | ||
| 102 | close(fpipe[1]); | ||
| 103 | return fpipe[0]; | ||
| 104 | } | ||
| 105 | |||
| 106 | int | ||
| 107 | getaddr(char *pattern) | ||
| 108 | { | ||
| 109 | /* Get char offset into dictionary of matches. */ | ||
| 110 | |||
| 111 | int fd, i; | ||
| 112 | Biobuf inbuf; | ||
| 113 | char *bufptr; | ||
| 114 | char *obuf; | ||
| 115 | |||
| 116 | if (pattern == nil) { | ||
| 117 | curone = nil; | ||
| 118 | curindex = 0; | ||
| 119 | curaddr[curindex] = nil; | ||
| 120 | return 0; | ||
| 121 | } | ||
| 122 | |||
| 123 | sprint(buffer,"/%s/A", pattern); | ||
| 124 | fd = procrexec(xprog, "-d", dict, "-c", buffer, nil); | ||
| 125 | Binit(&inbuf, fd, OREAD); | ||
| 126 | i = 0; | ||
| 127 | curindex = 0; | ||
| 128 | while ((bufptr = Brdline(&inbuf, '\n')) != nil && (i < (MAXMATCH-1))) { | ||
| 129 | bufptr[Blinelen(&inbuf)-1] = 0; | ||
| 130 | obuf=bufptr; | ||
| 131 | while (bufptr[0] != '#' && bufptr[0] != 0) bufptr++; | ||
| 132 | if(bufptr[0] == 0) | ||
| 133 | print("whoops buf «%s»\n", obuf); | ||
| 134 | curaddr[i] = malloc(strlen(bufptr)); | ||
| 135 | strcpy(curaddr[i], bufptr); | ||
| 136 | i++; | ||
| 137 | } | ||
| 138 | curaddr[i] = nil; | ||
| 139 | if (i == MAXMATCH) | ||
| 140 | fprint(2, "Too many matches!\n"); | ||
| 141 | Bterm(&inbuf); | ||
| 142 | close(fd); | ||
| 143 | |||
| 144 | curone = curaddr[curindex]; | ||
| 145 | return(i); | ||
| 146 | } | ||
| 147 | |||
| 148 | char* | ||
| 149 | getpattern(char *addr) | ||
| 150 | { | ||
| 151 | /* Get the pattern corresponding to an absolute address.*/ | ||
| 152 | int fd; | ||
| 153 | char *res, *t; | ||
| 154 | |||
| 155 | res = nil; | ||
| 156 | sprint(buffer,"%sh", addr); | ||
| 157 | fd = procrexec(xprog, "-d", dict, "-c", buffer, nil); | ||
| 158 | if (read(fd, pbuffer, 80) > 80) | ||
| 159 | fprint(2, "Error in getting addres from dict.\n"); | ||
| 160 | else { | ||
| 161 | t = pbuffer; | ||
| 162 | /* remove trailing whitespace, newline */ | ||
| 163 | if (t != nil){ | ||
| 164 | while(*t != 0 && *t != '\n') | ||
| 165 | t++; | ||
| 166 | if(t == 0 && t > pbuffer) | ||
| 167 | t--; | ||
| 168 | while(t >= pbuffer && (*t==' ' || *t=='\n' || *t=='\t' || *t=='\r')) | ||
| 169 | *t-- = 0; | ||
| 170 | } | ||
| 171 | res = pbuffer; | ||
| 172 | } | ||
| 173 | close(fd); | ||
| 174 | return(res); | ||
| 175 | } | ||
| 176 | |||
| 177 | char* | ||
| 178 | chgaddr(int dir) | ||
| 179 | { | ||
| 180 | /* Increment or decrement the current address (curone). */ | ||
| 181 | |||
| 182 | int fd; | ||
| 183 | char *res, *t; | ||
| 184 | |||
| 185 | res = nil; | ||
| 186 | if (dir < 0) | ||
| 187 | sprint(buffer,"%s-a", curone); | ||
| 188 | else | ||
| 189 | sprint(buffer,"%s+a", curone); | ||
| 190 | fd = procrexec(xprog, "-d", dict, "-c", buffer, nil); | ||
| 191 | if (read(fd, abuffer, 80) > 80) | ||
| 192 | fprint(2, "Error in getting addres from dict.\n"); | ||
| 193 | else { | ||
| 194 | res = abuffer; | ||
| 195 | while (*res != '#') res++; | ||
| 196 | t = res; | ||
| 197 | while ((*t != '\n') && (t != nil)) t++; | ||
| 198 | if (t != nil) *t = 0; | ||
| 199 | } | ||
| 200 | close(fd); | ||
| 201 | return(res); | ||
| 202 | } | ||
| 203 | |||
| 204 | void | ||
| 205 | dispdicts(Win *cwin) | ||
| 206 | { | ||
| 207 | /* Display available dictionaries in window. */ | ||
| 208 | |||
| 209 | int fd, nb, i; | ||
| 210 | char buf[1024], *t; | ||
| 211 | |||
| 212 | fd = procrexec(xprog, "-d", "?", nil); | ||
| 213 | wreplace(cwin, "0,$","",0); /* Clear window */ | ||
| 214 | while ((nb = read(fd, buf, 1024)) > 0) { | ||
| 215 | t = buf; | ||
| 216 | i = 0; | ||
| 217 | if (strncmp("Usage", buf, 5) == 0) { /* Remove first line. */ | ||
| 218 | while (t[0] != '\n') { | ||
| 219 | t++; | ||
| 220 | i++; | ||
| 221 | } | ||
| 222 | t++; | ||
| 223 | i++; | ||
| 224 | } | ||
| 225 | wwritebody(cwin, t, nb-i); | ||
| 226 | } | ||
| 227 | close(fd); | ||
| 228 | wclean(cwin); | ||
| 229 | } | ||
| 230 | |||
| 231 | void | ||
| 232 | dispentry(Win *cwin) | ||
| 233 | { | ||
| 234 | /* Display the current selection in window. */ | ||
| 235 | |||
| 236 | int fd, nb; | ||
| 237 | char buf[BUFSIZE]; | ||
| 238 | |||
| 239 | if (curone == nil) { | ||
| 240 | if (pattern != nil) { | ||
| 241 | sprint(buf,"Pattern not found.\n"); | ||
| 242 | wwritebody(cwin, buf, 19); | ||
| 243 | wclean(cwin); | ||
| 244 | } | ||
| 245 | return; | ||
| 246 | } | ||
| 247 | sprint(buffer,"%sp", curone); | ||
| 248 | fd = procrexec(xprog, "-d", dict, "-c", buffer, nil); | ||
| 249 | wreplace(cwin, "0,$","",0); /* Clear window */ | ||
| 250 | while ((nb = read(fd, buf, BUFSIZE)) > 0) { | ||
| 251 | wwritebody(cwin, buf, nb); | ||
| 252 | } | ||
| 253 | close(fd); | ||
| 254 | wclean(cwin); | ||
| 255 | } | ||
| 256 | |||
| 257 | void | ||
| 258 | dispmatches(Win *cwin) | ||
| 259 | { | ||
| 260 | /* Display the current matches. */ | ||
| 261 | |||
| 262 | int fd, nb; | ||
| 263 | char buf[BUFSIZE]; | ||
| 264 | |||
| 265 | sprint(buffer,"/%s/H", pattern); | ||
| 266 | fd = procrexec(xprog, "-d", dict, "-c", buffer, nil); | ||
| 267 | while ((nb = read(fd, buf, BUFSIZE)) > 0) | ||
| 268 | wwritebody(cwin, buf, nb); | ||
| 269 | close(fd); | ||
| 270 | wclean(cwin); | ||
| 271 | } | ||
| 272 | |||
| 273 | char* | ||
| 274 | format(char *s) | ||
| 275 | { | ||
| 276 | /* Format a string to be written in window tag. Acme doesn't like */ | ||
| 277 | /* non alpha-num's in the tag line. */ | ||
| 278 | |||
| 279 | char *t, *h; | ||
| 280 | |||
| 281 | t = fbuffer; | ||
| 282 | if (s == nil) { | ||
| 283 | *t = 0; | ||
| 284 | return t; | ||
| 285 | } | ||
| 286 | strcpy(t, s); | ||
| 287 | h = t; | ||
| 288 | while (*t != 0) { | ||
| 289 | if (!(((*t >= 'a') && (*t <= 'z')) || | ||
| 290 | ((*t >= 'A') && (*t <= 'Z')) || | ||
| 291 | ((*t >= '0') && (*t <= '9')))) | ||
| 292 | *t = '_'; | ||
| 293 | t++; | ||
| 294 | } | ||
| 295 | if (strlen(h) > MAXTAG) | ||
| 296 | h[MAXTAG] = 0; | ||
| 297 | if (strcmp(s,h) == 0) return s; | ||
| 298 | return h; | ||
| 299 | } | ||
| 300 | |||
| 301 | void | ||
| 302 | openwin(char *name, char *buttons, Win *twin, int wintype) | ||
| 303 | { | ||
| 304 | char buf[80]; | ||
| 305 | |||
| 306 | wnew(twin); | ||
| 307 | if (wintype == Dictwin) | ||
| 308 | sprint(buf,"%s",name); | ||
| 309 | else | ||
| 310 | if ((wintype == Entrywin) && (count > 1)) | ||
| 311 | sprint(buf,"%s/%s/%s/%d",name, dict, format(pattern), curindex+1); | ||
| 312 | else | ||
| 313 | sprint(buf,"%s/%s/%s",name, dict, format(pattern)); | ||
| 314 | wname(twin, buf); | ||
| 315 | wtagwrite(twin, buttons, strlen(buttons)); | ||
| 316 | wclean(twin); | ||
| 317 | wdormant(twin); | ||
| 318 | if (wintype == Dictwin) | ||
| 319 | dispdicts(twin); | ||
| 320 | if (wintype == Matchwin) { | ||
| 321 | Mopen = True; | ||
| 322 | dispmatches(twin); | ||
| 323 | } | ||
| 324 | if (wintype == Entrywin) { | ||
| 325 | Eopen = True; | ||
| 326 | dispentry(twin); | ||
| 327 | } | ||
| 328 | handle(twin, wintype); | ||
| 329 | } | ||
| 330 | |||
| 331 | void | ||
| 332 | vopenwin(void *v) | ||
| 333 | { | ||
| 334 | void **arg; | ||
| 335 | char *name, *buttons; | ||
| 336 | Win *twin; | ||
| 337 | int wintype; | ||
| 338 | |||
| 339 | arg = v; | ||
| 340 | name = arg[0]; | ||
| 341 | buttons = arg[1]; | ||
| 342 | twin = arg[2]; | ||
| 343 | wintype = (int)arg[3]; | ||
| 344 | sendul(arg[4], 0); | ||
| 345 | |||
| 346 | openwin(name, buttons, twin, wintype); | ||
| 347 | threadexits(nil); | ||
| 348 | } | ||
| 349 | |||
| 350 | void | ||
| 351 | procopenwin(char *name, char *buttons, Win *twin, int wintype) | ||
| 352 | { | ||
| 353 | void *arg[5]; | ||
| 354 | Channel *c; | ||
| 355 | |||
| 356 | c = chancreate(sizeof(ulong), 0); | ||
| 357 | arg[0] = name; | ||
| 358 | arg[1] = buttons; | ||
| 359 | arg[2] = twin; | ||
| 360 | arg[3] = (void*)wintype; | ||
| 361 | arg[4] = c; | ||
| 362 | proccreate(vopenwin, arg, STACK); | ||
| 363 | recvul(c); | ||
| 364 | chanfree(c); | ||
| 365 | } | ||
| 366 | |||
| 367 | void | ||
| 368 | rexec(void *v) | ||
| 369 | { | ||
| 370 | void **arg; | ||
| 371 | char *prog; | ||
| 372 | char **args; | ||
| 373 | int *fd; | ||
| 374 | Channel *c; | ||
| 375 | |||
| 376 | arg = v; | ||
| 377 | prog = arg[0]; | ||
| 378 | args = arg[1]; | ||
| 379 | fd = arg[2]; | ||
| 380 | c = arg[3]; | ||
| 381 | |||
| 382 | rfork(RFENVG|RFFDG); | ||
| 383 | dup(fd[1], 1); | ||
| 384 | close(fd[1]); | ||
| 385 | close(fd[0]); | ||
| 386 | procexec(c, prog, args); | ||
| 387 | fprint(2, "Remote pipe execution failed: %s %r\n", prog); | ||
| 388 | abort(); | ||
| 389 | threadexits(nil); | ||
| 390 | } | ||
| 391 | |||
| 392 | void | ||
| 393 | pexec(void *v) | ||
| 394 | { | ||
| 395 | void **arg; | ||
| 396 | char *prog; | ||
| 397 | char **args; | ||
| 398 | Channel *c; | ||
| 399 | |||
| 400 | arg = v; | ||
| 401 | prog = arg[0]; | ||
| 402 | args = arg[1]; | ||
| 403 | c = arg[2]; | ||
| 404 | |||
| 405 | procexec(c, prog, args); | ||
| 406 | fprint(2, "Remote execution failed: %s %r\n", prog); | ||
| 407 | abort(); | ||
| 408 | threadexits(nil); | ||
| 409 | } | ||
| 410 | |||
| 411 | void | ||
| 412 | procpexec(char *prog, char **args) | ||
| 413 | { | ||
| 414 | void *rexarg[4]; | ||
| 415 | Channel *c; | ||
| 416 | |||
| 417 | c = chancreate(sizeof(ulong), 0); | ||
| 418 | rexarg[0] = prog; | ||
| 419 | rexarg[1] = args; | ||
| 420 | rexarg[2] = c; | ||
| 421 | |||
| 422 | proccreate(pexec, rexarg, STACK); | ||
| 423 | recvul(c); | ||
| 424 | chanfree(c); | ||
| 425 | } | ||
| 426 | |||
| 427 | void | ||
| 428 | kill(void) | ||
| 429 | { | ||
| 430 | /* Kill all processes related to this one. */ | ||
| 431 | int fd; | ||
| 432 | |||
| 433 | sprint(buffer, "/proc/%d/notepg", getpid()); | ||
| 434 | fd = open(buffer, OWRITE); | ||
| 435 | rfork(RFNOTEG); | ||
| 436 | write(fd, "kill", 4); | ||
| 437 | } | ||
| 438 | |||
| 439 | int | ||
| 440 | command(char *com, Win *w, int wintype) | ||
| 441 | { | ||
| 442 | char *buf; | ||
| 443 | |||
| 444 | if (strncmp(com, "Del", 3) == 0) { | ||
| 445 | switch(wintype){ | ||
| 446 | case Entrywin: | ||
| 447 | if (wdel(w)) { | ||
| 448 | Eopen = False; | ||
| 449 | threadexits(nil); | ||
| 450 | } | ||
| 451 | break; | ||
| 452 | case Dictwin: | ||
| 453 | if (wdel(w)) | ||
| 454 | threadexits(nil); | ||
| 455 | break; | ||
| 456 | case Matchwin: | ||
| 457 | kill(); | ||
| 458 | if (Eopen) | ||
| 459 | if (~wdel(&Ewin)) /* Remove the entry window */ | ||
| 460 | wdel(&Ewin); | ||
| 461 | if (!wdel(w)) | ||
| 462 | wdel(w); | ||
| 463 | threadexits(nil); | ||
| 464 | break; | ||
| 465 | } | ||
| 466 | return True; | ||
| 467 | } | ||
| 468 | if (strncmp(com, "Next", 4) == 0){ | ||
| 469 | if (curone != nil) { | ||
| 470 | curone = chgaddr(1); | ||
| 471 | buf = getpattern(curone); | ||
| 472 | sprint(buffer,"%s/%s/%s", prog, dict, format(buf)); | ||
| 473 | wname(w, buffer); | ||
| 474 | dispentry(w); | ||
| 475 | } | ||
| 476 | return True; | ||
| 477 | } | ||
| 478 | if (strncmp(com, "Prev",4) == 0){ | ||
| 479 | if (curone != nil) { | ||
| 480 | curone = chgaddr(-1); | ||
| 481 | buf = getpattern(curone); | ||
| 482 | sprint(buffer,"%s/%s/%s", prog, dict, format(buf)); | ||
| 483 | wname(w, buffer); | ||
| 484 | dispentry(w); | ||
| 485 | } | ||
| 486 | return True; | ||
| 487 | } | ||
| 488 | if (strncmp(com, "Nmatch",6) == 0){ | ||
| 489 | if (curaddr[++curindex] == nil) | ||
| 490 | curindex = 0; | ||
| 491 | curone = curaddr[curindex]; | ||
| 492 | if (curone != nil) { | ||
| 493 | sprint(buffer,"%s/%s/%s/%d",prog,dict,format(pattern),curindex+1); | ||
| 494 | wname(w, buffer); | ||
| 495 | dispentry(w); | ||
| 496 | } | ||
| 497 | return True; | ||
| 498 | } | ||
| 499 | return False; | ||
| 500 | } | ||
| 501 | |||
| 502 | void | ||
| 503 | handle(Win *w, int wintype) | ||
| 504 | { | ||
| 505 | Event e, e2, ea, etoss; | ||
| 506 | char *s, *t, buf[80]; | ||
| 507 | int tmp, na; | ||
| 508 | |||
| 509 | while (True) { | ||
| 510 | wevent(w, &e); | ||
| 511 | switch(e.c2){ | ||
| 512 | default: | ||
| 513 | /* fprint(2,"unknown message %c%c\n", e.c1, e.c2); */ | ||
| 514 | break; | ||
| 515 | case 'i': | ||
| 516 | /* fprint(2,"'%s' inserted in tag at %d\n", e.b, e.q0);*/ | ||
| 517 | break; | ||
| 518 | case 'I': | ||
| 519 | /* fprint(2,"'%s' inserted in body at %d\n", e.b, e.q0);*/ | ||
| 520 | break; | ||
| 521 | case 'd': | ||
| 522 | /* fprint(2, "'%s' deleted in tag at %d\n", e.b, e.q0);*/ | ||
| 523 | break; | ||
| 524 | case 'D': | ||
| 525 | /* fprint(2, "'%s' deleted in body at %d\n", e.b, e.q0);*/ | ||
| 526 | break; | ||
| 527 | case 'x': | ||
| 528 | case 'X': /* Execute command. */ | ||
| 529 | if (e.flag & 2) | ||
| 530 | wevent(w, &e2); | ||
| 531 | if(e.flag & 8){ | ||
| 532 | wevent(w, &ea); | ||
| 533 | wevent(w, &etoss); | ||
| 534 | na = ea.nb; | ||
| 535 | } else | ||
| 536 | na = 0; | ||
| 537 | s = e.b; | ||
| 538 | if ((e.flag & 2) && e.nb == 0) | ||
| 539 | s = e2.b; | ||
| 540 | if(na){ | ||
| 541 | t = malloc(strlen(s)+1+na+1); | ||
| 542 | snprint(t, strlen(s)+1+na+1, "%s %s", s, ea.b); | ||
| 543 | s = t; | ||
| 544 | } | ||
| 545 | /* if it's a long message, it can't be for us anyway */ | ||
| 546 | if(!command(s, w, wintype)) /* send it back */ | ||
| 547 | wwriteevent(w, &e); | ||
| 548 | if(na) | ||
| 549 | free(s); | ||
| 550 | break; | ||
| 551 | case 'l': | ||
| 552 | case 'L': /* Look for something. */ | ||
| 553 | if (e.flag & 2) | ||
| 554 | wevent(w, &e); | ||
| 555 | wclean(w); /* Set clean bit. */ | ||
| 556 | if (wintype == Dictwin) { | ||
| 557 | strcpy(buf, e.b); | ||
| 558 | args[0] = lprog; | ||
| 559 | args[1] = "-d"; | ||
| 560 | args[2] = buf; | ||
| 561 | args[3] = nil; | ||
| 562 | procpexec(lprog, args); /* New adict with chosen dict. */ | ||
| 563 | } | ||
| 564 | if (wintype == Entrywin) { | ||
| 565 | strcpy(buf, e.b); | ||
| 566 | args[0] = lprog; | ||
| 567 | args[1] = "-d"; | ||
| 568 | args[2] = dict; | ||
| 569 | args[3] = buf; | ||
| 570 | args[4] = nil; | ||
| 571 | procpexec(lprog, args); /* New adict with chosen pattern. */ | ||
| 572 | } | ||
| 573 | if (wintype == Matchwin) { | ||
| 574 | tmp = atoi(e.b) - 1; | ||
| 575 | if ((tmp >= 0) && (tmp < MAXMATCH) && (curaddr[tmp] != nil)) { | ||
| 576 | curindex = tmp; | ||
| 577 | curone = curaddr[curindex]; | ||
| 578 | /* Display selected match. */ | ||
| 579 | if (Eopen) { | ||
| 580 | sprint(buf,"%s/%s/%s/%d",prog,dict,format(pattern),curindex+1); | ||
| 581 | wname(&Ewin, buf); | ||
| 582 | dispentry(&Ewin); | ||
| 583 | } | ||
| 584 | else | ||
| 585 | procopenwin(prog,"Nmatch Prev Next", &Ewin, Entrywin); | ||
| 586 | } | ||
| 587 | } | ||
| 588 | break; | ||
| 589 | } | ||
| 590 | } | ||
| 591 | } | ||
| @@ -0,0 +1,10 @@ | |||
| 1 | enum | ||
| 2 | { | ||
| 3 | Matchwin, | ||
| 4 | Entrywin, | ||
| 5 | Dictwin | ||
| 6 | }; | ||
| 7 | |||
| 8 | #define MAXTAG 20 | ||
| 9 | #define MAXMATCH 100 | ||
| 10 | #define BUFSIZE 4096 | ||
| @@ -0,0 +1,26 @@ | |||
| 1 | adict [-d dictionary] [pattern] | ||
| 2 | |||
| 3 | adict with no arguments opens a window that displays all the currently | ||
| 4 | available dictionaries. To select a dictionary, click the right mouse button on | ||
| 5 | its name. | ||
| 6 | |||
| 7 | -d dictionary Opens a window that interfaces to the specified dictionary. To | ||
| 8 | look up a word, enter it in the window, and click the right mouse button on it. | ||
| 9 | |||
| 10 | [pattern] If no dictionary is specified, adict looks up the pattern in "oed" (Oxford | ||
| 11 | English Dictionary). If more than one entry is found, adict opens a window | ||
| 12 | displaying the headers of the matching entries. To display a particular entry | ||
| 13 | click the right mouse button on the number to its left. | ||
| 14 | |||
| 15 | Quit Exit and remove all windows associated with this one. | ||
| 16 | |||
| 17 | Nmatch Display the next matching entry. | ||
| 18 | |||
| 19 | Next Display the next entry in the dictionary. | ||
| 20 | |||
| 21 | Prev Display the previous entry in the dictionary. | ||
| 22 | |||
| 23 | Nmatch works independently of Prev and Next. | ||
| 24 | |||
| 25 | Any word in the window displaying an entry can be looked up in the selected | ||
| 26 | dictionary by clicking the right mouse button on that word. | ||
| @@ -0,0 +1,11 @@ | |||
| 1 | </$objtype/mkfile | ||
| 2 | |||
| 3 | TARG=adict | ||
| 4 | |||
| 5 | HFILES=win.h | ||
| 6 | |||
| 7 | OFILES=adict.$O\ | ||
| 8 | win.$O\ | ||
| 9 | |||
| 10 | BIN= /acme/bin/$objtype | ||
| 11 | </sys/src/cmd/mkone | ||
| @@ -0,0 +1,315 @@ | |||
| 1 | #include <u.h> | ||
| 2 | #include <libc.h> | ||
| 3 | #include <bio.h> | ||
| 4 | #include <thread.h> | ||
| 5 | #include "win.h" | ||
| 6 | |||
| 7 | void* | ||
| 8 | erealloc(void *p, uint n) | ||
| 9 | { | ||
| 10 | p = realloc(p, n); | ||
| 11 | if(p == nil) | ||
| 12 | fprint(2, "realloc failed: %r"); | ||
| 13 | return p; | ||
| 14 | } | ||
| 15 | |||
| 16 | void | ||
| 17 | wnew(Win *w) | ||
| 18 | { | ||
| 19 | char buf[12]; | ||
| 20 | |||
| 21 | w->ctl = open("/mnt/acme/new/ctl", ORDWR); | ||
| 22 | if(w->ctl<0 || read(w->ctl, buf, 12)!=12) | ||
| 23 | fprint (2, "can't open window ctl file: %r"); | ||
| 24 | ctlwrite(w, "noscroll\n"); | ||
| 25 | w->winid = atoi(buf); | ||
| 26 | w->event = openfile(w, "event"); | ||
| 27 | w->addr = -1; /* will be opened when needed */ | ||
| 28 | w->body = nil; | ||
| 29 | w->data = -1; | ||
| 30 | } | ||
| 31 | |||
| 32 | int | ||
| 33 | openfile(Win *w, char *f) | ||
| 34 | { | ||
| 35 | char buf[64]; | ||
| 36 | int fd; | ||
| 37 | |||
| 38 | sprint(buf, "/mnt/acme/%d/%s", w->winid, f); | ||
| 39 | fd = open(buf, ORDWR|OCEXEC); | ||
| 40 | if(fd < 0) | ||
| 41 | fprint (2,"can't open window %s file: %r", f); | ||
| 42 | return fd; | ||
| 43 | } | ||
| 44 | |||
| 45 | void | ||
| 46 | openbody(Win *w, int mode) | ||
| 47 | { | ||
| 48 | char buf[64]; | ||
| 49 | |||
| 50 | sprint(buf, "/mnt/acme/%d/body", w->winid); | ||
| 51 | w->body = Bopen(buf, mode|OCEXEC); | ||
| 52 | if(w->body == nil) | ||
| 53 | fprint(2,"can't open window body file: %r"); | ||
| 54 | } | ||
| 55 | |||
| 56 | void | ||
| 57 | wwritebody(Win *w, char *s, int n) | ||
| 58 | { | ||
| 59 | if(w->body == nil) | ||
| 60 | openbody(w, OWRITE); | ||
| 61 | if(Bwrite(w->body, s, n) != n) | ||
| 62 | fprint(2,"write error to window: %r"); | ||
| 63 | Bflush(w->body); | ||
| 64 | } | ||
| 65 | |||
| 66 | void | ||
| 67 | wreplace(Win *w, char *addr, char *repl, int nrepl) | ||
| 68 | { | ||
| 69 | if(w->addr < 0) | ||
| 70 | w->addr = openfile(w, "addr"); | ||
| 71 | if(w->data < 0) | ||
| 72 | w->data = openfile(w, "data"); | ||
| 73 | if(write(w->addr, addr, strlen(addr)) < 0){ | ||
| 74 | fprint(2, "mail: warning: badd address %s:%r\n", addr); | ||
| 75 | return; | ||
| 76 | } | ||
| 77 | if(write(w->data, repl, nrepl) != nrepl) | ||
| 78 | fprint(2, "writing data: %r"); | ||
| 79 | } | ||
| 80 | |||
| 81 | static int | ||
| 82 | nrunes(char *s, int nb) | ||
| 83 | { | ||
| 84 | int i, n; | ||
| 85 | Rune r; | ||
| 86 | |||
| 87 | n = 0; | ||
| 88 | for(i=0; i<nb; n++) | ||
| 89 | i += chartorune(&r, s+i); | ||
| 90 | return n; | ||
| 91 | } | ||
| 92 | |||
| 93 | void | ||
| 94 | wread(Win *w, uint q0, uint q1, char *data) | ||
| 95 | { | ||
| 96 | int m, n, nr; | ||
| 97 | char buf[256]; | ||
| 98 | |||
| 99 | if(w->addr < 0) | ||
| 100 | w->addr = openfile(w, "addr"); | ||
| 101 | if(w->data < 0) | ||
| 102 | w->data = openfile(w, "data"); | ||
| 103 | m = q0; | ||
| 104 | while(m < q1){ | ||
| 105 | n = sprint(buf, "#%d", m); | ||
| 106 | if(write(w->addr, buf, n) != n) | ||
| 107 | fprint(2,"writing addr: %r"); | ||
| 108 | n = read(w->data, buf, sizeof buf); | ||
| 109 | if(n <= 0) | ||
| 110 | fprint(2,"reading data: %r"); | ||
| 111 | nr = nrunes(buf, n); | ||
| 112 | while(m+nr >q1){ | ||
| 113 | do; while(n>0 && (buf[--n]&0xC0)==0x80); | ||
| 114 | --nr; | ||
| 115 | } | ||
| 116 | if(n == 0) | ||
| 117 | break; | ||
| 118 | memmove(data, buf, n); | ||
| 119 | data += n; | ||
| 120 | *data = 0; | ||
| 121 | m += nr; | ||
| 122 | } | ||
| 123 | } | ||
| 124 | |||
| 125 | void | ||
| 126 | wselect(Win *w, char *addr) | ||
| 127 | { | ||
| 128 | if(w->addr < 0) | ||
| 129 | w->addr = openfile(w, "addr"); | ||
| 130 | if(write(w->addr, addr, strlen(addr)) < 0) | ||
| 131 | fprint(2,"writing addr"); | ||
| 132 | ctlwrite(w, "dot=addr\n"); | ||
| 133 | } | ||
| 134 | |||
| 135 | void | ||
| 136 | wtagwrite(Win *w, char *s, int n) | ||
| 137 | { | ||
| 138 | int fd; | ||
| 139 | |||
| 140 | fd = openfile(w, "tag"); | ||
| 141 | if(write(fd, s, n) != n) | ||
| 142 | fprint(2,"tag write: %r"); | ||
| 143 | close(fd); | ||
| 144 | } | ||
| 145 | |||
| 146 | void | ||
| 147 | ctlwrite(Win *w, char *s) | ||
| 148 | { | ||
| 149 | int n; | ||
| 150 | |||
| 151 | n = strlen(s); | ||
| 152 | if(write(w->ctl, s, n) != n) | ||
| 153 | fprint(2,"write error to ctl file: %r"); | ||
| 154 | } | ||
| 155 | |||
| 156 | int | ||
| 157 | wdel(Win *w) | ||
| 158 | { | ||
| 159 | if(write(w->ctl, "del\n", 4) != 4) | ||
| 160 | return False; | ||
| 161 | wdormant(w); | ||
| 162 | close(w->ctl); | ||
| 163 | w->ctl = -1; | ||
| 164 | close(w->event); | ||
| 165 | w->event = -1; | ||
| 166 | return True; | ||
| 167 | } | ||
| 168 | |||
| 169 | void | ||
| 170 | wname(Win *w, char *s) | ||
| 171 | { | ||
| 172 | char buf[128]; | ||
| 173 | |||
| 174 | sprint(buf, "name %s\n", s); | ||
| 175 | ctlwrite(w, buf); | ||
| 176 | } | ||
| 177 | |||
| 178 | void | ||
| 179 | wclean(Win *w) | ||
| 180 | { | ||
| 181 | if(w->body) | ||
| 182 | Bflush(w->body); | ||
| 183 | ctlwrite(w, "clean\n"); | ||
| 184 | } | ||
| 185 | |||
| 186 | void | ||
| 187 | wdormant(Win *w) | ||
| 188 | { | ||
| 189 | if(w->addr >= 0){ | ||
| 190 | close(w->addr); | ||
| 191 | w->addr = -1; | ||
| 192 | } | ||
| 193 | if(w->body != nil){ | ||
| 194 | Bterm(w->body); | ||
| 195 | w->body = nil; | ||
| 196 | } | ||
| 197 | if(w->data >= 0){ | ||
| 198 | close(w->data); | ||
| 199 | w->data = -1; | ||
| 200 | } | ||
| 201 | } | ||
| 202 | |||
| 203 | int | ||
| 204 | getec(Win *w) | ||
| 205 | { | ||
| 206 | if(w->nbuf == 0){ | ||
| 207 | w->nbuf = read(w->event, w->buf, sizeof w->buf); | ||
| 208 | if(w->nbuf <= 0) | ||
| 209 | fprint(2,"event read error: %r"); | ||
| 210 | w->bufp = w->buf; | ||
| 211 | } | ||
| 212 | w->nbuf--; | ||
| 213 | return *w->bufp++; | ||
| 214 | } | ||
| 215 | |||
| 216 | int | ||
| 217 | geten(Win *w) | ||
| 218 | { | ||
| 219 | int n, c; | ||
| 220 | |||
| 221 | n = 0; | ||
| 222 | while('0'<=(c=getec(w)) && c<='9') | ||
| 223 | n = n*10+(c-'0'); | ||
| 224 | if(c != ' ') | ||
| 225 | fprint(2, "event number syntax"); | ||
| 226 | return n; | ||
| 227 | } | ||
| 228 | |||
| 229 | int | ||
| 230 | geter(Win *w, char *buf, int *nb) | ||
| 231 | { | ||
| 232 | Rune r; | ||
| 233 | int n; | ||
| 234 | |||
| 235 | r = getec(w); | ||
| 236 | buf[0] = r; | ||
| 237 | n = 1; | ||
| 238 | if(r < Runeself) | ||
| 239 | goto Return; | ||
| 240 | while(!fullrune(buf, n)) | ||
| 241 | buf[n++] = getec(w); | ||
| 242 | chartorune(&r, buf); | ||
| 243 | Return: | ||
| 244 | *nb = n; | ||
| 245 | return r; | ||
| 246 | } | ||
| 247 | |||
| 248 | |||
| 249 | void | ||
| 250 | wevent(Win *w, Event *e) | ||
| 251 | { | ||
| 252 | int i, nb; | ||
| 253 | |||
| 254 | e->c1 = getec(w); | ||
| 255 | e->c2 = getec(w); | ||
| 256 | e->q0 = geten(w); | ||
| 257 | e->q1 = geten(w); | ||
| 258 | e->flag = geten(w); | ||
| 259 | e->nr = geten(w); | ||
| 260 | if(e->nr > EVENTSIZE) | ||
| 261 | fprint(2, "wevent: event string too long"); | ||
| 262 | e->nb = 0; | ||
| 263 | for(i=0; i<e->nr; i++){ | ||
| 264 | e->r[i] = geter(w, e->b+e->nb, &nb); | ||
| 265 | e->nb += nb; | ||
| 266 | } | ||
| 267 | e->r[e->nr] = 0; | ||
| 268 | e->b[e->nb] = 0; | ||
| 269 | if(getec(w) != '\n') | ||
| 270 | fprint(2, "wevent: event syntax 2"); | ||
| 271 | } | ||
| 272 | |||
| 273 | void | ||
| 274 | wslave(Win *w, Channel *ce) | ||
| 275 | { | ||
| 276 | Event e; | ||
| 277 | |||
| 278 | while(recv(ce, &e) >= 0) | ||
| 279 | wevent(w, &e); | ||
| 280 | } | ||
| 281 | |||
| 282 | void | ||
| 283 | wwriteevent(Win *w, Event *e) | ||
| 284 | { | ||
| 285 | fprint(w->event, "%c%c%d %d\n", e->c1, e->c2, e->q0, e->q1); | ||
| 286 | } | ||
| 287 | |||
| 288 | int | ||
| 289 | wreadall(Win *w, char **sp) | ||
| 290 | { | ||
| 291 | char *s; | ||
| 292 | int m, na, n; | ||
| 293 | |||
| 294 | if(w->body != nil) | ||
| 295 | Bterm(w->body); | ||
| 296 | openbody(w, OREAD); | ||
| 297 | s = nil; | ||
| 298 | na = 0; | ||
| 299 | n = 0; | ||
| 300 | for(;;){ | ||
| 301 | if(na < n+512){ | ||
| 302 | na += 1024; | ||
| 303 | s = erealloc(s, na+1); | ||
| 304 | } | ||
| 305 | m = Bread(w->body, s+n, na-n); | ||
| 306 | if(m <= 0) | ||
| 307 | break; | ||
| 308 | n += m; | ||
| 309 | } | ||
| 310 | s[n] = 0; | ||
| 311 | Bterm(w->body); | ||
| 312 | w->body = nil; | ||
| 313 | *sp = s; | ||
| 314 | return n; | ||
| 315 | } | ||
| @@ -0,0 +1,59 @@ | |||
| 1 | enum | ||
| 2 | { | ||
| 3 | False, | ||
| 4 | True, | ||
| 5 | EVENTSIZE=256, | ||
| 6 | }; | ||
| 7 | |||
| 8 | |||
| 9 | typedef struct Event Event; | ||
| 10 | struct Event | ||
| 11 | { | ||
| 12 | int c1; | ||
| 13 | int c2; | ||
| 14 | int q0; | ||
| 15 | int q1; | ||
| 16 | int flag; | ||
| 17 | int nb; | ||
| 18 | int nr; | ||
| 19 | char b[EVENTSIZE*UTFmax+1]; | ||
| 20 | Rune r[EVENTSIZE+1]; | ||
| 21 | }; | ||
| 22 | |||
| 23 | |||
| 24 | typedef struct Win Win; | ||
| 25 | struct Win | ||
| 26 | { | ||
| 27 | int winid; | ||
| 28 | int addr; | ||
| 29 | Biobuf *body; | ||
| 30 | int ctl; | ||
| 31 | int data; | ||
| 32 | int event; | ||
| 33 | char buf[512]; | ||
| 34 | char *bufp; | ||
| 35 | int nbuf; | ||
| 36 | }; | ||
| 37 | |||
| 38 | int dead(Win*); | ||
| 39 | void wnew(Win*); | ||
| 40 | void wwritebody(Win*, char *s, int n); | ||
| 41 | void wread(Win*, uint, uint, char*); | ||
| 42 | void wclean(Win*); | ||
| 43 | void wname(Win*, char*); | ||
| 44 | void wdormant(Win*); | ||
| 45 | void wevent(Win*, Event*); | ||
| 46 | void wtagwrite(Win*, char*, int); | ||
| 47 | void wwriteevent(Win*, Event*); | ||
| 48 | void wslave(Win*, Channel*); /* chan(Event) */ | ||
| 49 | void wreplace(Win*, char*, char*, int); | ||
| 50 | void wselect(Win*, char*); | ||
| 51 | int wdel(Win*); | ||
| 52 | int wreadall(Win*, char**); | ||
| 53 | |||
| 54 | void ctlwrite(Win*, char*); | ||
| 55 | int getec(Win*); | ||
| 56 | int geten(Win*); | ||
| 57 | int geter(Win*, char*, int*); | ||
| 58 | int openfile(Win*, char*); | ||
| 59 | void openbody(Win*, int); | ||
| @@ -0,0 +1,27 @@ | |||
| 1 | </$objtype/mkfile | ||
| 2 | |||
| 3 | TARG=\ | ||
| 4 | mkwnew\ | ||
| 5 | spout\ | ||
| 6 | |||
| 7 | OFILES= | ||
| 8 | HFILES= | ||
| 9 | LIB= | ||
| 10 | |||
| 11 | DIRS=win | ||
| 12 | |||
| 13 | BIN=../$objtype | ||
| 14 | |||
| 15 | </sys/src/cmd/mkmany | ||
| 16 | |||
| 17 | all:V: all.dirs | ||
| 18 | install:V: install.dirs | ||
| 19 | clean:V: clean.dirs | ||
| 20 | nuke:V: nuke.dirs | ||
| 21 | |||
| 22 | %.dirs:VQ: | ||
| 23 | for (i in $DIRS) @{ | ||
| 24 | echo mk $i | ||
| 25 | cd $i | ||
| 26 | mk $stem | ||
| 27 | } | ||
Binary file not shown.
Binary file not shown.
| @@ -0,0 +1,45 @@ | |||
| 1 | #include <u.h> | ||
| 2 | #include <libc.h> | ||
| 3 | |||
| 4 | void | ||
| 5 | main(int argc, char *argv[]) | ||
| 6 | { | ||
| 7 | int i, fd, pid, n; | ||
| 8 | char wdir[256]; | ||
| 9 | int dflag; | ||
| 10 | |||
| 11 | dflag = 0; | ||
| 12 | ARGBEGIN{ | ||
| 13 | case 'd': | ||
| 14 | dflag = 1; | ||
| 15 | break; | ||
| 16 | default: | ||
| 17 | fprint(2, "usage: wnew [-d] [label]\n"); | ||
| 18 | }ARGEND | ||
| 19 | |||
| 20 | pid = getpid(); | ||
| 21 | wdir[0] = '\0'; | ||
| 22 | if(!dflag) | ||
| 23 | getwd(wdir, sizeof wdir); | ||
| 24 | if(argc>0) | ||
| 25 | for(i=0; i<argc; i++) | ||
| 26 | snprint(wdir, sizeof wdir, "%s%c%s", wdir, i==0? '/' : '-', argv[i]); | ||
| 27 | else | ||
| 28 | snprint(wdir, sizeof wdir, "%s/-win", wdir); | ||
| 29 | |||
| 30 | if((fd = open("/dev/wnew", ORDWR)) < 0) | ||
| 31 | sysfatal("wnew: can't open /dev/wnew: %r"); | ||
| 32 | |||
| 33 | if(fprint(fd, "%d %s", pid, wdir+dflag) < 0) | ||
| 34 | sysfatal("wnew: can't create window: %r"); | ||
| 35 | |||
| 36 | if(seek(fd, 0, 0) != 0) | ||
| 37 | sysfatal("wnew: can't seek: %r"); | ||
| 38 | |||
| 39 | if((n=read(fd, wdir, sizeof wdir-1)) < 0) | ||
| 40 | sysfatal("wnew: can't read window id: %r"); | ||
| 41 | wdir[n] = '\0'; | ||
| 42 | |||
| 43 | print("%s\n", wdir); | ||
| 44 | exits(nil); | ||
| 45 | } | ||
Binary file not shown.
Binary file not shown.
| @@ -0,0 +1,123 @@ | |||
| 1 | #include <u.h> | ||
| 2 | #include <libc.h> | ||
| 3 | #include <ctype.h> | ||
| 4 | #include <bio.h> | ||
| 5 | |||
| 6 | void spout(int, char*); | ||
| 7 | |||
| 8 | Biobuf bout; | ||
| 9 | |||
| 10 | void | ||
| 11 | main(int argc, char *argv[]) | ||
| 12 | { | ||
| 13 | int i, fd; | ||
| 14 | |||
| 15 | Binit(&bout, 1, OWRITE); | ||
| 16 | if(argc == 1) | ||
| 17 | spout(0, ""); | ||
| 18 | else | ||
| 19 | for(i=1; i<argc; i++){ | ||
| 20 | fd = open(argv[i], OREAD); | ||
| 21 | if(fd < 0){ | ||
| 22 | fprint(2, "spell: can't open %s: %r\n", argv[i]); | ||
| 23 | continue; | ||
| 24 | } | ||
| 25 | spout(fd, argv[i]); | ||
| 26 | close(fd); | ||
| 27 | } | ||
| 28 | exits(nil); | ||
| 29 | } | ||
| 30 | |||
| 31 | Biobuf b; | ||
| 32 | |||
| 33 | void | ||
| 34 | spout(int fd, char *name) | ||
| 35 | { | ||
| 36 | char *s, *t, *w; | ||
| 37 | Rune r; | ||
| 38 | int inword, wordchar; | ||
| 39 | int n, wn, wid, c, m; | ||
| 40 | char buf[1024]; | ||
| 41 | |||
| 42 | Binit(&b, fd, OREAD); | ||
| 43 | n = 0; | ||
| 44 | wn = 0; | ||
| 45 | while((s = Brdline(&b, '\n')) != nil){ | ||
| 46 | if(s[0] == '.') | ||
| 47 | for(c=0; c<3 && *s>' '; c++){ | ||
| 48 | n++; | ||
| 49 | s++; | ||
| 50 | } | ||
| 51 | inword = 0; | ||
| 52 | w = s; | ||
| 53 | t = s; | ||
| 54 | do{ | ||
| 55 | c = *(uchar*)t; | ||
| 56 | if(c < Runeself) | ||
| 57 | wid = 1; | ||
| 58 | else{ | ||
| 59 | wid = chartorune(&r, t); | ||
| 60 | c = r; | ||
| 61 | } | ||
| 62 | wordchar = 0; | ||
| 63 | if(isalpha(c)) | ||
| 64 | wordchar = 1; | ||
| 65 | if(inword && !wordchar){ | ||
| 66 | if(c=='\'' && isalpha(t[1])) | ||
| 67 | goto Continue; | ||
| 68 | m = t-w; | ||
| 69 | if(m > 1){ | ||
| 70 | memmove(buf, w, m); | ||
| 71 | buf[m] = 0; | ||
| 72 | Bprint(&bout, "%s:#%d,#%d:%s\n", name, wn, n, buf); | ||
| 73 | } | ||
| 74 | inword = 0; | ||
| 75 | }else if(!inword && wordchar){ | ||
| 76 | wn = n; | ||
| 77 | w = t; | ||
| 78 | inword = 1; | ||
| 79 | } | ||
| 80 | if(c=='\\' && (isalpha(t[1]) || t[1]=='(')){ | ||
| 81 | switch(t[1]){ | ||
| 82 | case '(': | ||
| 83 | m = 4; | ||
| 84 | break; | ||
| 85 | case 'f': | ||
| 86 | if(t[2] == '(') | ||
| 87 | m = 5; | ||
| 88 | else | ||
| 89 | m = 3; | ||
| 90 | break; | ||
| 91 | case 's': | ||
| 92 | if(t[2] == '+' || t[2]=='-'){ | ||
| 93 | if(t[3] == '(') | ||
| 94 | m = 6; | ||
| 95 | else | ||
| 96 | m = 4; | ||
| 97 | }else{ | ||
| 98 | if(t[2] == '(') | ||
| 99 | m = 5; | ||
| 100 | else if(t[2]=='1' || t[2]=='2' || t[2]=='3') | ||
| 101 | m = 4; | ||
| 102 | else | ||
| 103 | m = 3; | ||
| 104 | } | ||
| 105 | break; | ||
| 106 | default: | ||
| 107 | m = 2; | ||
| 108 | } | ||
| 109 | while(m-- > 0){ | ||
| 110 | if(*t == '\n') | ||
| 111 | break; | ||
| 112 | n++; | ||
| 113 | t++; | ||
| 114 | } | ||
| 115 | continue; | ||
| 116 | } | ||
| 117 | Continue: | ||
| 118 | n++; | ||
| 119 | t += wid; | ||
| 120 | }while(c != '\n'); | ||
| 121 | } | ||
| 122 | Bterm(&b); | ||
| 123 | } | ||
Binary file not shown.
Binary file not shown.
| @@ -0,0 +1,98 @@ | |||
| 1 | typedef struct Fsevent Fsevent; | ||
| 2 | typedef struct Event Event; | ||
| 3 | typedef struct Message Message; | ||
| 4 | typedef struct Window Window; | ||
| 5 | |||
| 6 | enum | ||
| 7 | { | ||
| 8 | STACK = 8192, | ||
| 9 | NPIPEDATA = 8000, | ||
| 10 | NPIPE = NPIPEDATA+32, | ||
| 11 | /* EVENTSIZE is really 256 in acme, but we use events internally and want bigger buffers */ | ||
| 12 | EVENTSIZE = 8192, | ||
| 13 | NEVENT = 5, | ||
| 14 | }; | ||
| 15 | |||
| 16 | struct Fsevent | ||
| 17 | { | ||
| 18 | int type; | ||
| 19 | void *r; | ||
| 20 | }; | ||
| 21 | |||
| 22 | struct Event | ||
| 23 | { | ||
| 24 | int c1; | ||
| 25 | int c2; | ||
| 26 | int q0; | ||
| 27 | int q1; | ||
| 28 | int flag; | ||
| 29 | int nb; | ||
| 30 | int nr; | ||
| 31 | char b[EVENTSIZE*UTFmax+1]; | ||
| 32 | Rune r[EVENTSIZE+1]; | ||
| 33 | }; | ||
| 34 | |||
| 35 | struct Window | ||
| 36 | { | ||
| 37 | /* file descriptors */ | ||
| 38 | int ctl; | ||
| 39 | int event; | ||
| 40 | int addr; | ||
| 41 | int data; | ||
| 42 | int body; | ||
| 43 | |||
| 44 | /* event input */ | ||
| 45 | char buf[512]; | ||
| 46 | char *bufp; | ||
| 47 | int nbuf; | ||
| 48 | Event e[NEVENT]; | ||
| 49 | |||
| 50 | int id; | ||
| 51 | int open; | ||
| 52 | Channel *cevent; | ||
| 53 | }; | ||
| 54 | |||
| 55 | extern Window* newwindow(void); | ||
| 56 | extern int winopenfile(Window*, char*); | ||
| 57 | extern void wintagwrite(Window*, char*, int); | ||
| 58 | extern void winname(Window*, char*); | ||
| 59 | extern void winwriteevent(Window*, Event*); | ||
| 60 | extern int winread(Window*, uint, uint, char*); | ||
| 61 | extern int windel(Window*, int); | ||
| 62 | extern void wingetevent(Window*, Event*); | ||
| 63 | extern void wineventproc(void*); | ||
| 64 | extern void winclean(Window*); | ||
| 65 | extern int winselect(Window*, char*, int); | ||
| 66 | extern int winsetaddr(Window*, char*, int); | ||
| 67 | extern void windormant(Window*); | ||
| 68 | extern void winsetdump(Window*, char*, char*); | ||
| 69 | extern void winsetdir(Window*, char*, char*); | ||
| 70 | |||
| 71 | extern void ctlprint(int, char*, ...); | ||
| 72 | extern void* emalloc(uint); | ||
| 73 | extern char* estrdup(char*); | ||
| 74 | extern char* estrstrdup(char*, char*); | ||
| 75 | extern char* egrow(char*, char*, char*); | ||
| 76 | extern char* eappend(char*, char*, char*); | ||
| 77 | extern void error(char*, ...); | ||
| 78 | |||
| 79 | extern void startpipe(void); | ||
| 80 | extern void sendit(char*); | ||
| 81 | extern void execevent(Window *w, Event *e, int (*)(Window*, char*)); | ||
| 82 | |||
| 83 | extern void mountcons(void); | ||
| 84 | extern void fsloop(void*); | ||
| 85 | |||
| 86 | extern int newpipewin(int, char*); | ||
| 87 | extern void startpipe(void); | ||
| 88 | extern int pipecommand(Window*, char*); | ||
| 89 | extern void pipectl(void*); | ||
| 90 | |||
| 91 | #pragma varargck argpos error 1 | ||
| 92 | #pragma varargck argpos ctlprint 2 | ||
| 93 | |||
| 94 | extern char *wname; | ||
| 95 | extern char *wdir; | ||
| 96 | extern Window *win; | ||
| 97 | extern Channel *fschan, *writechan; | ||
| 98 | |||
Binary file not shown.
Binary file not shown.
| @@ -0,0 +1,190 @@ | |||
| 1 | #include <u.h> | ||
| 2 | #include <libc.h> | ||
| 3 | #include <fcall.h> | ||
| 4 | #include <thread.h> | ||
| 5 | #include <9p.h> | ||
| 6 | #include "dat.h" | ||
| 7 | |||
| 8 | Channel *fschan; | ||
| 9 | Channel *writechan; | ||
| 10 | |||
| 11 | static File *devcons, *devnew, *devwdir; | ||
| 12 | |||
| 13 | static void | ||
| 14 | fsread(Req *r) | ||
| 15 | { | ||
| 16 | Fsevent e; | ||
| 17 | |||
| 18 | if(r->fid->file == devnew){ | ||
| 19 | if(r->fid->aux==nil){ | ||
| 20 | respond(r, "phase error"); | ||
| 21 | return; | ||
| 22 | } | ||
| 23 | readstr(r, r->fid->aux); | ||
| 24 | respond(r, nil); | ||
| 25 | return; | ||
| 26 | } | ||
| 27 | |||
| 28 | if(r->fid->file == devwdir){ | ||
| 29 | readstr(r, wdir); | ||
| 30 | respond(r, nil); | ||
| 31 | return; | ||
| 32 | } | ||
| 33 | |||
| 34 | e.type = 'r'; | ||
| 35 | e.r = r; | ||
| 36 | send(fschan, &e); | ||
| 37 | } | ||
| 38 | |||
| 39 | static void | ||
| 40 | fsflush(Req *r) | ||
| 41 | { | ||
| 42 | Fsevent e; | ||
| 43 | |||
| 44 | e.type = 'f'; | ||
| 45 | e.r = r; | ||
| 46 | send(fschan, &e); | ||
| 47 | } | ||
| 48 | |||
| 49 | static void | ||
| 50 | fswrite(Req *r) | ||
| 51 | { | ||
| 52 | static Event *e[4]; | ||
| 53 | Event *ep; | ||
| 54 | int nb, wid, pid; | ||
| 55 | Rune rune; | ||
| 56 | char *s, *se, *d, *p; | ||
| 57 | static int n, partial; | ||
| 58 | |||
| 59 | if(r->fid->file == devnew){ | ||
| 60 | if(r->fid->aux){ | ||
| 61 | respond(r, "already created a window"); | ||
| 62 | return; | ||
| 63 | } | ||
| 64 | s = emalloc(r->ifcall.count+1); | ||
| 65 | memmove(s, r->ifcall.data, r->ifcall.count); | ||
| 66 | s[r->ifcall.count] = 0; | ||
| 67 | pid = strtol(s, &p, 0); | ||
| 68 | if(*p==' ') | ||
| 69 | p++; | ||
| 70 | nb = newpipewin(pid, p); | ||
| 71 | free(s); | ||
| 72 | s = emalloc(32); | ||
| 73 | sprint(s, "%lud", (ulong)nb); | ||
| 74 | r->fid->aux = s; | ||
| 75 | r->ofcall.count = r->ifcall.count; | ||
| 76 | respond(r, nil); | ||
| 77 | return; | ||
| 78 | } | ||
| 79 | |||
| 80 | if(r->fid->file == devwdir){ | ||
| 81 | s = emalloc(r->ifcall.count+1); | ||
| 82 | memmove(s, r->ifcall.data, r->ifcall.count); | ||
| 83 | s[r->ifcall.count] = 0; | ||
| 84 | if(s[0] == '#' || s[0] == '/'){ | ||
| 85 | free(wdir); | ||
| 86 | wdir = s; | ||
| 87 | } else { | ||
| 88 | wdir = eappend(wdir, "/", s); | ||
| 89 | free(s); | ||
| 90 | } | ||
| 91 | cleanname(wdir); | ||
| 92 | winsetdir(win, wdir, wname); | ||
| 93 | respond(r, nil); | ||
| 94 | return; | ||
| 95 | } | ||
| 96 | |||
| 97 | if(r->fid->file != devcons){ | ||
| 98 | respond(r, "bug in fswrite"); | ||
| 99 | return; | ||
| 100 | } | ||
| 101 | |||
| 102 | /* init buffer rings */ | ||
| 103 | if(e[0] == nil){ | ||
| 104 | for(n=0; n<nelem(e); n++){ | ||
| 105 | e[n] = emalloc(sizeof(Event)); | ||
| 106 | e[n]->c1 = 'S'; | ||
| 107 | } | ||
| 108 | } | ||
| 109 | |||
| 110 | s = r->ifcall.data; | ||
| 111 | se = s + r->ifcall.count; | ||
| 112 | |||
| 113 | while((nb = (se - s)) > 0){ | ||
| 114 | assert(partial >= 0); | ||
| 115 | if((partial+nb) > EVENTSIZE) | ||
| 116 | nb = EVENTSIZE - partial; | ||
| 117 | |||
| 118 | /* fill buffer */ | ||
| 119 | ep = e[n++ % nelem(e)]; | ||
| 120 | memmove(ep->b+partial, s, nb); | ||
| 121 | partial += nb; | ||
| 122 | s += nb; | ||
| 123 | |||
| 124 | /* check full runes, remove null bytes */ | ||
| 125 | ep->nr = ep->nb = 0; | ||
| 126 | for(d = p = ep->b; partial > 0; partial -= wid, p += wid){ | ||
| 127 | if(*p == '\0'){ | ||
| 128 | wid = 1; | ||
| 129 | continue; | ||
| 130 | } | ||
| 131 | |||
| 132 | if(!fullrune(p, partial)) | ||
| 133 | break; | ||
| 134 | |||
| 135 | wid = chartorune(&rune, p); | ||
| 136 | runetochar(d, &rune); | ||
| 137 | d += wid; | ||
| 138 | |||
| 139 | ep->nr++; | ||
| 140 | ep->nb += wid; | ||
| 141 | } | ||
| 142 | |||
| 143 | /* put partial reminder onto next buffer */ | ||
| 144 | if(partial > 0) | ||
| 145 | memmove(e[n % nelem(e)]->b, p, partial); | ||
| 146 | |||
| 147 | /* send buffer when not empty */ | ||
| 148 | if(ep->nb > 0){ | ||
| 149 | ep->b[ep->nb] = '\0'; | ||
| 150 | sendp(win->cevent, ep); | ||
| 151 | recvp(writechan); | ||
| 152 | } | ||
| 153 | } | ||
| 154 | |||
| 155 | r->ofcall.count = r->ifcall.count; | ||
| 156 | respond(r, nil); | ||
| 157 | } | ||
| 158 | |||
| 159 | void | ||
| 160 | fsdestroyfid(Fid *fid) | ||
| 161 | { | ||
| 162 | if(fid->aux) | ||
| 163 | free(fid->aux); | ||
| 164 | } | ||
| 165 | |||
| 166 | Srv fs = { | ||
| 167 | .read= fsread, | ||
| 168 | .write= fswrite, | ||
| 169 | .flush= fsflush, | ||
| 170 | .destroyfid= fsdestroyfid, | ||
| 171 | .leavefdsopen= 1, | ||
| 172 | }; | ||
| 173 | |||
| 174 | void | ||
| 175 | mountcons(void) | ||
| 176 | { | ||
| 177 | fschan = chancreate(sizeof(Fsevent), 0); | ||
| 178 | writechan = chancreate(sizeof(void*), 0); | ||
| 179 | fs.tree = alloctree("win", "win", DMDIR|0555, nil); | ||
| 180 | devcons = createfile(fs.tree->root, "cons", "win", 0666, nil); | ||
| 181 | if(devcons == nil) | ||
| 182 | sysfatal("creating /dev/cons: %r"); | ||
| 183 | devnew = createfile(fs.tree->root, "wnew", "win", 0666, nil); | ||
| 184 | if(devnew == nil) | ||
| 185 | sysfatal("creating /dev/wnew: %r"); | ||
| 186 | devwdir = createfile(fs.tree->root, "wdir", "win", 0666, nil); | ||
| 187 | if(devwdir == nil) | ||
| 188 | sysfatal("creating /dev/wdir: %r"); | ||
| 189 | threadpostmountsrv(&fs, nil, "/dev", MBEFORE); | ||
| 190 | } | ||
Binary file not shown.
Binary file not shown.
| @@ -0,0 +1,643 @@ | |||
| 1 | #include <u.h> | ||
| 2 | #include <libc.h> | ||
| 3 | #include <bio.h> | ||
| 4 | #include <thread.h> | ||
| 5 | #include <fcall.h> | ||
| 6 | #include <9p.h> | ||
| 7 | #include <ctype.h> | ||
| 8 | #include "dat.h" | ||
| 9 | |||
| 10 | void mainctl(void*); | ||
| 11 | void startcmd(char *[], int*); | ||
| 12 | void stdout2body(void*); | ||
| 13 | |||
| 14 | int debug; | ||
| 15 | int notepg; | ||
| 16 | int eraseinput; | ||
| 17 | int dirty = 0; | ||
| 18 | |||
| 19 | char *wname; | ||
| 20 | char *wdir; | ||
| 21 | Window *win; /* the main window */ | ||
| 22 | |||
| 23 | void | ||
| 24 | usage(void) | ||
| 25 | { | ||
| 26 | fprint(2, "usage: win [command]\n"); | ||
| 27 | threadexitsall("usage"); | ||
| 28 | } | ||
| 29 | |||
| 30 | void | ||
| 31 | threadmain(int argc, char *argv[]) | ||
| 32 | { | ||
| 33 | int i, j; | ||
| 34 | char buf[1024], **av; | ||
| 35 | |||
| 36 | quotefmtinstall(); | ||
| 37 | rfork(RFNAMEG); | ||
| 38 | ARGBEGIN{ | ||
| 39 | case 'd': | ||
| 40 | debug = 1; | ||
| 41 | chatty9p++; | ||
| 42 | break; | ||
| 43 | case 'e': | ||
| 44 | eraseinput = 1; | ||
| 45 | break; | ||
| 46 | case 'D': | ||
| 47 | {extern int _threaddebuglevel; | ||
| 48 | _threaddebuglevel = 1<<20; | ||
| 49 | } | ||
| 50 | }ARGEND | ||
| 51 | |||
| 52 | if(argc == 0){ | ||
| 53 | av = emalloc(3*sizeof(char*)); | ||
| 54 | av[0] = "rc"; | ||
| 55 | av[1] = "-i"; | ||
| 56 | }else{ | ||
| 57 | av = argv; | ||
| 58 | } | ||
| 59 | wname = utfrrune(av[0], '/'); | ||
| 60 | if(wname) | ||
| 61 | wname++; | ||
| 62 | else | ||
| 63 | wname = av[0]; | ||
| 64 | if(getwd(buf, sizeof buf) == 0) | ||
| 65 | wdir = "/"; | ||
| 66 | else | ||
| 67 | wdir = buf; | ||
| 68 | wdir = estrdup(wdir); | ||
| 69 | win = newwindow(); | ||
| 70 | snprint(buf, sizeof buf, "%d", win->id); | ||
| 71 | putenv("winid", buf); | ||
| 72 | winsetdir(win, wdir, wname); | ||
| 73 | wintagwrite(win, "Send Noscroll", 5+8); | ||
| 74 | threadcreate(mainctl, win, STACK); | ||
| 75 | mountcons(); | ||
| 76 | threadcreate(fsloop, nil, STACK); | ||
| 77 | startpipe(); | ||
| 78 | startcmd(av, ¬epg); | ||
| 79 | |||
| 80 | strcpy(buf, "win"); | ||
| 81 | j = 3; | ||
| 82 | for(i=0; i<argc && j+1+strlen(argv[i])+1<sizeof buf; i++){ | ||
| 83 | strcpy(buf+j, " "); | ||
| 84 | strcpy(buf+j+1, argv[i]); | ||
| 85 | j += 1+strlen(argv[i]); | ||
| 86 | } | ||
| 87 | |||
| 88 | ctlprint(win->ctl, "scroll"); | ||
| 89 | winsetdump(win, wdir, buf); | ||
| 90 | } | ||
| 91 | |||
| 92 | int | ||
| 93 | EQUAL(char *s, char *t) | ||
| 94 | { | ||
| 95 | while(tolower(*s) == tolower(*t++)) | ||
| 96 | if(*s++ == '\0') | ||
| 97 | return 1; | ||
| 98 | return 0; | ||
| 99 | } | ||
| 100 | |||
| 101 | int | ||
| 102 | command(Window *w, char *s) | ||
| 103 | { | ||
| 104 | while(*s==' ' || *s=='\t' || *s=='\n') | ||
| 105 | s++; | ||
| 106 | if(strcmp(s, "Delete")==0 || strcmp(s, "Del")==0){ | ||
| 107 | windel(w, 1); | ||
| 108 | threadexitsall(nil); | ||
| 109 | return 1; | ||
| 110 | } | ||
| 111 | if(EQUAL(s, "scroll")){ | ||
| 112 | ctlprint(w->ctl, "scroll\nshow"); | ||
| 113 | return 1; | ||
| 114 | } | ||
| 115 | if(EQUAL(s, "noscroll")){ | ||
| 116 | ctlprint(w->ctl, "noscroll"); | ||
| 117 | return 1; | ||
| 118 | } | ||
| 119 | return 0; | ||
| 120 | } | ||
| 121 | |||
| 122 | static long | ||
| 123 | utfncpy(char *to, char *from, int n) | ||
| 124 | { | ||
| 125 | char *end, *e; | ||
| 126 | |||
| 127 | e = to+n; | ||
| 128 | if(to >= e) | ||
| 129 | return 0; | ||
| 130 | end = memccpy(to, from, '\0', e - to); | ||
| 131 | if(end == nil){ | ||
| 132 | end = e; | ||
| 133 | if(end[-1]&0x80){ | ||
| 134 | if(end-2>=to && (end[-2]&0xE0)==0xC0) | ||
| 135 | return end-to; | ||
| 136 | if(end-3>=to && (end[-3]&0xF0)==0xE0) | ||
| 137 | return end-to; | ||
| 138 | while(end>to && (*--end&0xC0)==0x80) | ||
| 139 | ; | ||
| 140 | } | ||
| 141 | }else | ||
| 142 | end--; | ||
| 143 | return end - to; | ||
| 144 | } | ||
| 145 | |||
| 146 | /* sendinput and fsloop run in the same proc (can't interrupt each other). */ | ||
| 147 | static Req *q; | ||
| 148 | static Req **eq; | ||
| 149 | static int | ||
| 150 | __sendinput(Window *w, ulong q0, ulong q1) | ||
| 151 | { | ||
| 152 | char *s, *t; | ||
| 153 | int n, nb, eofchar; | ||
| 154 | static int partial; | ||
| 155 | static char tmp[UTFmax]; | ||
| 156 | Req *r; | ||
| 157 | Rune rune; | ||
| 158 | |||
| 159 | if(!q) | ||
| 160 | return 0; | ||
| 161 | |||
| 162 | r = q; | ||
| 163 | n = 0; | ||
| 164 | if(partial){ | ||
| 165 | Partial: | ||
| 166 | nb = partial; | ||
| 167 | if(nb > r->ifcall.count) | ||
| 168 | nb = r->ifcall.count; | ||
| 169 | memmove(r->ofcall.data, tmp, nb); | ||
| 170 | if(nb!=partial) | ||
| 171 | memmove(tmp, tmp+nb, partial-nb); | ||
| 172 | partial -= nb; | ||
| 173 | q = r->aux; | ||
| 174 | if(q == nil) | ||
| 175 | eq = &q; | ||
| 176 | r->aux = nil; | ||
| 177 | r->ofcall.count = nb; | ||
| 178 | if(debug) | ||
| 179 | fprint(2, "satisfy read with partial\n"); | ||
| 180 | respond(r, nil); | ||
| 181 | return n; | ||
| 182 | } | ||
| 183 | if(q0==q1) | ||
| 184 | return 0; | ||
| 185 | s = emalloc((q1-q0)*UTFmax+1); | ||
| 186 | n = winread(w, q0, q1, s); | ||
| 187 | s[n] = '\0'; | ||
| 188 | t = strpbrk(s, "\n\004"); | ||
| 189 | if(t == nil){ | ||
| 190 | free(s); | ||
| 191 | return 0; | ||
| 192 | } | ||
| 193 | r = q; | ||
| 194 | eofchar = 0; | ||
| 195 | if(*t == '\004'){ | ||
| 196 | eofchar = 1; | ||
| 197 | *t = '\0'; | ||
| 198 | }else | ||
| 199 | *++t = '\0'; | ||
| 200 | nb = utfncpy((char*)r->ofcall.data, s, r->ifcall.count); | ||
| 201 | if(nb==0 && s<t && r->ifcall.count > 0){ | ||
| 202 | partial = utfncpy(tmp, s, UTFmax); | ||
| 203 | assert(partial > 0); | ||
| 204 | chartorune(&rune, tmp); | ||
| 205 | partial = runelen(rune); | ||
| 206 | free(s); | ||
| 207 | n = 1; | ||
| 208 | goto Partial; | ||
| 209 | } | ||
| 210 | n = utfnlen(r->ofcall.data, nb); | ||
| 211 | if(nb==strlen(s) && eofchar) | ||
| 212 | n++; | ||
| 213 | r->ofcall.count = nb; | ||
| 214 | q = r->aux; | ||
| 215 | if(q == nil) | ||
| 216 | eq = &q; | ||
| 217 | r->aux = nil; | ||
| 218 | if(debug) | ||
| 219 | fprint(2, "read returns %lud-%lud: %.*q\n", q0, q0+n, n, r->ofcall.data); | ||
| 220 | respond(r, nil); | ||
| 221 | return n; | ||
| 222 | } | ||
| 223 | |||
| 224 | static int | ||
| 225 | _sendinput(Window *w, ulong q0, ulong *q1) | ||
| 226 | { | ||
| 227 | char buf[32]; | ||
| 228 | int n; | ||
| 229 | |||
| 230 | n = __sendinput(w, q0, *q1); | ||
| 231 | if(!n || !eraseinput) | ||
| 232 | return n; | ||
| 233 | /* erase q0 to q0+n */ | ||
| 234 | sprint(buf, "#%lud,#%lud", q0, q0+n); | ||
| 235 | winsetaddr(w, buf, 0); | ||
| 236 | write(w->data, buf, 0); | ||
| 237 | *q1 -= n; | ||
| 238 | return 0; | ||
| 239 | } | ||
| 240 | |||
| 241 | int | ||
| 242 | sendinput(Window *w, ulong q0, ulong *q1) | ||
| 243 | { | ||
| 244 | ulong n; | ||
| 245 | Req *oq; | ||
| 246 | |||
| 247 | n = 0; | ||
| 248 | do { | ||
| 249 | oq = q; | ||
| 250 | n += _sendinput(w, q0+n, q1); | ||
| 251 | } while(q != oq); | ||
| 252 | return n; | ||
| 253 | } | ||
| 254 | |||
| 255 | Event esendinput; | ||
| 256 | void | ||
| 257 | fsloop(void*) | ||
| 258 | { | ||
| 259 | Fsevent e; | ||
| 260 | Req **l, *r; | ||
| 261 | |||
| 262 | eq = &q; | ||
| 263 | memset(&esendinput, 0, sizeof esendinput); | ||
| 264 | esendinput.c1 = 'C'; | ||
| 265 | for(;;){ | ||
| 266 | while(recv(fschan, &e) == -1) | ||
| 267 | ; | ||
| 268 | r = e.r; | ||
| 269 | switch(e.type){ | ||
| 270 | case 'r': | ||
| 271 | *eq = r; | ||
| 272 | r->aux = nil; | ||
| 273 | eq = &r->aux; | ||
| 274 | /* call sendinput with hostpt and endpt */ | ||
| 275 | sendp(win->cevent, &esendinput); | ||
| 276 | break; | ||
| 277 | case 'f': | ||
| 278 | for(l=&q; *l; l=&(*l)->aux){ | ||
| 279 | if(*l == r->oldreq){ | ||
| 280 | *l = (*l)->aux; | ||
| 281 | if(*l == nil) | ||
| 282 | eq = l; | ||
| 283 | respond(r->oldreq, "interrupted"); | ||
| 284 | break; | ||
| 285 | } | ||
| 286 | } | ||
| 287 | respond(r, nil); | ||
| 288 | break; | ||
| 289 | } | ||
| 290 | } | ||
| 291 | } | ||
| 292 | |||
| 293 | void | ||
| 294 | sendit(char *s) | ||
| 295 | { | ||
| 296 | // char tmp[32]; | ||
| 297 | |||
| 298 | write(win->body, s, strlen(s)); | ||
| 299 | /* | ||
| 300 | * RSC: The problem here is that other procs can call sendit, | ||
| 301 | * so we lose our single-threadedness if we call sendinput. | ||
| 302 | * In fact, we don't even have the right queue memory, | ||
| 303 | * I think that we'll get a write event from the body write above, | ||
| 304 | * and we can do the sendinput then, from our single thread. | ||
| 305 | * | ||
| 306 | * I still need to figure out how to test this assertion for | ||
| 307 | * programs that use /srv/win* | ||
| 308 | * | ||
| 309 | winselect(win, "$", 0); | ||
| 310 | seek(win->addr, 0UL, 0); | ||
| 311 | if(read(win->addr, tmp, 2*12) == 2*12) | ||
| 312 | hostpt += sendinput(win, hostpt, atol(tmp), ); | ||
| 313 | */ | ||
| 314 | } | ||
| 315 | |||
| 316 | void | ||
| 317 | execevent(Window *w, Event *e, int (*command)(Window*, char*)) | ||
| 318 | { | ||
| 319 | Event *ea, *e2; | ||
| 320 | int n, na, len, needfree; | ||
| 321 | char *s, *t; | ||
| 322 | |||
| 323 | ea = nil; | ||
| 324 | e2 = nil; | ||
| 325 | if(e->flag & 2) | ||
| 326 | e2 = recvp(w->cevent); | ||
| 327 | if(e->flag & 8){ | ||
| 328 | ea = recvp(w->cevent); | ||
| 329 | na = ea->nb; | ||
| 330 | recvp(w->cevent); | ||
| 331 | }else | ||
| 332 | na = 0; | ||
| 333 | |||
| 334 | needfree = 0; | ||
| 335 | s = e->b; | ||
| 336 | if(e->nb==0 && (e->flag&2)){ | ||
| 337 | s = e2->b; | ||
| 338 | e->q0 = e2->q0; | ||
| 339 | e->q1 = e2->q1; | ||
| 340 | e->nb = e2->nb; | ||
| 341 | } | ||
| 342 | if(e->nb==0 && e->q0<e->q1){ | ||
| 343 | /* fetch data from window */ | ||
| 344 | s = emalloc((e->q1-e->q0)*UTFmax+2); | ||
| 345 | n = winread(w, e->q0, e->q1, s); | ||
| 346 | s[n] = '\0'; | ||
| 347 | needfree = 1; | ||
| 348 | }else | ||
| 349 | if(na){ | ||
| 350 | t = emalloc(strlen(s)+1+na+2); | ||
| 351 | sprint(t, "%s %s", s, ea->b); | ||
| 352 | if(needfree) | ||
| 353 | free(s); | ||
| 354 | s = t; | ||
| 355 | needfree = 1; | ||
| 356 | } | ||
| 357 | |||
| 358 | /* if it's a known command, do it */ | ||
| 359 | /* if it's a long message, it can't be for us anyway */ | ||
| 360 | if(!command(w, s) && s[0]!='\0'){ /* send it as typed text */ | ||
| 361 | /* if it's a built-in from the tag, send it back */ | ||
| 362 | if(e->flag & 1) | ||
| 363 | fprint(w->event, "%c%c%d %d\n", e->c1, e->c2, e->q0, e->q1); | ||
| 364 | else{ /* send text to main window */ | ||
| 365 | len = strlen(s); | ||
| 366 | if(len>0 && s[len-1]!='\n' && s[len-1]!='\004'){ | ||
| 367 | if(!needfree){ | ||
| 368 | /* if(needfree), we left room for a newline before */ | ||
| 369 | t = emalloc(len+2); | ||
| 370 | strcpy(t, s); | ||
| 371 | s = t; | ||
| 372 | needfree = 1; | ||
| 373 | } | ||
| 374 | s[len++] = '\n'; | ||
| 375 | s[len] = '\0'; | ||
| 376 | } | ||
| 377 | sendit(s); | ||
| 378 | } | ||
| 379 | } | ||
| 380 | if(needfree) | ||
| 381 | free(s); | ||
| 382 | } | ||
| 383 | |||
| 384 | int | ||
| 385 | hasboundary(Rune *r, int nr) | ||
| 386 | { | ||
| 387 | int i; | ||
| 388 | |||
| 389 | for(i=0; i<nr; i++) | ||
| 390 | if(r[i]=='\n' || r[i]=='\004') | ||
| 391 | return 1; | ||
| 392 | return 0; | ||
| 393 | } | ||
| 394 | |||
| 395 | void | ||
| 396 | mainctl(void *v) | ||
| 397 | { | ||
| 398 | Window *w; | ||
| 399 | Event *e; | ||
| 400 | int delta, pendingS, pendingK; | ||
| 401 | ulong hostpt, endpt; | ||
| 402 | char tmp[32]; | ||
| 403 | |||
| 404 | w = v; | ||
| 405 | proccreate(wineventproc, w, STACK); | ||
| 406 | |||
| 407 | hostpt = 0; | ||
| 408 | endpt = 0; | ||
| 409 | winsetaddr(w, "0", 0); | ||
| 410 | pendingS = 0; | ||
| 411 | pendingK = 0; | ||
| 412 | for(;;){ | ||
| 413 | if(debug) | ||
| 414 | fprint(2, "input range %lud-%lud\n", hostpt, endpt); | ||
| 415 | e = recvp(w->cevent); | ||
| 416 | if(debug) | ||
| 417 | fprint(2, "msg: %C %C %d %d %d %d %q\n", | ||
| 418 | e->c1 ? e->c1 : ' ', e->c2 ? e->c2 : ' ', e->q0, e->q1, e->flag, e->nb, e->b); | ||
| 419 | switch(e->c1){ | ||
| 420 | default: | ||
| 421 | Unknown: | ||
| 422 | fprint(2, "unknown message %c%c\n", e->c1, e->c2); | ||
| 423 | break; | ||
| 424 | |||
| 425 | case 'C': /* input needed for /dev/cons */ | ||
| 426 | if(pendingS) | ||
| 427 | pendingK = 1; | ||
| 428 | else | ||
| 429 | hostpt += sendinput(w, hostpt, &endpt); | ||
| 430 | break; | ||
| 431 | |||
| 432 | case 'S': /* output to stdout */ | ||
| 433 | sprint(tmp, "#%lud", hostpt); | ||
| 434 | winsetaddr(w, tmp, 0); | ||
| 435 | write(w->data, e->b, e->nb); | ||
| 436 | pendingS += e->nr; | ||
| 437 | break; | ||
| 438 | |||
| 439 | case 'E': /* write to tag or body; body happens due to sendit */ | ||
| 440 | delta = e->q1-e->q0; | ||
| 441 | if(e->c2=='I'){ | ||
| 442 | endpt += delta; | ||
| 443 | if(e->q0 < hostpt) | ||
| 444 | hostpt += delta; | ||
| 445 | else | ||
| 446 | hostpt += sendinput(w, hostpt, &endpt); | ||
| 447 | break; | ||
| 448 | } | ||
| 449 | if(!islower(e->c2)) | ||
| 450 | fprint(2, "win msg: %C %C %d %d %d %d %q\n", | ||
| 451 | e->c1, e->c2, e->q0, e->q1, e->flag, e->nb, e->b); | ||
| 452 | break; | ||
| 453 | |||
| 454 | case 'F': /* generated by our actions (specifically case 'S' above) */ | ||
| 455 | delta = e->q1-e->q0; | ||
| 456 | if(e->c2=='D'){ | ||
| 457 | /* we know about the delete by _sendinput */ | ||
| 458 | break; | ||
| 459 | } | ||
| 460 | if(e->c2=='I'){ | ||
| 461 | pendingS -= e->q1 - e->q0; | ||
| 462 | if(pendingS < 0) | ||
| 463 | fprint(2, "win: pendingS = %d\n", pendingS); | ||
| 464 | if(e->q0 != hostpt) | ||
| 465 | fprint(2, "win: insert at %d expected %lud\n", e->q0, hostpt); | ||
| 466 | endpt += delta; | ||
| 467 | hostpt += delta; | ||
| 468 | sendp(writechan, nil); | ||
| 469 | if(pendingS == 0 && pendingK){ | ||
| 470 | pendingK = 0; | ||
| 471 | hostpt += sendinput(w, hostpt, &endpt); | ||
| 472 | } | ||
| 473 | break; | ||
| 474 | } | ||
| 475 | if(!islower(e->c2)) | ||
| 476 | fprint(2, "win msg: %C %C %d %d %d %d %q\n", | ||
| 477 | e->c1, e->c2, e->q0, e->q1, e->flag, e->nb, e->b); | ||
| 478 | break; | ||
| 479 | |||
| 480 | case 'K': | ||
| 481 | delta = e->q1-e->q0; | ||
| 482 | switch(e->c2){ | ||
| 483 | case 'D': | ||
| 484 | endpt -= delta; | ||
| 485 | if(e->q1 < hostpt) | ||
| 486 | hostpt -= delta; | ||
| 487 | else if(e->q0 < hostpt) | ||
| 488 | hostpt = e->q0; | ||
| 489 | break; | ||
| 490 | case 'I': | ||
| 491 | delta = e->q1 - e->q0; | ||
| 492 | endpt += delta; | ||
| 493 | if(endpt < e->q1) /* just in case */ | ||
| 494 | endpt = e->q1; | ||
| 495 | if(e->q0 < hostpt) | ||
| 496 | hostpt += delta; | ||
| 497 | if(e->nr>0 && e->r[e->nr-1]==0x7F){ | ||
| 498 | write(notepg, "interrupt", 9); | ||
| 499 | hostpt = endpt; | ||
| 500 | break; | ||
| 501 | } | ||
| 502 | if(e->q0 >= hostpt | ||
| 503 | && hasboundary(e->r, e->nr)){ | ||
| 504 | /* | ||
| 505 | * If we are between the S message (which | ||
| 506 | * we processed by inserting text in the | ||
| 507 | * window) and the F message notifying us | ||
| 508 | * that the text has been inserted, then our | ||
| 509 | * impression of the hostpt and acme's | ||
| 510 | * may be different. This could be seen if you | ||
| 511 | * hit enter a bunch of times in a con | ||
| 512 | * session. To work around the unreliability, | ||
| 513 | * only send input if we don't have an S pending. | ||
| 514 | * The same race occurs between when a character | ||
| 515 | * is typed and when we get notice of it, but | ||
| 516 | * since characters tend to be typed at the end | ||
| 517 | * of the buffer, we don't run into it. There's | ||
| 518 | * no workaround possible for this typing race, | ||
| 519 | * since we can't tell when the user has typed | ||
| 520 | * something but we just haven't been notified. | ||
| 521 | */ | ||
| 522 | if(pendingS) | ||
| 523 | pendingK = 1; | ||
| 524 | else | ||
| 525 | hostpt += sendinput(w, hostpt, &endpt); | ||
| 526 | } | ||
| 527 | break; | ||
| 528 | } | ||
| 529 | break; | ||
| 530 | |||
| 531 | case 'M': /* mouse */ | ||
| 532 | delta = e->q1-e->q0; | ||
| 533 | switch(e->c2){ | ||
| 534 | case 'x': | ||
| 535 | case 'X': | ||
| 536 | execevent(w, e, command); | ||
| 537 | break; | ||
| 538 | |||
| 539 | case 'l': /* reflect all searches back to acme */ | ||
| 540 | case 'L': | ||
| 541 | if(e->flag & 2) | ||
| 542 | recvp(w->cevent); | ||
| 543 | winwriteevent(w, e); | ||
| 544 | break; | ||
| 545 | |||
| 546 | case 'I': | ||
| 547 | endpt += delta; | ||
| 548 | if(e->q0 < hostpt) | ||
| 549 | hostpt += delta; | ||
| 550 | else | ||
| 551 | hostpt += sendinput(w, hostpt, &endpt); | ||
| 552 | break; | ||
| 553 | |||
| 554 | case 'D': | ||
| 555 | endpt -= delta; | ||
| 556 | if(e->q1 < hostpt) | ||
| 557 | hostpt -= delta; | ||
| 558 | else if(e->q0 < hostpt) | ||
| 559 | hostpt = e->q0; | ||
| 560 | break; | ||
| 561 | case 'd': /* modify away; we don't care */ | ||
| 562 | case 'i': | ||
| 563 | break; | ||
| 564 | |||
| 565 | default: | ||
| 566 | goto Unknown; | ||
| 567 | } | ||
| 568 | } | ||
| 569 | } | ||
| 570 | } | ||
| 571 | |||
| 572 | enum | ||
| 573 | { | ||
| 574 | NARGS = 100, | ||
| 575 | NARGCHAR = 8*1024, | ||
| 576 | EXECSTACK = STACK+(NARGS+1)*sizeof(char*)+NARGCHAR | ||
| 577 | }; | ||
| 578 | |||
| 579 | struct Exec | ||
| 580 | { | ||
| 581 | char **argv; | ||
| 582 | Channel *cpid; | ||
| 583 | }; | ||
| 584 | |||
| 585 | int | ||
| 586 | lookinbin(char *s) | ||
| 587 | { | ||
| 588 | if(s[0] == '/') | ||
| 589 | return 0; | ||
| 590 | if(s[0]=='.' && s[1]=='/') | ||
| 591 | return 0; | ||
| 592 | if(s[0]=='.' && s[1]=='.' && s[2]=='/') | ||
| 593 | return 0; | ||
| 594 | return 1; | ||
| 595 | } | ||
| 596 | |||
| 597 | /* adapted from mail. not entirely free of details from that environment */ | ||
| 598 | void | ||
| 599 | execproc(void *v) | ||
| 600 | { | ||
| 601 | struct Exec *e; | ||
| 602 | char *cmd, **av; | ||
| 603 | Channel *cpid; | ||
| 604 | |||
| 605 | e = v; | ||
| 606 | rfork(RFCFDG|RFNOTEG); | ||
| 607 | av = e->argv; | ||
| 608 | close(0); | ||
| 609 | open("/dev/cons", OREAD); | ||
| 610 | close(1); | ||
| 611 | open("/dev/cons", OWRITE); | ||
| 612 | dup(1, 2); | ||
| 613 | cpid = e->cpid; | ||
| 614 | free(e); | ||
| 615 | procexec(cpid, av[0], av); | ||
| 616 | if(lookinbin(av[0])){ | ||
| 617 | cmd = estrstrdup("/bin/", av[0]); | ||
| 618 | procexec(cpid, cmd, av); | ||
| 619 | } | ||
| 620 | error("can't exec %s: %r", av[0]); | ||
| 621 | } | ||
| 622 | |||
| 623 | void | ||
| 624 | startcmd(char *argv[], int *notepg) | ||
| 625 | { | ||
| 626 | struct Exec *e; | ||
| 627 | Channel *cpid; | ||
| 628 | char buf[64]; | ||
| 629 | int pid; | ||
| 630 | |||
| 631 | e = emalloc(sizeof(struct Exec)); | ||
| 632 | e->argv = argv; | ||
| 633 | cpid = chancreate(sizeof(ulong), 0); | ||
| 634 | e->cpid = cpid; | ||
| 635 | sprint(buf, "/mnt/wsys/%d", win->id); | ||
| 636 | bind(buf, "/dev/acme", MREPL); | ||
| 637 | proccreate(execproc, e, EXECSTACK); | ||
| 638 | do | ||
| 639 | pid = recvul(cpid); | ||
| 640 | while(pid == -1); | ||
| 641 | sprint(buf, "/proc/%d/notepg", pid); | ||
| 642 | *notepg = open(buf, OWRITE); | ||
| 643 | } | ||
| @@ -0,0 +1,25 @@ | |||
| 1 | </$objtype/mkfile | ||
| 2 | |||
| 3 | TARG=win | ||
| 4 | OFILES=\ | ||
| 5 | fs.$O\ | ||
| 6 | main.$O\ | ||
| 7 | pipe.$O\ | ||
| 8 | util.$O\ | ||
| 9 | win.$O | ||
| 10 | |||
| 11 | HFILES=dat.h | ||
| 12 | LIB=/$objtype/lib/lib9p.a | ||
| 13 | |||
| 14 | BIN=/acme/bin/$objtype | ||
| 15 | </sys/src/cmd/mkone | ||
| 16 | |||
| 17 | UPDATE=\ | ||
| 18 | mkfile\ | ||
| 19 | $HFILES\ | ||
| 20 | ${OFILES:%.$O=%.c}\ | ||
| 21 | ${TARG:%=/acme/bin/$objtype/%}\ | ||
| 22 | |||
| 23 | syms:V: | ||
| 24 | 8c -a main.c >syms | ||
| 25 | 8c -aa util.c win.c >>syms | ||
Binary file not shown.
Binary file not shown.
| @@ -0,0 +1,175 @@ | |||
| 1 | #include <u.h> | ||
| 2 | #include <libc.h> | ||
| 3 | #include <fcall.h> | ||
| 4 | #include <thread.h> | ||
| 5 | #include <9p.h> | ||
| 6 | #include "dat.h" | ||
| 7 | |||
| 8 | typedef struct Wpid Wpid; | ||
| 9 | struct Wpid | ||
| 10 | { | ||
| 11 | int pid; | ||
| 12 | Window *w; | ||
| 13 | Wpid *next; | ||
| 14 | }; | ||
| 15 | |||
| 16 | void pipectl(void*); | ||
| 17 | |||
| 18 | int pipefd; | ||
| 19 | Wpid *wpid; | ||
| 20 | int snarffd; | ||
| 21 | Channel *newpipechan; | ||
| 22 | |||
| 23 | int | ||
| 24 | newpipewin(int pid, char *p) | ||
| 25 | { | ||
| 26 | int id; | ||
| 27 | Window *w; | ||
| 28 | Wpid *wp; | ||
| 29 | |||
| 30 | w = newwindow(); | ||
| 31 | winname(w, p); | ||
| 32 | wintagwrite(w, "Send ", 5); | ||
| 33 | wp = emalloc(sizeof(Wpid)); | ||
| 34 | wp->pid = pid; | ||
| 35 | wp->w = w; | ||
| 36 | wp->next = wpid; /* BUG: this happens in fsread proc (we don't use wpid, so it's okay) */ | ||
| 37 | wpid = wp; | ||
| 38 | id = w->id; | ||
| 39 | sendp(newpipechan, w); | ||
| 40 | return id; | ||
| 41 | } | ||
| 42 | |||
| 43 | int | ||
| 44 | pipecommand(Window *w, char *s) | ||
| 45 | { | ||
| 46 | ulong q0, q1; | ||
| 47 | char tmp[32], *t; | ||
| 48 | int n, k; | ||
| 49 | |||
| 50 | while(*s==' ' || *s=='\t' || *s=='\n') | ||
| 51 | s++; | ||
| 52 | if(strcmp(s, "Delete")==0){ | ||
| 53 | windel(w, 1); | ||
| 54 | threadexits(nil); | ||
| 55 | return 1; | ||
| 56 | } | ||
| 57 | if(strcmp(s, "Del")==0){ | ||
| 58 | if(windel(w, 0)) | ||
| 59 | threadexits(nil); | ||
| 60 | return 1; | ||
| 61 | } | ||
| 62 | if(strcmp(s, "Send") == 0){ | ||
| 63 | if(w->addr < 0) | ||
| 64 | w->addr = winopenfile(w, "addr"); | ||
| 65 | ctlprint(w->ctl, "addr=dot\n"); | ||
| 66 | seek(w->addr, 0UL, 0); | ||
| 67 | if(read(w->addr, tmp, 2*12) == 2*12){ | ||
| 68 | q0 = atol(tmp+0*12); | ||
| 69 | q1 = atol(tmp+1*12); | ||
| 70 | if(q0 == q1){ | ||
| 71 | t = nil; | ||
| 72 | k = 0; | ||
| 73 | if(snarffd > 0){ | ||
| 74 | seek(0, snarffd, 0); | ||
| 75 | for(;;){ | ||
| 76 | t = realloc(t, k+8192+2); | ||
| 77 | if(t == nil) | ||
| 78 | error("alloc failed: %r\n"); | ||
| 79 | n = read(snarffd, t+k, 8192); | ||
| 80 | if(n <= 0) | ||
| 81 | break; | ||
| 82 | k += n; | ||
| 83 | } | ||
| 84 | t[k] = 0; | ||
| 85 | } | ||
| 86 | }else{ | ||
| 87 | t = emalloc((q1-q0)*UTFmax+2); | ||
| 88 | winread(w, q0, q1, t); | ||
| 89 | k = strlen(t); | ||
| 90 | } | ||
| 91 | if(t!=nil && t[0]!='\0'){ | ||
| 92 | if(t[k-1]!='\n' && t[k-1]!='\004'){ | ||
| 93 | t[k++] = '\n'; | ||
| 94 | t[k] = '\0'; | ||
| 95 | } | ||
| 96 | sendit(t); | ||
| 97 | } | ||
| 98 | free(t); | ||
| 99 | } | ||
| 100 | return 1; | ||
| 101 | } | ||
| 102 | return 0; | ||
| 103 | } | ||
| 104 | |||
| 105 | void | ||
| 106 | pipectl(void *v) | ||
| 107 | { | ||
| 108 | Window *w; | ||
| 109 | Event *e; | ||
| 110 | |||
| 111 | w = v; | ||
| 112 | proccreate(wineventproc, w, STACK); | ||
| 113 | |||
| 114 | windormant(w); | ||
| 115 | winsetaddr(w, "0", 0); | ||
| 116 | for(;;){ | ||
| 117 | e = recvp(w->cevent); | ||
| 118 | switch(e->c1){ | ||
| 119 | default: | ||
| 120 | Unknown: | ||
| 121 | fprint(2, "unknown message %c%c\n", e->c1, e->c2); | ||
| 122 | break; | ||
| 123 | |||
| 124 | case 'E': /* write to body; can't affect us */ | ||
| 125 | break; | ||
| 126 | |||
| 127 | case 'F': /* generated by our actions; ignore */ | ||
| 128 | break; | ||
| 129 | |||
| 130 | case 'K': /* ignore */ | ||
| 131 | break; | ||
| 132 | |||
| 133 | case 'M': | ||
| 134 | switch(e->c2){ | ||
| 135 | case 'x': | ||
| 136 | case 'X': | ||
| 137 | execevent(w, e, pipecommand); | ||
| 138 | break; | ||
| 139 | |||
| 140 | case 'l': /* reflect all searches back to acme */ | ||
| 141 | case 'L': | ||
| 142 | if(e->flag & 2) | ||
| 143 | recvp(w->cevent); | ||
| 144 | winwriteevent(w, e); | ||
| 145 | break; | ||
| 146 | |||
| 147 | case 'I': /* modify away; we don't care */ | ||
| 148 | case 'i': | ||
| 149 | case 'D': | ||
| 150 | case 'd': | ||
| 151 | break; | ||
| 152 | |||
| 153 | default: | ||
| 154 | goto Unknown; | ||
| 155 | } | ||
| 156 | } | ||
| 157 | } | ||
| 158 | } | ||
| 159 | |||
| 160 | void | ||
| 161 | newpipethread(void*) | ||
| 162 | { | ||
| 163 | Window *w; | ||
| 164 | |||
| 165 | while(w = recvp(newpipechan)) | ||
| 166 | threadcreate(pipectl, w, STACK); | ||
| 167 | } | ||
| 168 | |||
| 169 | void | ||
| 170 | startpipe(void) | ||
| 171 | { | ||
| 172 | newpipechan = chancreate(sizeof(Window*), 0); | ||
| 173 | threadcreate(newpipethread, nil, STACK); | ||
| 174 | snarffd = open("/dev/snarf", OREAD|OCEXEC); | ||
| 175 | } | ||
Binary file not shown.
Binary file not shown.
| @@ -0,0 +1,90 @@ | |||
| 1 | #include <u.h> | ||
| 2 | #include <libc.h> | ||
| 3 | #include <bio.h> | ||
| 4 | #include <thread.h> | ||
| 5 | #include "dat.h" | ||
| 6 | |||
| 7 | void* | ||
| 8 | emalloc(uint n) | ||
| 9 | { | ||
| 10 | void *p; | ||
| 11 | |||
| 12 | p = malloc(n); | ||
| 13 | if(p == nil) | ||
| 14 | error("can't malloc: %r"); | ||
| 15 | memset(p, 0, n); | ||
| 16 | return p; | ||
| 17 | } | ||
| 18 | |||
| 19 | char* | ||
| 20 | estrdup(char *s) | ||
| 21 | { | ||
| 22 | char *t; | ||
| 23 | |||
| 24 | t = emalloc(strlen(s)+1); | ||
| 25 | strcpy(t, s); | ||
| 26 | return t; | ||
| 27 | } | ||
| 28 | |||
| 29 | char* | ||
| 30 | estrstrdup(char *s, char *t) | ||
| 31 | { | ||
| 32 | char *u; | ||
| 33 | |||
| 34 | u = emalloc(strlen(s)+strlen(t)+1); | ||
| 35 | sprint(u, "%s%s", s, t); | ||
| 36 | return u; | ||
| 37 | } | ||
| 38 | |||
| 39 | char* | ||
| 40 | eappend(char *s, char *sep, char *t) | ||
| 41 | { | ||
| 42 | char *u; | ||
| 43 | |||
| 44 | if(t == nil) | ||
| 45 | u = estrstrdup(s, sep); | ||
| 46 | else{ | ||
| 47 | u = emalloc(strlen(s)+strlen(sep)+strlen(t)+1); | ||
| 48 | sprint(u, "%s%s%s", s, sep, t); | ||
| 49 | } | ||
| 50 | free(s); | ||
| 51 | return u; | ||
| 52 | } | ||
| 53 | |||
| 54 | char* | ||
| 55 | egrow(char *s, char *sep, char *t) | ||
| 56 | { | ||
| 57 | s = eappend(s, sep, t); | ||
| 58 | free(t); | ||
| 59 | return s; | ||
| 60 | } | ||
| 61 | |||
| 62 | void | ||
| 63 | error(char *fmt, ...) | ||
| 64 | { | ||
| 65 | Fmt f; | ||
| 66 | char buf[64]; | ||
| 67 | va_list arg; | ||
| 68 | |||
| 69 | fmtfdinit(&f, 2, buf, sizeof buf); | ||
| 70 | fmtprint(&f, "win: "); | ||
| 71 | va_start(arg, fmt); | ||
| 72 | fmtvprint(&f, fmt, arg); | ||
| 73 | va_end(arg); | ||
| 74 | fmtprint(&f, "\n"); | ||
| 75 | fmtfdflush(&f); | ||
| 76 | threadexitsall(buf); | ||
| 77 | } | ||
| 78 | |||
| 79 | void | ||
| 80 | ctlprint(int fd, char *fmt, ...) | ||
| 81 | { | ||
| 82 | int n; | ||
| 83 | va_list arg; | ||
| 84 | |||
| 85 | va_start(arg, fmt); | ||
| 86 | n = vfprint(fd, fmt, arg); | ||
| 87 | va_end(arg); | ||
| 88 | if(n <= 0) | ||
| 89 | error("control file write error: %r"); | ||
| 90 | } | ||
Binary file not shown.
Binary file not shown.
| @@ -0,0 +1,273 @@ | |||
| 1 | #include <u.h> | ||
| 2 | #include <libc.h> | ||
| 3 | #include <bio.h> | ||
| 4 | #include <thread.h> | ||
| 5 | #include "dat.h" | ||
| 6 | |||
| 7 | Window* | ||
| 8 | newwindow(void) | ||
| 9 | { | ||
| 10 | char buf[12]; | ||
| 11 | Window *w; | ||
| 12 | |||
| 13 | w = emalloc(sizeof(Window)); | ||
| 14 | w->ctl = open("/mnt/wsys/new/ctl", ORDWR|OCEXEC); | ||
| 15 | if(w->ctl<0 || read(w->ctl, buf, 12)!=12) | ||
| 16 | error("can't open window ctl file: %r"); | ||
| 17 | ctlprint(w->ctl, "noscroll\n"); | ||
| 18 | w->id = atoi(buf); | ||
| 19 | w->event = winopenfile(w, "event"); | ||
| 20 | w->addr = winopenfile(w, "addr"); | ||
| 21 | w->body = winopenfile(w, "body"); | ||
| 22 | w->data = winopenfile(w, "data"); | ||
| 23 | w->cevent = chancreate(sizeof(Event*), 0); | ||
| 24 | return w; | ||
| 25 | } | ||
| 26 | |||
| 27 | void | ||
| 28 | winsetdump(Window *w, char *dir, char *cmd) | ||
| 29 | { | ||
| 30 | if(dir != nil) | ||
| 31 | ctlprint(w->ctl, "dumpdir %s\n", dir); | ||
| 32 | if(cmd != nil) | ||
| 33 | ctlprint(w->ctl, "dump %s\n", cmd); | ||
| 34 | } | ||
| 35 | |||
| 36 | void | ||
| 37 | winsetdir(Window *w, char *dir, char *name) | ||
| 38 | { | ||
| 39 | ctlprint(w->ctl, "dumpdir %s\n", dir); | ||
| 40 | if(strcmp(dir, "/")==0) | ||
| 41 | dir++; | ||
| 42 | ctlprint(w->ctl, "name %s/-%s\n", dir, name); | ||
| 43 | } | ||
| 44 | |||
| 45 | void | ||
| 46 | wineventproc(void *v) | ||
| 47 | { | ||
| 48 | Window *w; | ||
| 49 | int i; | ||
| 50 | |||
| 51 | w = v; | ||
| 52 | for(i=0; ; i++){ | ||
| 53 | if(i >= NEVENT) | ||
| 54 | i = 0; | ||
| 55 | wingetevent(w, &w->e[i]); | ||
| 56 | sendp(w->cevent, &w->e[i]); | ||
| 57 | } | ||
| 58 | } | ||
| 59 | |||
| 60 | int | ||
| 61 | winopenfile(Window *w, char *f) | ||
| 62 | { | ||
| 63 | char buf[64]; | ||
| 64 | int fd; | ||
| 65 | |||
| 66 | sprint(buf, "/mnt/wsys/%d/%s", w->id, f); | ||
| 67 | fd = open(buf, ORDWR|OCEXEC); | ||
| 68 | if(fd < 0) | ||
| 69 | error("can't open window file %s: %r", f); | ||
| 70 | return fd; | ||
| 71 | } | ||
| 72 | |||
| 73 | void | ||
| 74 | wintagwrite(Window *w, char *s, int n) | ||
| 75 | { | ||
| 76 | int fd; | ||
| 77 | |||
| 78 | fd = winopenfile(w, "tag"); | ||
| 79 | if(write(fd, s, n) != n) | ||
| 80 | error("tag write: %r"); | ||
| 81 | close(fd); | ||
| 82 | } | ||
| 83 | |||
| 84 | void | ||
| 85 | winname(Window *w, char *s) | ||
| 86 | { | ||
| 87 | ctlprint(w->ctl, "name %s\n", s); | ||
| 88 | } | ||
| 89 | |||
| 90 | int | ||
| 91 | wingetec(Window *w) | ||
| 92 | { | ||
| 93 | if(w->nbuf == 0){ | ||
| 94 | w->nbuf = read(w->event, w->buf, sizeof w->buf); | ||
| 95 | if(w->nbuf <= 0){ | ||
| 96 | /* probably because window has exited, and only called by wineventproc, so just shut down */ | ||
| 97 | threadexits(nil); | ||
| 98 | } | ||
| 99 | w->bufp = w->buf; | ||
| 100 | } | ||
| 101 | w->nbuf--; | ||
| 102 | return *w->bufp++; | ||
| 103 | } | ||
| 104 | |||
| 105 | int | ||
| 106 | wingeten(Window *w) | ||
| 107 | { | ||
| 108 | int n, c; | ||
| 109 | |||
| 110 | n = 0; | ||
| 111 | while('0'<=(c=wingetec(w)) && c<='9') | ||
| 112 | n = n*10+(c-'0'); | ||
| 113 | if(c != ' ') | ||
| 114 | error("event number syntax"); | ||
| 115 | return n; | ||
| 116 | } | ||
| 117 | |||
| 118 | int | ||
| 119 | wingeter(Window *w, char *buf, int *nb) | ||
| 120 | { | ||
| 121 | Rune r; | ||
| 122 | int n; | ||
| 123 | |||
| 124 | r = wingetec(w); | ||
| 125 | buf[0] = r; | ||
| 126 | n = 1; | ||
| 127 | if(r >= Runeself) { | ||
| 128 | while(!fullrune(buf, n)) | ||
| 129 | buf[n++] = wingetec(w); | ||
| 130 | chartorune(&r, buf); | ||
| 131 | } | ||
| 132 | *nb = n; | ||
| 133 | return r; | ||
| 134 | } | ||
| 135 | |||
| 136 | void | ||
| 137 | wingetevent(Window *w, Event *e) | ||
| 138 | { | ||
| 139 | int i, nb; | ||
| 140 | |||
| 141 | e->c1 = wingetec(w); | ||
| 142 | e->c2 = wingetec(w); | ||
| 143 | e->q0 = wingeten(w); | ||
| 144 | e->q1 = wingeten(w); | ||
| 145 | e->flag = wingeten(w); | ||
| 146 | e->nr = wingeten(w); | ||
| 147 | if(e->nr > EVENTSIZE) | ||
| 148 | error("event string too long"); | ||
| 149 | e->nb = 0; | ||
| 150 | for(i=0; i<e->nr; i++){ | ||
| 151 | e->r[i] = wingeter(w, e->b+e->nb, &nb); | ||
| 152 | e->nb += nb; | ||
| 153 | } | ||
| 154 | e->r[e->nr] = 0; | ||
| 155 | e->b[e->nb] = 0; | ||
| 156 | if(wingetec(w) != '\n') | ||
| 157 | error("event syntax error"); | ||
| 158 | } | ||
| 159 | |||
| 160 | void | ||
| 161 | winwriteevent(Window *w, Event *e) | ||
| 162 | { | ||
| 163 | fprint(w->event, "%c%c%d %d\n", e->c1, e->c2, e->q0, e->q1); | ||
| 164 | } | ||
| 165 | |||
| 166 | static int | ||
| 167 | nrunes(char *s, int nb) | ||
| 168 | { | ||
| 169 | int i, n; | ||
| 170 | Rune r; | ||
| 171 | |||
| 172 | n = 0; | ||
| 173 | for(i=0; i<nb; n++) | ||
| 174 | i += chartorune(&r, s+i); | ||
| 175 | return n; | ||
| 176 | } | ||
| 177 | |||
| 178 | int | ||
| 179 | winread(Window *w, uint q0, uint q1, char *data) | ||
| 180 | { | ||
| 181 | int m, n, nr, nb; | ||
| 182 | char buf[256]; | ||
| 183 | |||
| 184 | if(w->addr < 0) | ||
| 185 | w->addr = winopenfile(w, "addr"); | ||
| 186 | if(w->data < 0) | ||
| 187 | w->data = winopenfile(w, "data"); | ||
| 188 | m = q0; | ||
| 189 | nb = 0; | ||
| 190 | while(m < q1){ | ||
| 191 | n = sprint(buf, "#%d", m); | ||
| 192 | if(write(w->addr, buf, n) != n) | ||
| 193 | error("error writing addr: %r"); | ||
| 194 | n = read(w->data, buf, sizeof buf); | ||
| 195 | if(n < 0) | ||
| 196 | error("reading data: %r"); | ||
| 197 | nr = nrunes(buf, n); | ||
| 198 | while(m+nr >q1){ | ||
| 199 | do; while(n>0 && (buf[--n]&0xC0)==0x80); | ||
| 200 | --nr; | ||
| 201 | } | ||
| 202 | if(n == 0) | ||
| 203 | break; | ||
| 204 | memmove(data, buf, n); | ||
| 205 | nb += n; | ||
| 206 | data += n; | ||
| 207 | *data = 0; | ||
| 208 | m += nr; | ||
| 209 | } | ||
| 210 | return nb; | ||
| 211 | } | ||
| 212 | |||
| 213 | void | ||
| 214 | windormant(Window *w) | ||
| 215 | { | ||
| 216 | if(w->addr >= 0){ | ||
| 217 | close(w->addr); | ||
| 218 | w->addr = -1; | ||
| 219 | } | ||
| 220 | if(w->body >= 0){ | ||
| 221 | close(w->body); | ||
| 222 | w->body = -1; | ||
| 223 | } | ||
| 224 | if(w->data >= 0){ | ||
| 225 | close(w->data); | ||
| 226 | w->data = -1; | ||
| 227 | } | ||
| 228 | } | ||
| 229 | |||
| 230 | int | ||
| 231 | windel(Window *w, int sure) | ||
| 232 | { | ||
| 233 | if(sure) | ||
| 234 | write(w->ctl, "delete\n", 7); | ||
| 235 | else if(write(w->ctl, "del\n", 4) != 4) | ||
| 236 | return 0; | ||
| 237 | /* event proc will die due to read error from event file */ | ||
| 238 | windormant(w); | ||
| 239 | close(w->ctl); | ||
| 240 | w->ctl = -1; | ||
| 241 | close(w->event); | ||
| 242 | w->event = -1; | ||
| 243 | return 1; | ||
| 244 | } | ||
| 245 | |||
| 246 | void | ||
| 247 | winclean(Window *w) | ||
| 248 | { | ||
| 249 | ctlprint(w->ctl, "clean\n"); | ||
| 250 | } | ||
| 251 | |||
| 252 | int | ||
| 253 | winsetaddr(Window *w, char *addr, int errok) | ||
| 254 | { | ||
| 255 | if(w->addr < 0) | ||
| 256 | w->addr = winopenfile(w, "addr"); | ||
| 257 | if(write(w->addr, addr, strlen(addr)) < 0){ | ||
| 258 | if(!errok) | ||
| 259 | error("error writing addr(%s): %r", addr); | ||
| 260 | return 0; | ||
| 261 | } | ||
| 262 | return 1; | ||
| 263 | } | ||
| 264 | |||
| 265 | int | ||
| 266 | winselect(Window *w, char *addr, int errok) | ||
| 267 | { | ||
| 268 | if(winsetaddr(w, addr, errok)){ | ||
| 269 | ctlprint(w->ctl, "dot=addr\n"); | ||
| 270 | return 1; | ||
| 271 | } | ||
| 272 | return 0; | ||
| 273 | } | ||
| @@ -0,0 +1,3 @@ | |||
| 1 | #!/bin/rc | ||
| 2 | |||
| 3 | sed 's/^ //' $* | ||
| @@ -0,0 +1,5 @@ | |||
| 1 | #!/bin/rc -e | ||
| 2 | |||
| 3 | id=`{mkwnew $*} | ||
| 4 | cat >/mnt/acme/$id/body | ||
| 5 | echo clean >/mnt/acme/$id/ctl | ||
| @@ -0,0 +1,4 @@ | |||
| 1 | Mail stored | ||
| 2 | plumb /mail/box/$user/names | ||
| 3 | mail -'x' someaddress | ||
| 4 | mkbox /mail/box/$user/new_box | ||
| @@ -0,0 +1,11 @@ | |||
| 1 | #!/bin/rc | ||
| 2 | |||
| 3 | for(i){ | ||
| 4 | if(! test -e $i){ | ||
| 5 | if(cp /dev/null $i){ | ||
| 6 | chmod 600 $i | ||
| 7 | chmod +al $i | ||
| 8 | } | ||
| 9 | } | ||
| 10 | if not echo $i already exists | ||
| 11 | } | ||
| @@ -0,0 +1,57 @@ | |||
| 1 | The Acme Mail program uses upas/fs to parse the mail box, and then | ||
| 2 | presents a file-browser-like user interface to reading and sending | ||
| 3 | messages. The Mail window presents each numbered message like the | ||
| 4 | contents of a directory presented one per line. If a message has a | ||
| 5 | Subject: line, that is shown indented on the following line. | ||
| 6 | Multipart MIME-encoded messages are presented in the obvious | ||
| 7 | hierarchical format. | ||
| 8 | |||
| 9 | Mail uses upas/fs to access the mail box. By default it reads "mbox", | ||
| 10 | the standard user mail box. If Mail is given an argument, it is | ||
| 11 | passed to upas/fs as the name of the mail box (or upas/fs directory) | ||
| 12 | to open. | ||
| 13 | |||
| 14 | Although Mail works if the plumber is not running, it's designed to be | ||
| 15 | run with plumbing enabled and many of its features work best if it is. | ||
| 16 | |||
| 17 | The mailbox window has a few commands: Put writes back the mailbox; | ||
| 18 | Mail creates a new window in which to compose a message; and Delmesg | ||
| 19 | deletes messages by number. The number may be given as argument or | ||
| 20 | indicated by selecting the header line in the mailbox window. | ||
| 21 | (Delmesg does not expand null selections, in the interest of safety.) | ||
| 22 | |||
| 23 | Clicking the right button on a message number opens it; clicking on | ||
| 24 | any of the subparts of a message opens that (and also opens the | ||
| 25 | message itself). Each message window has a few commands in the tag | ||
| 26 | with obvious names: Reply, Delmsg, etc. "Reply" replies to the single | ||
| 27 | sender of the message, "Reply all" or "Replyall" replies to everyone | ||
| 28 | in the From:, To:, and CC: lines. | ||
| 29 | |||
| 30 | Message parts with recognized MIME types such as image/jpeg are sent | ||
| 31 | to the plumber for further dispatch. Acme Mail also listens to | ||
| 32 | messages on the seemail and showmail plumbing ports, to report the | ||
| 33 | arrival of new messages (highlighting the entry; right-click on the | ||
| 34 | entry to open the message) and open them if you right-click on the | ||
| 35 | face in the faces window. | ||
| 36 | |||
| 37 | When composing a mail message or replying to a message, the first line | ||
| 38 | of the text is a list of recipients of the message. To:, and CC:, and BCC: | ||
| 39 | lines are interpreted in the usual way. Two other header lines are | ||
| 40 | special to Acme Mail: | ||
| 41 | Include: file places a copy of file in the message as an | ||
| 42 | inline MIME attachment. | ||
| 43 | Attach: file places a copy of file in the message as a regular | ||
| 44 | MIME attachment. | ||
| 45 | |||
| 46 | Acme Mail uses these conventions when replying to messages, | ||
| 47 | constructing headers for the default behavior. You may edit these to | ||
| 48 | change behavior. Most important, when replying to a message Mail will | ||
| 49 | always Include: the original message; delete that line if you don't | ||
| 50 | want to include it. | ||
| 51 | |||
| 52 | If the mailbox | ||
| 53 | /mail/box/$user/outgoing | ||
| 54 | exists, Acme Mail will save your a copy of your outgoing messages | ||
| 55 | there. Attachments are described in the copy but not included. | ||
| 56 | |||
| 57 | The -m mntpoint flag specifies a different mount point for /upas/fs. | ||
Binary file not shown.
Binary file not shown.
| @@ -0,0 +1,164 @@ | |||
| 1 | typedef struct Event Event; | ||
| 2 | typedef struct Exec Exec; | ||
| 3 | typedef struct Message Message; | ||
| 4 | typedef struct Window Window; | ||
| 5 | |||
| 6 | enum | ||
| 7 | { | ||
| 8 | STACK = 8192, | ||
| 9 | EVENTSIZE = 256, | ||
| 10 | NEVENT = 5, | ||
| 11 | }; | ||
| 12 | |||
| 13 | struct Event | ||
| 14 | { | ||
| 15 | int c1; | ||
| 16 | int c2; | ||
| 17 | int q0; | ||
| 18 | int q1; | ||
| 19 | int flag; | ||
| 20 | int nb; | ||
| 21 | int nr; | ||
| 22 | char b[EVENTSIZE*UTFmax+1]; | ||
| 23 | Rune r[EVENTSIZE+1]; | ||
| 24 | }; | ||
| 25 | |||
| 26 | struct Window | ||
| 27 | { | ||
| 28 | /* file descriptors */ | ||
| 29 | int ctl; | ||
| 30 | int event; | ||
| 31 | int addr; | ||
| 32 | int data; | ||
| 33 | Biobuf *body; | ||
| 34 | |||
| 35 | /* event input */ | ||
| 36 | char buf[512]; | ||
| 37 | char *bufp; | ||
| 38 | int nbuf; | ||
| 39 | Event e[NEVENT]; | ||
| 40 | |||
| 41 | int id; | ||
| 42 | int open; | ||
| 43 | Channel *cevent; | ||
| 44 | }; | ||
| 45 | |||
| 46 | struct Message | ||
| 47 | { | ||
| 48 | Window *w; | ||
| 49 | int ctlfd; | ||
| 50 | char *name; | ||
| 51 | char *replyname; | ||
| 52 | uchar opened; | ||
| 53 | uchar dirty; | ||
| 54 | uchar isreply; | ||
| 55 | uchar deleted; | ||
| 56 | uchar writebackdel; | ||
| 57 | uchar tagposted; | ||
| 58 | uchar recursed; | ||
| 59 | uchar level; | ||
| 60 | |||
| 61 | /* header info */ | ||
| 62 | char *fromcolon; /* from header file; all rest are from info file */ | ||
| 63 | char *from; | ||
| 64 | char *to; | ||
| 65 | char *cc; | ||
| 66 | char *replyto; | ||
| 67 | char *date; | ||
| 68 | char *subject; | ||
| 69 | char *type; | ||
| 70 | char *disposition; | ||
| 71 | char *filename; | ||
| 72 | char *digest; | ||
| 73 | |||
| 74 | Message *next; /* next in this mailbox */ | ||
| 75 | Message *prev; /* prev in this mailbox */ | ||
| 76 | Message *head; /* first subpart */ | ||
| 77 | Message *tail; /* last subpart */ | ||
| 78 | }; | ||
| 79 | |||
| 80 | enum | ||
| 81 | { | ||
| 82 | NARGS = 100, | ||
| 83 | NARGCHAR = 8*1024, | ||
| 84 | EXECSTACK = STACK+(NARGS+1)*sizeof(char*)+NARGCHAR | ||
| 85 | }; | ||
| 86 | |||
| 87 | struct Exec | ||
| 88 | { | ||
| 89 | char *prog; | ||
| 90 | char **argv; | ||
| 91 | int p[2]; /* p[1] is write to program; p[0] set to prog fd 0*/ | ||
| 92 | int q[2]; /* q[0] is read from program; q[1] set to prog fd 1 */ | ||
| 93 | Channel *sync; | ||
| 94 | }; | ||
| 95 | |||
| 96 | extern Window* newwindow(void); | ||
| 97 | extern int winopenfile(Window*, char*); | ||
| 98 | extern void winopenbody(Window*, int); | ||
| 99 | extern void winclosebody(Window*); | ||
| 100 | extern void wintagwrite(Window*, char*, int); | ||
| 101 | extern void winname(Window*, char*); | ||
| 102 | extern void winwriteevent(Window*, Event*); | ||
| 103 | extern void winread(Window*, uint, uint, char*); | ||
| 104 | extern int windel(Window*, int); | ||
| 105 | extern void wingetevent(Window*, Event*); | ||
| 106 | extern void wineventproc(void*); | ||
| 107 | extern void winwritebody(Window*, char*, int); | ||
| 108 | extern void winclean(Window*); | ||
| 109 | extern int winselect(Window*, char*, int); | ||
| 110 | extern char* winselection(Window*); | ||
| 111 | extern int winsetaddr(Window*, char*, int); | ||
| 112 | extern char* winreadbody(Window*, int*); | ||
| 113 | extern void windormant(Window*); | ||
| 114 | extern void winsetdump(Window*, char*, char*); | ||
| 115 | |||
| 116 | extern void readmbox(Message*, char*, char*); | ||
| 117 | extern void rewritembox(Window*, Message*); | ||
| 118 | |||
| 119 | extern void mkreply(Message*, char*, char*, Plumbattr*, char*); | ||
| 120 | extern void delreply(Message*); | ||
| 121 | |||
| 122 | extern int mesgadd(Message*, char*, Dir*, char*); | ||
| 123 | extern void mesgmenu(Window*, Message*); | ||
| 124 | extern void mesgmenunew(Window*, Message*); | ||
| 125 | extern int mesgopen(Message*, char*, char*, Message*, int, char*); | ||
| 126 | extern void mesgctl(void*); | ||
| 127 | extern void mesgsend(Message*); | ||
| 128 | extern void mesgdel(Message*, Message*); | ||
| 129 | extern void mesgmenudel(Window*, Message*, Message*); | ||
| 130 | extern void mesgmenumark(Window*, char*, char*); | ||
| 131 | extern void mesgmenumarkdel(Window*, Message*, Message*, int); | ||
| 132 | extern Message* mesglookup(Message*, char*, char*); | ||
| 133 | extern Message* mesglookupfile(Message*, char*, char*); | ||
| 134 | extern void mesgfreeparts(Message*); | ||
| 135 | |||
| 136 | extern char* readfile(char*, char*, int*); | ||
| 137 | extern char* readbody(char*, char*, int*); | ||
| 138 | extern void ctlprint(int, char*, ...); | ||
| 139 | extern void* emalloc(uint); | ||
| 140 | extern void* erealloc(void*, uint); | ||
| 141 | extern char* estrdup(char*); | ||
| 142 | extern char* estrstrdup(char*, char*); | ||
| 143 | extern char* egrow(char*, char*, char*); | ||
| 144 | extern char* eappend(char*, char*, char*); | ||
| 145 | extern void error(char*, ...); | ||
| 146 | extern int tokenizec(char*, char**, int, char*); | ||
| 147 | extern void execproc(void*); | ||
| 148 | |||
| 149 | #pragma varargck argpos error 1 | ||
| 150 | #pragma varargck argpos ctlprint 2 | ||
| 151 | |||
| 152 | extern Window *wbox; | ||
| 153 | extern Message mbox; | ||
| 154 | extern Message replies; | ||
| 155 | extern char *fsname; | ||
| 156 | extern int plumbsendfd; | ||
| 157 | extern int plumbseemailfd; | ||
| 158 | extern char *home; | ||
| 159 | extern char *outgoing; | ||
| 160 | extern char *mailboxdir; | ||
| 161 | extern char *user; | ||
| 162 | extern char deleted[]; | ||
| 163 | extern int wctlfd; | ||
| 164 | extern int shortmenu; | ||
Binary file not shown.
Binary file not shown.
| @@ -0,0 +1,75 @@ | |||
| 1 | #include <u.h> | ||
| 2 | #include <libc.h> | ||
| 3 | #include <bio.h> | ||
| 4 | #include <thread.h> | ||
| 5 | #include <ctype.h> | ||
| 6 | #include <plumb.h> | ||
| 7 | #include "dat.h" | ||
| 8 | |||
| 9 | |||
| 10 | char* | ||
| 11 | formathtml(char *body, int *np) | ||
| 12 | { | ||
| 13 | int i, j, p[2], q[2]; | ||
| 14 | Exec *e; | ||
| 15 | char buf[1024]; | ||
| 16 | Channel *sync; | ||
| 17 | |||
| 18 | e = emalloc(sizeof(struct Exec)); | ||
| 19 | if(pipe(p) < 0 || pipe(q) < 0) | ||
| 20 | error("can't create pipe: %r"); | ||
| 21 | |||
| 22 | e->p[0] = p[0]; | ||
| 23 | e->p[1] = p[1]; | ||
| 24 | e->q[0] = q[0]; | ||
| 25 | e->q[1] = q[1]; | ||
| 26 | e->argv = emalloc(3*sizeof(char*)); | ||
| 27 | e->argv[0] = estrdup("htmlfmt"); | ||
| 28 | e->argv[1] = estrdup("-cutf-8"); | ||
| 29 | e->argv[2] = nil; | ||
| 30 | e->prog = "/bin/htmlfmt"; | ||
| 31 | sync = chancreate(sizeof(int), 0); | ||
| 32 | e->sync = sync; | ||
| 33 | proccreate(execproc, e, EXECSTACK); | ||
| 34 | recvul(sync); | ||
| 35 | close(p[0]); | ||
| 36 | close(q[1]); | ||
| 37 | |||
| 38 | if((i=write(p[1], body, *np)) != *np){ | ||
| 39 | fprint(2, "Mail: warning: htmlfmt failed: wrote %d of %d: %r\n", i, *np); | ||
| 40 | close(p[1]); | ||
| 41 | close(q[0]); | ||
| 42 | return body; | ||
| 43 | } | ||
| 44 | close(p[1]); | ||
| 45 | |||
| 46 | free(body); | ||
| 47 | body = nil; | ||
| 48 | i = 0; | ||
| 49 | for(;;){ | ||
| 50 | j = read(q[0], buf, sizeof buf); | ||
| 51 | if(j <= 0) | ||
| 52 | break; | ||
| 53 | body = realloc(body, i+j+1); | ||
| 54 | if(body == nil) | ||
| 55 | error("realloc failed: %r"); | ||
| 56 | memmove(body+i, buf, j); | ||
| 57 | i += j; | ||
| 58 | body[i] = '\0'; | ||
| 59 | } | ||
| 60 | close(q[0]); | ||
| 61 | |||
| 62 | *np = i; | ||
| 63 | return body; | ||
| 64 | } | ||
| 65 | |||
| 66 | char* | ||
| 67 | readbody(char *type, char *dir, int *np) | ||
| 68 | { | ||
| 69 | char *body; | ||
| 70 | |||
| 71 | body = readfile(dir, "body", np); | ||
| 72 | if(body != nil && strcmp(type, "text/html") == 0) | ||
| 73 | return formathtml(body, np); | ||
| 74 | return body; | ||
| 75 | } | ||
Binary file not shown.
Binary file not shown.
| @@ -0,0 +1,550 @@ | |||
| 1 | #include <u.h> | ||
| 2 | #include <libc.h> | ||
| 3 | #include <bio.h> | ||
| 4 | #include <thread.h> | ||
| 5 | #include <plumb.h> | ||
| 6 | #include <ctype.h> | ||
| 7 | #include "dat.h" | ||
| 8 | |||
| 9 | char *maildir = "/mail/fs/"; /* mountpoint of mail file system */ | ||
| 10 | char *mailtermdir = "/mnt/term/mail/fs/"; /* alternate mountpoint */ | ||
| 11 | char *mboxname = "mbox"; /* mailboxdir/mboxname is mail spool file */ | ||
| 12 | char *mailboxdir = nil; /* nil == /mail/box/$user */ | ||
| 13 | char *fsname; /* filesystem for mailboxdir/mboxname is at maildir/fsname */ | ||
| 14 | char *user; | ||
| 15 | char *outgoing; | ||
| 16 | |||
| 17 | Window *wbox; | ||
| 18 | Message mbox; | ||
| 19 | Message replies; | ||
| 20 | char *home; | ||
| 21 | int plumbsendfd; | ||
| 22 | int plumbseemailfd; | ||
| 23 | int plumbshowmailfd; | ||
| 24 | int plumbsendmailfd; | ||
| 25 | Channel *cplumb; | ||
| 26 | Channel *cplumbshow; | ||
| 27 | Channel *cplumbsend; | ||
| 28 | int wctlfd; | ||
| 29 | void mainctl(void*); | ||
| 30 | void plumbproc(void*); | ||
| 31 | void plumbshowproc(void*); | ||
| 32 | void plumbsendproc(void*); | ||
| 33 | void plumbthread(void); | ||
| 34 | void plumbshowthread(void*); | ||
| 35 | void plumbsendthread(void*); | ||
| 36 | |||
| 37 | int shortmenu; | ||
| 38 | |||
| 39 | void | ||
| 40 | usage(void) | ||
| 41 | { | ||
| 42 | fprint(2, "usage: Mail [-sS] [-o outgoing] [mailboxname [directoryname]]\n"); | ||
| 43 | threadexitsall("usage"); | ||
| 44 | } | ||
| 45 | |||
| 46 | void | ||
| 47 | removeupasfs(void) | ||
| 48 | { | ||
| 49 | char buf[256]; | ||
| 50 | |||
| 51 | if(strcmp(mboxname, "mbox") == 0) | ||
| 52 | return; | ||
| 53 | snprint(buf, sizeof buf, "close %s", mboxname); | ||
| 54 | write(mbox.ctlfd, buf, strlen(buf)); | ||
| 55 | } | ||
| 56 | |||
| 57 | int | ||
| 58 | ismaildir(char *s) | ||
| 59 | { | ||
| 60 | char buf[256]; | ||
| 61 | Dir *d; | ||
| 62 | int ret; | ||
| 63 | |||
| 64 | snprint(buf, sizeof buf, "%s%s", maildir, s); | ||
| 65 | d = dirstat(buf); | ||
| 66 | if(d == nil) | ||
| 67 | return 0; | ||
| 68 | ret = d->qid.type & QTDIR; | ||
| 69 | free(d); | ||
| 70 | return ret; | ||
| 71 | } | ||
| 72 | |||
| 73 | void | ||
| 74 | threadmain(int argc, char *argv[]) | ||
| 75 | { | ||
| 76 | char *s, *name; | ||
| 77 | char err[ERRMAX], *cmd; | ||
| 78 | int i, newdir; | ||
| 79 | Fmt fmt; | ||
| 80 | |||
| 81 | doquote = needsrcquote; | ||
| 82 | quotefmtinstall(); | ||
| 83 | |||
| 84 | /* open these early so we won't miss notification of new mail messages while we read mbox */ | ||
| 85 | plumbsendfd = plumbopen("send", OWRITE|OCEXEC); | ||
| 86 | plumbseemailfd = plumbopen("seemail", OREAD|OCEXEC); | ||
| 87 | plumbshowmailfd = plumbopen("showmail", OREAD|OCEXEC); | ||
| 88 | |||
| 89 | shortmenu = 0; | ||
| 90 | ARGBEGIN{ | ||
| 91 | case 's': | ||
| 92 | shortmenu = 1; | ||
| 93 | break; | ||
| 94 | case 'S': | ||
| 95 | shortmenu = 2; | ||
| 96 | break; | ||
| 97 | case 'o': | ||
| 98 | outgoing = EARGF(usage()); | ||
| 99 | break; | ||
| 100 | case 'm': | ||
| 101 | smprint(maildir, "%s/", EARGF(usage())); | ||
| 102 | break; | ||
| 103 | default: | ||
| 104 | usage(); | ||
| 105 | }ARGEND | ||
| 106 | |||
| 107 | name = "mbox"; | ||
| 108 | |||
| 109 | /* bind the terminal /mail/fs directory over the local one */ | ||
| 110 | if(access(maildir, 0)<0 && access(mailtermdir, 0)==0) | ||
| 111 | bind(mailtermdir, maildir, MAFTER); | ||
| 112 | |||
| 113 | newdir = 1; | ||
| 114 | if(argc > 0){ | ||
| 115 | i = strlen(argv[0]); | ||
| 116 | if(argc>2 || i==0) | ||
| 117 | usage(); | ||
| 118 | /* see if the name is that of an existing /mail/fs directory */ | ||
| 119 | if(argc==1 && strchr(argv[0], '/')==0 && ismaildir(argv[0])){ | ||
| 120 | name = argv[0]; | ||
| 121 | mboxname = eappend(estrdup(maildir), "", name); | ||
| 122 | newdir = 0; | ||
| 123 | }else{ | ||
| 124 | if(argv[0][i-1] == '/') | ||
| 125 | argv[0][i-1] = '\0'; | ||
| 126 | s = strrchr(argv[0], '/'); | ||
| 127 | if(s == nil) | ||
| 128 | mboxname = estrdup(argv[0]); | ||
| 129 | else{ | ||
| 130 | *s++ = '\0'; | ||
| 131 | if(*s == '\0') | ||
| 132 | usage(); | ||
| 133 | mailboxdir = argv[0]; | ||
| 134 | mboxname = estrdup(s); | ||
| 135 | } | ||
| 136 | if(argc > 1) | ||
| 137 | name = argv[1]; | ||
| 138 | else | ||
| 139 | name = mboxname; | ||
| 140 | } | ||
| 141 | } | ||
| 142 | |||
| 143 | user = getenv("user"); | ||
| 144 | if(user == nil) | ||
| 145 | user = "none"; | ||
| 146 | if(mailboxdir == nil) | ||
| 147 | mailboxdir = estrstrdup("/mail/box/", user); | ||
| 148 | if(outgoing == nil) | ||
| 149 | outgoing = estrstrdup(mailboxdir, "/outgoing"); | ||
| 150 | |||
| 151 | s = estrstrdup(maildir, "ctl"); | ||
| 152 | mbox.ctlfd = open(s, ORDWR|OCEXEC); | ||
| 153 | if(mbox.ctlfd < 0) | ||
| 154 | error("can't open %s: %r", s); | ||
| 155 | |||
| 156 | fsname = estrdup(name); | ||
| 157 | if(newdir && argc > 0){ | ||
| 158 | s = emalloc(5+strlen(mailboxdir)+strlen(mboxname)+strlen(name)+10+1); | ||
| 159 | for(i=0; i<10; i++){ | ||
| 160 | sprint(s, "open %s/%s %s", mailboxdir, mboxname, fsname); | ||
| 161 | if(write(mbox.ctlfd, s, strlen(s)) >= 0) | ||
| 162 | break; | ||
| 163 | err[0] = '\0'; | ||
| 164 | errstr(err, sizeof err); | ||
| 165 | if(strstr(err, "mbox name in use") == nil) | ||
| 166 | error("can't create directory %s for mail: %s", name, err); | ||
| 167 | free(fsname); | ||
| 168 | fsname = emalloc(strlen(name)+10); | ||
| 169 | sprint(fsname, "%s-%d", name, i); | ||
| 170 | } | ||
| 171 | if(i == 10) | ||
| 172 | error("can't open %s/%s: %r", mailboxdir, mboxname); | ||
| 173 | free(s); | ||
| 174 | } | ||
| 175 | |||
| 176 | s = estrstrdup(fsname, "/"); | ||
| 177 | mbox.name = estrstrdup(maildir, s); | ||
| 178 | mbox.level= 0; | ||
| 179 | readmbox(&mbox, maildir, s); | ||
| 180 | home = getenv("home"); | ||
| 181 | if(home == nil) | ||
| 182 | home = "/"; | ||
| 183 | |||
| 184 | wbox = newwindow(); | ||
| 185 | winname(wbox, mbox.name); | ||
| 186 | wintagwrite(wbox, "Put Mail Delmesg ", 3+1+4+1+7+1); | ||
| 187 | threadcreate(mainctl, wbox, STACK); | ||
| 188 | |||
| 189 | fmtstrinit(&fmt); | ||
| 190 | fmtprint(&fmt, "Mail"); | ||
| 191 | if(shortmenu) | ||
| 192 | fmtprint(&fmt, " -%c", "sS"[shortmenu-1]); | ||
| 193 | if(outgoing) | ||
| 194 | fmtprint(&fmt, " -o %s", outgoing); | ||
| 195 | fmtprint(&fmt, " %s", name); | ||
| 196 | cmd = fmtstrflush(&fmt); | ||
| 197 | if(cmd == nil) | ||
| 198 | sysfatal("out of memory"); | ||
| 199 | winsetdump(wbox, "/acme/mail", cmd); | ||
| 200 | mbox.w = wbox; | ||
| 201 | |||
| 202 | mesgmenu(wbox, &mbox); | ||
| 203 | winclean(wbox); | ||
| 204 | |||
| 205 | wctlfd = open("/dev/wctl", OWRITE|OCEXEC); /* for acme window */ | ||
| 206 | cplumb = chancreate(sizeof(Plumbmsg*), 0); | ||
| 207 | cplumbshow = chancreate(sizeof(Plumbmsg*), 0); | ||
| 208 | if(strcmp(name, "mbox") == 0){ | ||
| 209 | /* | ||
| 210 | * Avoid creating multiple windows to send mail by only accepting | ||
| 211 | * sendmail plumb messages if we're reading the main mailbox. | ||
| 212 | */ | ||
| 213 | plumbsendmailfd = plumbopen("sendmail", OREAD|OCEXEC); | ||
| 214 | cplumbsend = chancreate(sizeof(Plumbmsg*), 0); | ||
| 215 | proccreate(plumbsendproc, nil, STACK); | ||
| 216 | threadcreate(plumbsendthread, nil, STACK); | ||
| 217 | } | ||
| 218 | /* start plumb reader as separate proc ... */ | ||
| 219 | proccreate(plumbproc, nil, STACK); | ||
| 220 | proccreate(plumbshowproc, nil, STACK); | ||
| 221 | threadcreate(plumbshowthread, nil, STACK); | ||
| 222 | /* ... and use this thread to read the messages */ | ||
| 223 | plumbthread(); | ||
| 224 | } | ||
| 225 | |||
| 226 | void | ||
| 227 | plumbproc(void*) | ||
| 228 | { | ||
| 229 | Plumbmsg *m; | ||
| 230 | |||
| 231 | threadsetname("plumbproc"); | ||
| 232 | for(;;){ | ||
| 233 | m = plumbrecv(plumbseemailfd); | ||
| 234 | sendp(cplumb, m); | ||
| 235 | if(m == nil) | ||
| 236 | threadexits(nil); | ||
| 237 | } | ||
| 238 | } | ||
| 239 | |||
| 240 | void | ||
| 241 | plumbshowproc(void*) | ||
| 242 | { | ||
| 243 | Plumbmsg *m; | ||
| 244 | |||
| 245 | threadsetname("plumbshowproc"); | ||
| 246 | for(;;){ | ||
| 247 | m = plumbrecv(plumbshowmailfd); | ||
| 248 | sendp(cplumbshow, m); | ||
| 249 | if(m == nil) | ||
| 250 | threadexits(nil); | ||
| 251 | } | ||
| 252 | } | ||
| 253 | |||
| 254 | void | ||
| 255 | plumbsendproc(void*) | ||
| 256 | { | ||
| 257 | Plumbmsg *m; | ||
| 258 | |||
| 259 | threadsetname("plumbsendproc"); | ||
| 260 | for(;;){ | ||
| 261 | m = plumbrecv(plumbsendmailfd); | ||
| 262 | sendp(cplumbsend, m); | ||
| 263 | if(m == nil) | ||
| 264 | threadexits(nil); | ||
| 265 | } | ||
| 266 | } | ||
| 267 | |||
| 268 | void | ||
| 269 | newmesg(char *name, char *digest) | ||
| 270 | { | ||
| 271 | Dir *d; | ||
| 272 | |||
| 273 | if(strncmp(name, mbox.name, strlen(mbox.name)) != 0) | ||
| 274 | return; /* message is about another mailbox */ | ||
| 275 | if(mesglookupfile(&mbox, name, digest) != nil) | ||
| 276 | return; | ||
| 277 | d = dirstat(name); | ||
| 278 | if(d == nil) | ||
| 279 | return; | ||
| 280 | if(mesgadd(&mbox, mbox.name, d, digest)) | ||
| 281 | mesgmenunew(wbox, &mbox); | ||
| 282 | free(d); | ||
| 283 | } | ||
| 284 | |||
| 285 | void | ||
| 286 | showmesg(char *name, char *digest) | ||
| 287 | { | ||
| 288 | char *n; | ||
| 289 | |||
| 290 | if(strncmp(name, mbox.name, strlen(mbox.name)) != 0) | ||
| 291 | return; /* message is about another mailbox */ | ||
| 292 | n = estrdup(name+strlen(mbox.name)); | ||
| 293 | if(n[strlen(n)-1] != '/') | ||
| 294 | n = egrow(n, "/", nil); | ||
| 295 | mesgopen(&mbox, mbox.name, name+strlen(mbox.name), nil, 1, digest); | ||
| 296 | free(n); | ||
| 297 | } | ||
| 298 | |||
| 299 | void | ||
| 300 | delmesg(char *name, char *digest, int dodel) | ||
| 301 | { | ||
| 302 | Message *m; | ||
| 303 | |||
| 304 | m = mesglookupfile(&mbox, name, digest); | ||
| 305 | if(m != nil){ | ||
| 306 | mesgmenumarkdel(wbox, &mbox, m, 0); | ||
| 307 | if(dodel) | ||
| 308 | m->writebackdel = 1; | ||
| 309 | } | ||
| 310 | } | ||
| 311 | |||
| 312 | void | ||
| 313 | plumbthread(void) | ||
| 314 | { | ||
| 315 | Plumbmsg *m; | ||
| 316 | Plumbattr *a; | ||
| 317 | char *type, *digest; | ||
| 318 | |||
| 319 | threadsetname("plumbthread"); | ||
| 320 | while((m = recvp(cplumb)) != nil){ | ||
| 321 | a = m->attr; | ||
| 322 | digest = plumblookup(a, "digest"); | ||
| 323 | type = plumblookup(a, "mailtype"); | ||
| 324 | if(type == nil) | ||
| 325 | fprint(2, "Mail: plumb message with no mailtype attribute\n"); | ||
| 326 | else if(strcmp(type, "new") == 0) | ||
| 327 | newmesg(m->data, digest); | ||
| 328 | else if(strcmp(type, "delete") == 0) | ||
| 329 | delmesg(m->data, digest, 0); | ||
| 330 | else | ||
| 331 | fprint(2, "Mail: unknown plumb attribute %s\n", type); | ||
| 332 | plumbfree(m); | ||
| 333 | } | ||
| 334 | threadexits(nil); | ||
| 335 | } | ||
| 336 | |||
| 337 | void | ||
| 338 | plumbshowthread(void*) | ||
| 339 | { | ||
| 340 | Plumbmsg *m; | ||
| 341 | |||
| 342 | threadsetname("plumbshowthread"); | ||
| 343 | while((m = recvp(cplumbshow)) != nil){ | ||
| 344 | showmesg(m->data, plumblookup(m->attr, "digest")); | ||
| 345 | plumbfree(m); | ||
| 346 | } | ||
| 347 | threadexits(nil); | ||
| 348 | } | ||
| 349 | |||
| 350 | void | ||
| 351 | plumbsendthread(void*) | ||
| 352 | { | ||
| 353 | Plumbmsg *m; | ||
| 354 | |||
| 355 | threadsetname("plumbsendthread"); | ||
| 356 | while((m = recvp(cplumbsend)) != nil){ | ||
| 357 | mkreply(nil, "Mail", m->data, m->attr, nil); | ||
| 358 | plumbfree(m); | ||
| 359 | } | ||
| 360 | threadexits(nil); | ||
| 361 | } | ||
| 362 | |||
| 363 | int | ||
| 364 | mboxcommand(Window *w, char *s) | ||
| 365 | { | ||
| 366 | char *args[10], **targs; | ||
| 367 | Message *m, *next; | ||
| 368 | int ok, nargs, i, j; | ||
| 369 | char buf[128]; | ||
| 370 | |||
| 371 | nargs = tokenize(s, args, nelem(args)); | ||
| 372 | if(nargs == 0) | ||
| 373 | return 0; | ||
| 374 | if(strcmp(args[0], "Mail") == 0){ | ||
| 375 | if(nargs == 1) | ||
| 376 | mkreply(nil, "Mail", "", nil, nil); | ||
| 377 | else | ||
| 378 | mkreply(nil, "Mail", args[1], nil, nil); | ||
| 379 | return 1; | ||
| 380 | } | ||
| 381 | if(strcmp(s, "Del") == 0){ | ||
| 382 | if(mbox.dirty){ | ||
| 383 | mbox.dirty = 0; | ||
| 384 | fprint(2, "mail: mailbox not written\n"); | ||
| 385 | return 1; | ||
| 386 | } | ||
| 387 | ok = 1; | ||
| 388 | for(m=mbox.head; m!=nil; m=next){ | ||
| 389 | next = m->next; | ||
| 390 | if(m->w){ | ||
| 391 | if(windel(m->w, 0)) | ||
| 392 | m->w = nil; | ||
| 393 | else | ||
| 394 | ok = 0; | ||
| 395 | } | ||
| 396 | } | ||
| 397 | for(m=replies.head; m!=nil; m=next){ | ||
| 398 | next = m->next; | ||
| 399 | if(m->w){ | ||
| 400 | if(windel(m->w, 0)) | ||
| 401 | m->w = nil; | ||
| 402 | else | ||
| 403 | ok = 0; | ||
| 404 | } | ||
| 405 | } | ||
| 406 | if(ok){ | ||
| 407 | windel(w, 1); | ||
| 408 | removeupasfs(); | ||
| 409 | threadexitsall(nil); | ||
| 410 | } | ||
| 411 | return 1; | ||
| 412 | } | ||
| 413 | if(strcmp(s, "Put") == 0){ | ||
| 414 | rewritembox(wbox, &mbox); | ||
| 415 | return 1; | ||
| 416 | } | ||
| 417 | if(strcmp(s, "Delmesg") == 0){ | ||
| 418 | if(nargs > 1){ | ||
| 419 | for(i=1; i<nargs; i++){ | ||
| 420 | snprint(buf, sizeof buf, "%s%s", mbox.name, args[i]); | ||
| 421 | delmesg(buf, nil, 1); | ||
| 422 | } | ||
| 423 | } | ||
| 424 | s = winselection(w); | ||
| 425 | if(s == nil) | ||
| 426 | return 1; | ||
| 427 | nargs = 1; | ||
| 428 | for(i=0; s[i]; i++) | ||
| 429 | if(s[i] == '\n') | ||
| 430 | nargs++; | ||
| 431 | targs = emalloc(nargs*sizeof(char*)); /* could be too many for a local array */ | ||
| 432 | nargs = getfields(s, targs, nargs, 1, "\n"); | ||
| 433 | for(i=0; i<nargs; i++){ | ||
| 434 | if(!isdigit(targs[i][0])) | ||
| 435 | continue; | ||
| 436 | j = atoi(targs[i]); /* easy way to parse the number! */ | ||
| 437 | if(j == 0) | ||
| 438 | continue; | ||
| 439 | snprint(buf, sizeof buf, "%s%d", mbox.name, j); | ||
| 440 | delmesg(buf, nil, 1); | ||
| 441 | } | ||
| 442 | free(s); | ||
| 443 | free(targs); | ||
| 444 | return 1; | ||
| 445 | } | ||
| 446 | return 0; | ||
| 447 | } | ||
| 448 | |||
| 449 | void | ||
| 450 | mainctl(void *v) | ||
| 451 | { | ||
| 452 | Window *w; | ||
| 453 | Event *e, *e2, *eq, *ea; | ||
| 454 | int na, nopen; | ||
| 455 | char *s, *t, *buf; | ||
| 456 | |||
| 457 | w = v; | ||
| 458 | proccreate(wineventproc, w, STACK); | ||
| 459 | |||
| 460 | for(;;){ | ||
| 461 | e = recvp(w->cevent); | ||
| 462 | switch(e->c1){ | ||
| 463 | default: | ||
| 464 | Unknown: | ||
| 465 | print("unknown message %c%c\n", e->c1, e->c2); | ||
| 466 | break; | ||
| 467 | |||
| 468 | case 'E': /* write to body; can't affect us */ | ||
| 469 | break; | ||
| 470 | |||
| 471 | case 'F': /* generated by our actions; ignore */ | ||
| 472 | break; | ||
| 473 | |||
| 474 | case 'K': /* type away; we don't care */ | ||
| 475 | break; | ||
| 476 | |||
| 477 | case 'M': | ||
| 478 | switch(e->c2){ | ||
| 479 | case 'x': | ||
| 480 | case 'X': | ||
| 481 | ea = nil; | ||
| 482 | e2 = nil; | ||
| 483 | if(e->flag & 2) | ||
| 484 | e2 = recvp(w->cevent); | ||
| 485 | if(e->flag & 8){ | ||
| 486 | ea = recvp(w->cevent); | ||
| 487 | na = ea->nb; | ||
| 488 | recvp(w->cevent); | ||
| 489 | }else | ||
| 490 | na = 0; | ||
| 491 | s = e->b; | ||
| 492 | /* if it's a known command, do it */ | ||
| 493 | if((e->flag&2) && e->nb==0) | ||
| 494 | s = e2->b; | ||
| 495 | if(na){ | ||
| 496 | t = emalloc(strlen(s)+1+na+1); | ||
| 497 | sprint(t, "%s %s", s, ea->b); | ||
| 498 | s = t; | ||
| 499 | } | ||
| 500 | /* if it's a long message, it can't be for us anyway */ | ||
| 501 | if(!mboxcommand(w, s)) /* send it back */ | ||
| 502 | winwriteevent(w, e); | ||
| 503 | if(na) | ||
| 504 | free(s); | ||
| 505 | break; | ||
| 506 | |||
| 507 | case 'l': | ||
| 508 | case 'L': | ||
| 509 | buf = nil; | ||
| 510 | eq = e; | ||
| 511 | if(e->flag & 2){ | ||
| 512 | e2 = recvp(w->cevent); | ||
| 513 | eq = e2; | ||
| 514 | } | ||
| 515 | s = eq->b; | ||
| 516 | if(eq->q1>eq->q0 && eq->nb==0){ | ||
| 517 | buf = emalloc((eq->q1-eq->q0)*UTFmax+1); | ||
| 518 | winread(w, eq->q0, eq->q1, buf); | ||
| 519 | s = buf; | ||
| 520 | } | ||
| 521 | nopen = 0; | ||
| 522 | do{ | ||
| 523 | /* skip 'deleted' string if present' */ | ||
| 524 | if(strncmp(s, deleted, strlen(deleted)) == 0) | ||
| 525 | s += strlen(deleted); | ||
| 526 | /* skip mail box name if present */ | ||
| 527 | if(strncmp(s, mbox.name, strlen(mbox.name)) == 0) | ||
| 528 | s += strlen(mbox.name); | ||
| 529 | nopen += mesgopen(&mbox, mbox.name, s, nil, 0, nil); | ||
| 530 | while(*s!='\0' && *s++!='\n') | ||
| 531 | ; | ||
| 532 | }while(*s); | ||
| 533 | if(nopen == 0) /* send it back */ | ||
| 534 | winwriteevent(w, e); | ||
| 535 | free(buf); | ||
| 536 | break; | ||
| 537 | |||
| 538 | case 'I': /* modify away; we don't care */ | ||
| 539 | case 'D': | ||
| 540 | case 'd': | ||
| 541 | case 'i': | ||
| 542 | break; | ||
| 543 | |||
| 544 | default: | ||
| 545 | goto Unknown; | ||
| 546 | } | ||
| 547 | } | ||
| 548 | } | ||
| 549 | } | ||
| 550 | |||
Binary file not shown.
Binary file not shown.
| @@ -0,0 +1,1322 @@ | |||
| 1 | #include <u.h> | ||
| 2 | #include <libc.h> | ||
| 3 | #include <bio.h> | ||
| 4 | #include <thread.h> | ||
| 5 | #include <ctype.h> | ||
| 6 | #include <plumb.h> | ||
| 7 | #include "dat.h" | ||
| 8 | |||
| 9 | enum | ||
| 10 | { | ||
| 11 | DIRCHUNK = 32*sizeof(Dir) | ||
| 12 | }; | ||
| 13 | |||
| 14 | char regexchars[] = "\\/[].+?()*^$"; | ||
| 15 | char deleted[] = "(deleted)-"; | ||
| 16 | char deletedrx[] = "\\(deleted\\)-"; | ||
| 17 | char deletedrx01[] = "(\\(deleted\\)-)?"; | ||
| 18 | char deletedaddr[] = "-#0;/^\\(deleted\\)-/"; | ||
| 19 | |||
| 20 | struct{ | ||
| 21 | char *type; | ||
| 22 | char *port; | ||
| 23 | char *suffix; | ||
| 24 | } ports[] = { | ||
| 25 | "text/", "edit", ".txt", | ||
| 26 | /* text must be first for plumbport() */ | ||
| 27 | "image/gif", "image", ".gif", | ||
| 28 | "image/jpeg", "image", ".jpg", | ||
| 29 | "image/jpeg", "image", ".jpeg", | ||
| 30 | "image/png", "image", ".png", | ||
| 31 | "image/tiff", "image", ".tif", | ||
| 32 | "application/postscript", "postscript", ".ps", | ||
| 33 | "application/pdf", "postscript", ".pdf", | ||
| 34 | "application/msword", "msword", ".doc", | ||
| 35 | "application/rtf", "msword", ".rtf", | ||
| 36 | "audio/x-wav", "wav", ".wav", | ||
| 37 | nil, nil | ||
| 38 | }; | ||
| 39 | |||
| 40 | char *goodtypes[] = { | ||
| 41 | "text", | ||
| 42 | "text/plain", | ||
| 43 | "message/rfc822", | ||
| 44 | "text/richtext", | ||
| 45 | "text/tab-separated-values", | ||
| 46 | "application/octet-stream", | ||
| 47 | nil, | ||
| 48 | }; | ||
| 49 | |||
| 50 | struct{ | ||
| 51 | char *type; | ||
| 52 | char *ext; | ||
| 53 | } exts[] = { | ||
| 54 | "image/gif", ".gif", | ||
| 55 | "image/jpeg", ".jpg", | ||
| 56 | nil, nil | ||
| 57 | }; | ||
| 58 | |||
| 59 | char *okheaders[] = | ||
| 60 | { | ||
| 61 | "From:", | ||
| 62 | "Date:", | ||
| 63 | "To:", | ||
| 64 | "CC:", | ||
| 65 | "Subject:", | ||
| 66 | nil | ||
| 67 | }; | ||
| 68 | |||
| 69 | char *extraheaders[] = | ||
| 70 | { | ||
| 71 | "Resent-From:", | ||
| 72 | "Resent-To:", | ||
| 73 | "Sort:", | ||
| 74 | nil, | ||
| 75 | }; | ||
| 76 | |||
| 77 | char* | ||
| 78 | line(char *data, char **pp) | ||
| 79 | { | ||
| 80 | char *p, *q; | ||
| 81 | |||
| 82 | for(p=data; *p!='\0' && *p!='\n'; p++) | ||
| 83 | ; | ||
| 84 | if(*p == '\n') | ||
| 85 | *pp = p+1; | ||
| 86 | else | ||
| 87 | *pp = p; | ||
| 88 | q = emalloc(p-data + 1); | ||
| 89 | memmove(q, data, p-data); | ||
| 90 | return q; | ||
| 91 | } | ||
| 92 | |||
| 93 | void | ||
| 94 | scanheaders(Message *m, char *dir) | ||
| 95 | { | ||
| 96 | char *s, *t, *u, *f; | ||
| 97 | |||
| 98 | s = f = readfile(dir, "header", nil); | ||
| 99 | if(s != nil) | ||
| 100 | while(*s){ | ||
| 101 | t = line(s, &s); | ||
| 102 | if(strncmp(t, "From: ", 6) == 0){ | ||
| 103 | m->fromcolon = estrdup(t+6); | ||
| 104 | /* remove all quotes; they're ugly and irregular */ | ||
| 105 | for(u=m->fromcolon; *u; u++) | ||
| 106 | if(*u == '"') | ||
| 107 | memmove(u, u+1, strlen(u)); | ||
| 108 | } | ||
| 109 | if(strncmp(t, "Subject: ", 9) == 0) | ||
| 110 | m->subject = estrdup(t+9); | ||
| 111 | free(t); | ||
| 112 | } | ||
| 113 | if(m->fromcolon == nil) | ||
| 114 | m->fromcolon = estrdup(m->from); | ||
| 115 | free(f); | ||
| 116 | } | ||
| 117 | |||
| 118 | int | ||
| 119 | loadinfo(Message *m, char *dir) | ||
| 120 | { | ||
| 121 | int n; | ||
| 122 | char *data, *p, *s; | ||
| 123 | |||
| 124 | data = readfile(dir, "info", &n); | ||
| 125 | if(data == nil) | ||
| 126 | return 0; | ||
| 127 | m->from = line(data, &p); | ||
| 128 | scanheaders(m, dir); /* depends on m->from being set */ | ||
| 129 | m->to = line(p, &p); | ||
| 130 | m->cc = line(p, &p); | ||
| 131 | m->replyto = line(p, &p); | ||
| 132 | m->date = line(p, &p); | ||
| 133 | s = line(p, &p); | ||
| 134 | if(m->subject == nil) | ||
| 135 | m->subject = s; | ||
| 136 | else | ||
| 137 | free(s); | ||
| 138 | m->type = line(p, &p); | ||
| 139 | m->disposition = line(p, &p); | ||
| 140 | m->filename = line(p, &p); | ||
| 141 | m->digest = line(p, &p); | ||
| 142 | free(data); | ||
| 143 | return 1; | ||
| 144 | } | ||
| 145 | |||
| 146 | int | ||
| 147 | isnumeric(char *s) | ||
| 148 | { | ||
| 149 | while(*s){ | ||
| 150 | if(!isdigit(*s)) | ||
| 151 | return 0; | ||
| 152 | s++; | ||
| 153 | } | ||
| 154 | return 1; | ||
| 155 | } | ||
| 156 | |||
| 157 | Dir* | ||
| 158 | loaddir(char *name, int *np) | ||
| 159 | { | ||
| 160 | int fd; | ||
| 161 | Dir *dp; | ||
| 162 | |||
| 163 | fd = open(name, OREAD); | ||
| 164 | if(fd < 0) | ||
| 165 | return nil; | ||
| 166 | *np = dirreadall(fd, &dp); | ||
| 167 | close(fd); | ||
| 168 | return dp; | ||
| 169 | } | ||
| 170 | |||
| 171 | void | ||
| 172 | readmbox(Message *mbox, char *dir, char *subdir) | ||
| 173 | { | ||
| 174 | char *name; | ||
| 175 | Dir *d, *dirp; | ||
| 176 | int i, n; | ||
| 177 | |||
| 178 | name = estrstrdup(dir, subdir); | ||
| 179 | dirp = loaddir(name, &n); | ||
| 180 | mbox->recursed = 1; | ||
| 181 | if(dirp) | ||
| 182 | for(i=0; i<n; i++){ | ||
| 183 | d = &dirp[i]; | ||
| 184 | if(isnumeric(d->name)) | ||
| 185 | mesgadd(mbox, name, d, nil); | ||
| 186 | } | ||
| 187 | free(dirp); | ||
| 188 | free(name); | ||
| 189 | } | ||
| 190 | |||
| 191 | /* add message to box, in increasing numerical order */ | ||
| 192 | int | ||
| 193 | mesgadd(Message *mbox, char *dir, Dir *d, char *digest) | ||
| 194 | { | ||
| 195 | Message *m; | ||
| 196 | char *name; | ||
| 197 | int loaded; | ||
| 198 | |||
| 199 | m = emalloc(sizeof(Message)); | ||
| 200 | m->name = estrstrdup(d->name, "/"); | ||
| 201 | m->next = nil; | ||
| 202 | m->prev = mbox->tail; | ||
| 203 | m->level= mbox->level+1; | ||
| 204 | m->recursed = 0; | ||
| 205 | name = estrstrdup(dir, m->name); | ||
| 206 | loaded = loadinfo(m, name); | ||
| 207 | free(name); | ||
| 208 | /* if two upas/fs are running, we can get misled, so check digest before accepting message */ | ||
| 209 | if(loaded==0 || (digest!=nil && m->digest!=nil && strcmp(digest, m->digest)!=0)){ | ||
| 210 | mesgfreeparts(m); | ||
| 211 | free(m); | ||
| 212 | return 0; | ||
| 213 | } | ||
| 214 | if(mbox->tail != nil) | ||
| 215 | mbox->tail->next = m; | ||
| 216 | mbox->tail = m; | ||
| 217 | if(mbox->head == nil) | ||
| 218 | mbox->head = m; | ||
| 219 | |||
| 220 | if (m->level != 1){ | ||
| 221 | m->recursed = 1; | ||
| 222 | readmbox(m, dir, m->name); | ||
| 223 | } | ||
| 224 | return 1; | ||
| 225 | } | ||
| 226 | |||
| 227 | int | ||
| 228 | thisyear(char *year) | ||
| 229 | { | ||
| 230 | static char now[10]; | ||
| 231 | char *s; | ||
| 232 | |||
| 233 | if(now[0] == '\0'){ | ||
| 234 | s = ctime(time(nil)); | ||
| 235 | strcpy(now, s+24); | ||
| 236 | } | ||
| 237 | return strncmp(year, now, 4) == 0; | ||
| 238 | } | ||
| 239 | |||
| 240 | char* | ||
| 241 | stripdate(char *as) | ||
| 242 | { | ||
| 243 | int n; | ||
| 244 | char *s, *fld[10]; | ||
| 245 | |||
| 246 | as = estrdup(as); | ||
| 247 | s = estrdup(as); | ||
| 248 | n = tokenize(s, fld, 10); | ||
| 249 | if(n > 5){ | ||
| 250 | sprint(as, "%.3s ", fld[0]); /* day */ | ||
| 251 | /* some dates have 19 Apr, some Apr 19 */ | ||
| 252 | if(strlen(fld[1])<4 && isnumeric(fld[1])) | ||
| 253 | sprint(as+strlen(as), "%.3s %.3s ", fld[1], fld[2]); /* date, month */ | ||
| 254 | else | ||
| 255 | sprint(as+strlen(as), "%.3s %.3s ", fld[2], fld[1]); /* date, month */ | ||
| 256 | /* do we use time or year? depends on whether year matches this one */ | ||
| 257 | if(thisyear(fld[5])){ | ||
| 258 | if(strchr(fld[3], ':') != nil) | ||
| 259 | sprint(as+strlen(as), "%.5s ", fld[3]); /* time */ | ||
| 260 | else if(strchr(fld[4], ':') != nil) | ||
| 261 | sprint(as+strlen(as), "%.5s ", fld[4]); /* time */ | ||
| 262 | }else | ||
| 263 | sprint(as+strlen(as), "%.4s ", fld[5]); /* year */ | ||
| 264 | } | ||
| 265 | free(s); | ||
| 266 | return as; | ||
| 267 | } | ||
| 268 | |||
| 269 | char* | ||
| 270 | readfile(char *dir, char *name, int *np) | ||
| 271 | { | ||
| 272 | char *file, *data; | ||
| 273 | int fd, len; | ||
| 274 | Dir *d; | ||
| 275 | |||
| 276 | if(np != nil) | ||
| 277 | *np = 0; | ||
| 278 | file = estrstrdup(dir, name); | ||
| 279 | fd = open(file, OREAD); | ||
| 280 | if(fd < 0) | ||
| 281 | return nil; | ||
| 282 | d = dirfstat(fd); | ||
| 283 | free(file); | ||
| 284 | len = 0; | ||
| 285 | if(d != nil) | ||
| 286 | len = d->length; | ||
| 287 | free(d); | ||
| 288 | data = emalloc(len+1); | ||
| 289 | read(fd, data, len); | ||
| 290 | close(fd); | ||
| 291 | if(np != nil) | ||
| 292 | *np = len; | ||
| 293 | return data; | ||
| 294 | } | ||
| 295 | |||
| 296 | char* | ||
| 297 | info(Message *m, int ind, int ogf) | ||
| 298 | { | ||
| 299 | char *i; | ||
| 300 | int j, len, lens; | ||
| 301 | char *p; | ||
| 302 | char fmt[80], s[80]; | ||
| 303 | |||
| 304 | if (ogf) | ||
| 305 | p=m->to; | ||
| 306 | else | ||
| 307 | p=m->fromcolon; | ||
| 308 | |||
| 309 | if(ind==0 && shortmenu){ | ||
| 310 | len = 30; | ||
| 311 | lens = 30; | ||
| 312 | if(shortmenu > 1){ | ||
| 313 | len = 10; | ||
| 314 | lens = 25; | ||
| 315 | } | ||
| 316 | if(ind==0 && m->subject[0]=='\0'){ | ||
| 317 | snprint(fmt, sizeof fmt, " %%-%d.%ds", len, len); | ||
| 318 | snprint(s, sizeof s, fmt, p); | ||
| 319 | }else{ | ||
| 320 | snprint(fmt, sizeof fmt, " %%-%d.%ds %%-%d.%ds", len, len, lens, lens); | ||
| 321 | snprint(s, sizeof s, fmt, p, m->subject); | ||
| 322 | } | ||
| 323 | i = estrdup(s); | ||
| 324 | |||
| 325 | return i; | ||
| 326 | } | ||
| 327 | |||
| 328 | i = estrdup(""); | ||
| 329 | i = eappend(i, "\t", p); | ||
| 330 | i = egrow(i, "\t", stripdate(m->date)); | ||
| 331 | if(ind == 0){ | ||
| 332 | if(strcmp(m->type, "text")!=0 && strncmp(m->type, "text/", 5)!=0 && | ||
| 333 | strncmp(m->type, "multipart/", 10)!=0) | ||
| 334 | i = egrow(i, "\t(", estrstrdup(m->type, ")")); | ||
| 335 | }else if(strncmp(m->type, "multipart/", 10) != 0) | ||
| 336 | i = egrow(i, "\t(", estrstrdup(m->type, ")")); | ||
| 337 | if(m->subject[0] != '\0'){ | ||
| 338 | i = eappend(i, "\n", nil); | ||
| 339 | for(j=0; j<ind; j++) | ||
| 340 | i = eappend(i, "\t", nil); | ||
| 341 | i = eappend(i, "\t", m->subject); | ||
| 342 | } | ||
| 343 | return i; | ||
| 344 | } | ||
| 345 | |||
| 346 | void | ||
| 347 | mesgmenu0(Window *w, Message *mbox, char *realdir, char *dir, int ind, Biobuf *fd, int onlyone, int dotail) | ||
| 348 | { | ||
| 349 | int i; | ||
| 350 | Message *m; | ||
| 351 | char *name, *tmp; | ||
| 352 | int ogf=0; | ||
| 353 | |||
| 354 | if(strstr(realdir, "outgoing") != nil) | ||
| 355 | ogf=1; | ||
| 356 | |||
| 357 | /* show mail box in reverse order, pieces in forward order */ | ||
| 358 | if(ind > 0) | ||
| 359 | m = mbox->head; | ||
| 360 | else | ||
| 361 | m = mbox->tail; | ||
| 362 | while(m != nil){ | ||
| 363 | for(i=0; i<ind; i++) | ||
| 364 | Bprint(fd, "\t"); | ||
| 365 | if(ind != 0) | ||
| 366 | Bprint(fd, " "); | ||
| 367 | name = estrstrdup(dir, m->name); | ||
| 368 | tmp = info(m, ind, ogf); | ||
| 369 | Bprint(fd, "%s%s\n", name, tmp); | ||
| 370 | free(tmp); | ||
| 371 | if(dotail && m->tail) | ||
| 372 | mesgmenu0(w, m, realdir, name, ind+1, fd, 0, dotail); | ||
| 373 | free(name); | ||
| 374 | if(ind) | ||
| 375 | m = m->next; | ||
| 376 | else | ||
| 377 | m = m->prev; | ||
| 378 | if(onlyone) | ||
| 379 | m = nil; | ||
| 380 | } | ||
| 381 | } | ||
| 382 | |||
| 383 | void | ||
| 384 | mesgmenu(Window *w, Message *mbox) | ||
| 385 | { | ||
| 386 | winopenbody(w, OWRITE); | ||
| 387 | mesgmenu0(w, mbox, mbox->name, "", 0, w->body, 0, !shortmenu); | ||
| 388 | winclosebody(w); | ||
| 389 | } | ||
| 390 | |||
| 391 | /* one new message has arrived, as mbox->tail */ | ||
| 392 | void | ||
| 393 | mesgmenunew(Window *w, Message *mbox) | ||
| 394 | { | ||
| 395 | Biobuf *b; | ||
| 396 | |||
| 397 | winselect(w, "0", 0); | ||
| 398 | w->data = winopenfile(w, "data"); | ||
| 399 | b = emalloc(sizeof(Biobuf)); | ||
| 400 | Binit(b, w->data, OWRITE); | ||
| 401 | mesgmenu0(w, mbox, mbox->name, "", 0, b, 1, !shortmenu); | ||
| 402 | Bterm(b); | ||
| 403 | free(b); | ||
| 404 | if(!mbox->dirty) | ||
| 405 | winclean(w); | ||
| 406 | /* select tag line plus following indented lines, but not final newline (it's distinctive) */ | ||
| 407 | winselect(w, "0/.*\\n((\t.*\\n)*\t.*)?/", 1); | ||
| 408 | close(w->addr); | ||
| 409 | close(w->data); | ||
| 410 | w->addr = -1; | ||
| 411 | w->data = -1; | ||
| 412 | } | ||
| 413 | |||
| 414 | char* | ||
| 415 | name2regexp(char *prefix, char *s) | ||
| 416 | { | ||
| 417 | char *buf, *p, *q; | ||
| 418 | |||
| 419 | buf = emalloc(strlen(prefix)+2*strlen(s)+50); /* leave room to append more */ | ||
| 420 | p = buf; | ||
| 421 | *p++ = '0'; | ||
| 422 | *p++ = '/'; | ||
| 423 | *p++ = '^'; | ||
| 424 | strcpy(p, prefix); | ||
| 425 | p += strlen(prefix); | ||
| 426 | for(q=s; *q!='\0'; q++){ | ||
| 427 | if(strchr(regexchars, *q) != nil) | ||
| 428 | *p++ = '\\'; | ||
| 429 | *p++ = *q; | ||
| 430 | } | ||
| 431 | *p++ = '/'; | ||
| 432 | *p = '\0'; | ||
| 433 | return buf; | ||
| 434 | } | ||
| 435 | |||
| 436 | void | ||
| 437 | mesgmenumarkdel(Window *w, Message *mbox, Message *m, int writeback) | ||
| 438 | { | ||
| 439 | char *buf; | ||
| 440 | |||
| 441 | |||
| 442 | if(m->deleted) | ||
| 443 | return; | ||
| 444 | m->writebackdel = writeback; | ||
| 445 | if(w->data < 0) | ||
| 446 | w->data = winopenfile(w, "data"); | ||
| 447 | buf = name2regexp("", m->name); | ||
| 448 | strcat(buf, "-#0"); | ||
| 449 | if(winselect(w, buf, 1)) | ||
| 450 | write(w->data, deleted, 10); | ||
| 451 | free(buf); | ||
| 452 | close(w->data); | ||
| 453 | close(w->addr); | ||
| 454 | w->addr = w->data = -1; | ||
| 455 | mbox->dirty = 1; | ||
| 456 | m->deleted = 1; | ||
| 457 | } | ||
| 458 | |||
| 459 | void | ||
| 460 | mesgmenumarkundel(Window *w, Message*, Message *m) | ||
| 461 | { | ||
| 462 | char *buf; | ||
| 463 | |||
| 464 | if(m->deleted == 0) | ||
| 465 | return; | ||
| 466 | if(w->data < 0) | ||
| 467 | w->data = winopenfile(w, "data"); | ||
| 468 | buf = name2regexp(deletedrx, m->name); | ||
| 469 | if(winselect(w, buf, 1)) | ||
| 470 | if(winsetaddr(w, deletedaddr, 1)) | ||
| 471 | write(w->data, "", 0); | ||
| 472 | free(buf); | ||
| 473 | close(w->data); | ||
| 474 | close(w->addr); | ||
| 475 | w->addr = w->data = -1; | ||
| 476 | m->deleted = 0; | ||
| 477 | } | ||
| 478 | |||
| 479 | void | ||
| 480 | mesgmenudel(Window *w, Message *mbox, Message *m) | ||
| 481 | { | ||
| 482 | char *buf; | ||
| 483 | |||
| 484 | if(w->data < 0) | ||
| 485 | w->data = winopenfile(w, "data"); | ||
| 486 | buf = name2regexp(deletedrx, m->name); | ||
| 487 | if(winsetaddr(w, buf, 1) && winsetaddr(w, ".,./.*\\n(\t.*\\n)*/", 1)) | ||
| 488 | write(w->data, "", 0); | ||
| 489 | free(buf); | ||
| 490 | close(w->data); | ||
| 491 | close(w->addr); | ||
| 492 | w->addr = w->data = -1; | ||
| 493 | mbox->dirty = 1; | ||
| 494 | m->deleted = 1; | ||
| 495 | } | ||
| 496 | |||
| 497 | void | ||
| 498 | mesgmenumark(Window *w, char *which, char *mark) | ||
| 499 | { | ||
| 500 | char *buf; | ||
| 501 | |||
| 502 | if(w->data < 0) | ||
| 503 | w->data = winopenfile(w, "data"); | ||
| 504 | buf = name2regexp(deletedrx01, which); | ||
| 505 | if(winsetaddr(w, buf, 1) && winsetaddr(w, "+0-#1", 1)) /* go to end of line */ | ||
| 506 | write(w->data, mark, strlen(mark)); | ||
| 507 | free(buf); | ||
| 508 | close(w->data); | ||
| 509 | close(w->addr); | ||
| 510 | w->addr = w->data = -1; | ||
| 511 | if(!mbox.dirty) | ||
| 512 | winclean(w); | ||
| 513 | } | ||
| 514 | |||
| 515 | void | ||
| 516 | mesgfreeparts(Message *m) | ||
| 517 | { | ||
| 518 | free(m->name); | ||
| 519 | free(m->replyname); | ||
| 520 | free(m->fromcolon); | ||
| 521 | free(m->from); | ||
| 522 | free(m->to); | ||
| 523 | free(m->cc); | ||
| 524 | free(m->replyto); | ||
| 525 | free(m->date); | ||
| 526 | free(m->subject); | ||
| 527 | free(m->type); | ||
| 528 | free(m->disposition); | ||
| 529 | free(m->filename); | ||
| 530 | free(m->digest); | ||
| 531 | } | ||
| 532 | |||
| 533 | void | ||
| 534 | mesgdel(Message *mbox, Message *m) | ||
| 535 | { | ||
| 536 | Message *n, *next; | ||
| 537 | |||
| 538 | if(m->opened) | ||
| 539 | error("internal error: deleted message still open in mesgdel"); | ||
| 540 | /* delete subparts */ | ||
| 541 | for(n=m->head; n!=nil; n=next){ | ||
| 542 | next = n->next; | ||
| 543 | mesgdel(m, n); | ||
| 544 | } | ||
| 545 | /* remove this message from list */ | ||
| 546 | if(m->next) | ||
| 547 | m->next->prev = m->prev; | ||
| 548 | else | ||
| 549 | mbox->tail = m->prev; | ||
| 550 | if(m->prev) | ||
| 551 | m->prev->next = m->next; | ||
| 552 | else | ||
| 553 | mbox->head = m->next; | ||
| 554 | |||
| 555 | mesgfreeparts(m); | ||
| 556 | } | ||
| 557 | |||
| 558 | int | ||
| 559 | mesgsave(Message *m, char *s) | ||
| 560 | { | ||
| 561 | int ofd, n, k, ret; | ||
| 562 | char *t, *raw, *unixheader, *all; | ||
| 563 | |||
| 564 | t = estrstrdup(mbox.name, m->name); | ||
| 565 | raw = readfile(t, "raw", &n); | ||
| 566 | unixheader = readfile(t, "unixheader", &k); | ||
| 567 | if(raw==nil || unixheader==nil){ | ||
| 568 | fprint(2, "Mail: can't read %s: %r\n", t); | ||
| 569 | free(t); | ||
| 570 | return 0; | ||
| 571 | } | ||
| 572 | free(t); | ||
| 573 | |||
| 574 | all = emalloc(n+k+1); | ||
| 575 | memmove(all, unixheader, k); | ||
| 576 | memmove(all+k, raw, n); | ||
| 577 | memmove(all+k+n, "\n", 1); | ||
| 578 | n = k+n+1; | ||
| 579 | free(unixheader); | ||
| 580 | free(raw); | ||
| 581 | ret = 1; | ||
| 582 | s = estrdup(s); | ||
| 583 | if(s[0] != '/') | ||
| 584 | s = egrow(estrdup(mailboxdir), "/", s); | ||
| 585 | ofd = open(s, OWRITE); | ||
| 586 | if(ofd < 0){ | ||
| 587 | fprint(2, "Mail: can't open %s: %r\n", s); | ||
| 588 | ret = 0; | ||
| 589 | }else if(seek(ofd, 0LL, 2)<0 || write(ofd, all, n)!=n){ | ||
| 590 | fprint(2, "Mail: save failed: can't write %s: %r\n", s); | ||
| 591 | ret = 0; | ||
| 592 | } | ||
| 593 | free(all); | ||
| 594 | close(ofd); | ||
| 595 | free(s); | ||
| 596 | return ret; | ||
| 597 | } | ||
| 598 | |||
| 599 | int | ||
| 600 | mesgcommand(Message *m, char *cmd) | ||
| 601 | { | ||
| 602 | char *s; | ||
| 603 | char *args[10]; | ||
| 604 | int ok, ret, nargs; | ||
| 605 | |||
| 606 | s = cmd; | ||
| 607 | ret = 1; | ||
| 608 | nargs = tokenize(s, args, nelem(args)); | ||
| 609 | if(nargs == 0) | ||
| 610 | return 0; | ||
| 611 | if(strcmp(args[0], "Post") == 0){ | ||
| 612 | mesgsend(m); | ||
| 613 | goto Return; | ||
| 614 | } | ||
| 615 | if(strncmp(args[0], "Save", 4) == 0){ | ||
| 616 | if(m->isreply) | ||
| 617 | goto Return; | ||
| 618 | s = estrdup("\t[saved"); | ||
| 619 | if(nargs==1 || strcmp(args[1], "")==0){ | ||
| 620 | ok = mesgsave(m, "stored"); | ||
| 621 | }else{ | ||
| 622 | ok = mesgsave(m, args[1]); | ||
| 623 | s = eappend(s, " ", args[1]); | ||
| 624 | } | ||
| 625 | if(ok){ | ||
| 626 | s = egrow(s, "]", nil); | ||
| 627 | mesgmenumark(mbox.w, m->name, s); | ||
| 628 | } | ||
| 629 | free(s); | ||
| 630 | goto Return; | ||
| 631 | } | ||
| 632 | if(strcmp(args[0], "Reply")==0){ | ||
| 633 | if(nargs>=2 && strcmp(args[1], "all")==0) | ||
| 634 | mkreply(m, "Replyall", nil, nil, nil); | ||
| 635 | else | ||
| 636 | mkreply(m, "Reply", nil, nil, nil); | ||
| 637 | goto Return; | ||
| 638 | } | ||
| 639 | if(strcmp(args[0], "Q") == 0){ | ||
| 640 | s = winselection(m->w); /* will be freed by mkreply */ | ||
| 641 | if(nargs>=3 && strcmp(args[1], "Reply")==0 && strcmp(args[2], "all")==0) | ||
| 642 | mkreply(m, "QReplyall", nil, nil, s); | ||
| 643 | else | ||
| 644 | mkreply(m, "QReply", nil, nil, s); | ||
| 645 | goto Return; | ||
| 646 | } | ||
| 647 | if(strcmp(args[0], "Del") == 0){ | ||
| 648 | if(windel(m->w, 0)){ | ||
| 649 | chanfree(m->w->cevent); | ||
| 650 | free(m->w); | ||
| 651 | m->w = nil; | ||
| 652 | if(m->isreply) | ||
| 653 | delreply(m); | ||
| 654 | else{ | ||
| 655 | m->opened = 0; | ||
| 656 | m->tagposted = 0; | ||
| 657 | } | ||
| 658 | free(cmd); | ||
| 659 | threadexits(nil); | ||
| 660 | } | ||
| 661 | goto Return; | ||
| 662 | } | ||
| 663 | if(strcmp(args[0], "Delmesg") == 0){ | ||
| 664 | if(!m->isreply){ | ||
| 665 | mesgmenumarkdel(wbox, &mbox, m, 1); | ||
| 666 | free(cmd); /* mesgcommand might not return */ | ||
| 667 | mesgcommand(m, estrdup("Del")); | ||
| 668 | return 1; | ||
| 669 | } | ||
| 670 | goto Return; | ||
| 671 | } | ||
| 672 | if(strcmp(args[0], "UnDelmesg") == 0){ | ||
| 673 | if(!m->isreply && m->deleted) | ||
| 674 | mesgmenumarkundel(wbox, &mbox, m); | ||
| 675 | goto Return; | ||
| 676 | } | ||
| 677 | // if(strcmp(args[0], "Headers") == 0){ | ||
| 678 | // m->showheaders(); | ||
| 679 | // return True; | ||
| 680 | // } | ||
| 681 | |||
| 682 | ret = 0; | ||
| 683 | |||
| 684 | Return: | ||
| 685 | free(cmd); | ||
| 686 | return ret; | ||
| 687 | } | ||
| 688 | |||
| 689 | void | ||
| 690 | mesgtagpost(Message *m) | ||
| 691 | { | ||
| 692 | if(m->tagposted) | ||
| 693 | return; | ||
| 694 | wintagwrite(m->w, " Post", 5); | ||
| 695 | m->tagposted = 1; | ||
| 696 | } | ||
| 697 | |||
| 698 | /* need to expand selection more than default word */ | ||
| 699 | #pragma varargck argpos eval 2 | ||
| 700 | |||
| 701 | long | ||
| 702 | eval(Window *w, char *s, ...) | ||
| 703 | { | ||
| 704 | char buf[64]; | ||
| 705 | va_list arg; | ||
| 706 | |||
| 707 | va_start(arg, s); | ||
| 708 | vsnprint(buf, sizeof buf, s, arg); | ||
| 709 | va_end(arg); | ||
| 710 | |||
| 711 | if(winsetaddr(w, buf, 1)==0) | ||
| 712 | return -1; | ||
| 713 | |||
| 714 | if(pread(w->addr, buf, 24, 0) != 24) | ||
| 715 | return -1; | ||
| 716 | return strtol(buf, 0, 10); | ||
| 717 | } | ||
| 718 | |||
| 719 | int | ||
| 720 | isemail(char *s) | ||
| 721 | { | ||
| 722 | int nat; | ||
| 723 | |||
| 724 | nat = 0; | ||
| 725 | for(; *s; s++) | ||
| 726 | if(*s == '@') | ||
| 727 | nat++; | ||
| 728 | else if(!isalpha(*s) && !isdigit(*s) && !strchr("_.-+/", *s)) | ||
| 729 | return 0; | ||
| 730 | return nat==1; | ||
| 731 | } | ||
| 732 | |||
| 733 | char addrdelim[] = "/[ \t\\n<>()\\[\\]]/"; | ||
| 734 | char* | ||
| 735 | expandaddr(Window *w, Event *e) | ||
| 736 | { | ||
| 737 | char *s; | ||
| 738 | long q0, q1; | ||
| 739 | |||
| 740 | if(e->q0 != e->q1) /* cannot happen */ | ||
| 741 | return nil; | ||
| 742 | |||
| 743 | q0 = eval(w, "#%d-%s", e->q0, addrdelim); | ||
| 744 | if(q0 == -1) /* bad char not found */ | ||
| 745 | q0 = 0; | ||
| 746 | else /* increment past bad char */ | ||
| 747 | q0++; | ||
| 748 | |||
| 749 | q1 = eval(w, "#%d+%s", e->q0, addrdelim); | ||
| 750 | if(q1 < 0){ | ||
| 751 | q1 = eval(w, "$"); | ||
| 752 | if(q1 < 0) | ||
| 753 | return nil; | ||
| 754 | } | ||
| 755 | if(q0 >= q1) | ||
| 756 | return nil; | ||
| 757 | s = emalloc((q1-q0)*UTFmax+1); | ||
| 758 | winread(w, q0, q1, s); | ||
| 759 | return s; | ||
| 760 | } | ||
| 761 | |||
| 762 | int | ||
| 763 | replytoaddr(Window *w, Message *m, Event *e, char *s) | ||
| 764 | { | ||
| 765 | int did; | ||
| 766 | char *buf; | ||
| 767 | Plumbmsg *pm; | ||
| 768 | |||
| 769 | buf = nil; | ||
| 770 | did = 0; | ||
| 771 | if(e->flag & 2){ | ||
| 772 | /* autoexpanded; use our own bigger expansion */ | ||
| 773 | buf = expandaddr(w, e); | ||
| 774 | if(buf == nil) | ||
| 775 | return 0; | ||
| 776 | s = buf; | ||
| 777 | } | ||
| 778 | if(isemail(s)){ | ||
| 779 | did = 1; | ||
| 780 | pm = emalloc(sizeof(Plumbmsg)); | ||
| 781 | pm->src = estrdup("Mail"); | ||
| 782 | pm->dst = estrdup("sendmail"); | ||
| 783 | pm->data = estrdup(s); | ||
| 784 | pm->ndata = -1; | ||
| 785 | if(m->subject && m->subject[0]){ | ||
| 786 | pm->attr = emalloc(sizeof(Plumbattr)); | ||
| 787 | pm->attr->name = estrdup("Subject"); | ||
| 788 | if(tolower(m->subject[0]) != 'r' || tolower(m->subject[1]) != 'e' || m->subject[2] != ':') | ||
| 789 | pm->attr->value = estrstrdup("Re: ", m->subject); | ||
| 790 | else | ||
| 791 | pm->attr->value = estrdup(m->subject); | ||
| 792 | pm->attr->next = nil; | ||
| 793 | } | ||
| 794 | if(plumbsend(plumbsendfd, pm) < 0) | ||
| 795 | fprint(2, "error writing plumb message: %r\n"); | ||
| 796 | plumbfree(pm); | ||
| 797 | } | ||
| 798 | free(buf); | ||
| 799 | return did; | ||
| 800 | } | ||
| 801 | |||
| 802 | |||
| 803 | void | ||
| 804 | mesgctl(void *v) | ||
| 805 | { | ||
| 806 | Message *m; | ||
| 807 | Window *w; | ||
| 808 | Event *e, *eq, *e2, *ea; | ||
| 809 | int na, nopen, i, j; | ||
| 810 | char *os, *s, *t, *buf; | ||
| 811 | |||
| 812 | m = v; | ||
| 813 | w = m->w; | ||
| 814 | threadsetname("mesgctl"); | ||
| 815 | proccreate(wineventproc, w, STACK); | ||
| 816 | for(;;){ | ||
| 817 | e = recvp(w->cevent); | ||
| 818 | switch(e->c1){ | ||
| 819 | default: | ||
| 820 | Unk: | ||
| 821 | print("unknown message %c%c\n", e->c1, e->c2); | ||
| 822 | break; | ||
| 823 | |||
| 824 | case 'E': /* write to body; can't affect us */ | ||
| 825 | break; | ||
| 826 | |||
| 827 | case 'F': /* generated by our actions; ignore */ | ||
| 828 | break; | ||
| 829 | |||
| 830 | case 'K': /* type away; we don't care */ | ||
| 831 | case 'M': | ||
| 832 | switch(e->c2){ | ||
| 833 | case 'x': /* mouse only */ | ||
| 834 | case 'X': | ||
| 835 | ea = nil; | ||
| 836 | eq = e; | ||
| 837 | if(e->flag & 2){ | ||
| 838 | e2 = recvp(w->cevent); | ||
| 839 | eq = e2; | ||
| 840 | } | ||
| 841 | if(e->flag & 8){ | ||
| 842 | ea = recvp(w->cevent); | ||
| 843 | recvp(w->cevent); | ||
| 844 | na = ea->nb; | ||
| 845 | }else | ||
| 846 | na = 0; | ||
| 847 | if(eq->q1>eq->q0 && eq->nb==0){ | ||
| 848 | s = emalloc((eq->q1-eq->q0)*UTFmax+1); | ||
| 849 | winread(w, eq->q0, eq->q1, s); | ||
| 850 | }else | ||
| 851 | s = estrdup(eq->b); | ||
| 852 | if(na){ | ||
| 853 | t = emalloc(strlen(s)+1+na+1); | ||
| 854 | sprint(t, "%s %s", s, ea->b); | ||
| 855 | free(s); | ||
| 856 | s = t; | ||
| 857 | } | ||
| 858 | if(!mesgcommand(m, s)) /* send it back */ | ||
| 859 | winwriteevent(w, e); | ||
| 860 | break; | ||
| 861 | |||
| 862 | case 'l': /* mouse only */ | ||
| 863 | case 'L': | ||
| 864 | buf = nil; | ||
| 865 | eq = e; | ||
| 866 | if(e->flag & 2){ | ||
| 867 | e2 = recvp(w->cevent); | ||
| 868 | eq = e2; | ||
| 869 | } | ||
| 870 | s = eq->b; | ||
| 871 | if(eq->q1>eq->q0 && eq->nb==0){ | ||
| 872 | buf = emalloc((eq->q1-eq->q0)*UTFmax+1); | ||
| 873 | winread(w, eq->q0, eq->q1, buf); | ||
| 874 | s = buf; | ||
| 875 | } | ||
| 876 | os = s; | ||
| 877 | nopen = 0; | ||
| 878 | do{ | ||
| 879 | /* skip mail box name if present */ | ||
| 880 | if(strncmp(s, mbox.name, strlen(mbox.name)) == 0) | ||
| 881 | s += strlen(mbox.name); | ||
| 882 | if(strstr(s, "body") != nil){ | ||
| 883 | /* strip any known extensions */ | ||
| 884 | for(i=0; exts[i].ext!=nil; i++){ | ||
| 885 | j = strlen(exts[i].ext); | ||
| 886 | if(strlen(s)>j && strcmp(s+strlen(s)-j, exts[i].ext)==0){ | ||
| 887 | s[strlen(s)-j] = '\0'; | ||
| 888 | break; | ||
| 889 | } | ||
| 890 | } | ||
| 891 | if(strlen(s)>5 && strcmp(s+strlen(s)-5, "/body")==0) | ||
| 892 | s[strlen(s)-4] = '\0'; /* leave / in place */ | ||
| 893 | } | ||
| 894 | nopen += mesgopen(&mbox, mbox.name, s, m, 0, nil); | ||
| 895 | while(*s!=0 && *s++!='\n') | ||
| 896 | ; | ||
| 897 | }while(*s); | ||
| 898 | if(nopen == 0 && e->c1 == 'L') | ||
| 899 | nopen += replytoaddr(w, m, e, os); | ||
| 900 | if(nopen == 0) | ||
| 901 | winwriteevent(w, e); | ||
| 902 | free(buf); | ||
| 903 | break; | ||
| 904 | |||
| 905 | case 'I': /* modify away; we don't care */ | ||
| 906 | case 'D': | ||
| 907 | mesgtagpost(m); | ||
| 908 | /* fall through */ | ||
| 909 | case 'd': | ||
| 910 | case 'i': | ||
| 911 | break; | ||
| 912 | |||
| 913 | default: | ||
| 914 | goto Unk; | ||
| 915 | } | ||
| 916 | } | ||
| 917 | } | ||
| 918 | } | ||
| 919 | |||
| 920 | void | ||
| 921 | mesgline(Message *m, char *header, char *value) | ||
| 922 | { | ||
| 923 | if(strlen(value) > 0) | ||
| 924 | Bprint(m->w->body, "%s: %s\n", header, value); | ||
| 925 | } | ||
| 926 | |||
| 927 | int | ||
| 928 | isprintable(char *type) | ||
| 929 | { | ||
| 930 | int i; | ||
| 931 | |||
| 932 | for(i=0; goodtypes[i]!=nil; i++) | ||
| 933 | if(strcmp(type, goodtypes[i])==0) | ||
| 934 | return 1; | ||
| 935 | return 0; | ||
| 936 | } | ||
| 937 | |||
| 938 | char* | ||
| 939 | ext(char *type) | ||
| 940 | { | ||
| 941 | int i; | ||
| 942 | |||
| 943 | for(i=0; exts[i].type!=nil; i++) | ||
| 944 | if(strcmp(type, exts[i].type)==0) | ||
| 945 | return exts[i].ext; | ||
| 946 | return ""; | ||
| 947 | } | ||
| 948 | |||
| 949 | void | ||
| 950 | mimedisplay(Message *m, char *name, char *rootdir, Window *w, int fileonly) | ||
| 951 | { | ||
| 952 | char *dest; | ||
| 953 | |||
| 954 | if(strcmp(m->disposition, "file")==0 || strlen(m->filename)!=0){ | ||
| 955 | if(strlen(m->filename) == 0){ | ||
| 956 | dest = estrdup(m->name); | ||
| 957 | dest[strlen(dest)-1] = '\0'; | ||
| 958 | }else | ||
| 959 | dest = estrdup(m->filename); | ||
| 960 | if(m->filename[0] != '/') | ||
| 961 | dest = egrow(estrdup(home), "/", dest); | ||
| 962 | Bprint(w->body, "\tcp %s%sbody%s %q\n", rootdir, name, ext(m->type), dest); | ||
| 963 | free(dest); | ||
| 964 | }else if(!fileonly) | ||
| 965 | Bprint(w->body, "\tfile is %s%sbody%s\n", rootdir, name, ext(m->type)); | ||
| 966 | } | ||
| 967 | |||
| 968 | void | ||
| 969 | printheader(char *dir, Biobuf *b, char **okheaders) | ||
| 970 | { | ||
| 971 | char *s; | ||
| 972 | char *lines[100]; | ||
| 973 | int i, j, n; | ||
| 974 | |||
| 975 | s = readfile(dir, "header", nil); | ||
| 976 | if(s == nil) | ||
| 977 | return; | ||
| 978 | n = getfields(s, lines, nelem(lines), 0, "\n"); | ||
| 979 | for(i=0; i<n; i++) | ||
| 980 | for(j=0; okheaders[j]; j++) | ||
| 981 | if(cistrncmp(lines[i], okheaders[j], strlen(okheaders[j])) == 0) | ||
| 982 | Bprint(b, "%s\n", lines[i]); | ||
| 983 | free(s); | ||
| 984 | } | ||
| 985 | |||
| 986 | void | ||
| 987 | mesgload(Message *m, char *rootdir, char *file, Window *w) | ||
| 988 | { | ||
| 989 | char *s, *subdir, *name, *dir; | ||
| 990 | Message *mp, *thisone; | ||
| 991 | int n; | ||
| 992 | |||
| 993 | dir = estrstrdup(rootdir, file); | ||
| 994 | |||
| 995 | if(strcmp(m->type, "message/rfc822") != 0){ /* suppress headers of envelopes */ | ||
| 996 | if(strlen(m->from) > 0){ | ||
| 997 | Bprint(w->body, "From: %s\n", m->from); | ||
| 998 | mesgline(m, "Date", m->date); | ||
| 999 | mesgline(m, "To", m->to); | ||
| 1000 | mesgline(m, "CC", m->cc); | ||
| 1001 | mesgline(m, "Subject", m->subject); | ||
| 1002 | printheader(dir, w->body, extraheaders); | ||
| 1003 | }else{ | ||
| 1004 | printheader(dir, w->body, okheaders); | ||
| 1005 | printheader(dir, w->body, extraheaders); | ||
| 1006 | } | ||
| 1007 | Bprint(w->body, "\n"); | ||
| 1008 | } | ||
| 1009 | |||
| 1010 | if(m->level == 1 && m->recursed == 0){ | ||
| 1011 | m->recursed = 1; | ||
| 1012 | readmbox(m, rootdir, m->name); | ||
| 1013 | } | ||
| 1014 | if(m->head == nil){ /* single part message */ | ||
| 1015 | if(strcmp(m->type, "text")==0 || strncmp(m->type, "text/", 5)==0){ | ||
| 1016 | mimedisplay(m, m->name, rootdir, w, 1); | ||
| 1017 | s = readbody(m->type, dir, &n); | ||
| 1018 | winwritebody(w, s, n); | ||
| 1019 | free(s); | ||
| 1020 | }else | ||
| 1021 | mimedisplay(m, m->name, rootdir, w, 0); | ||
| 1022 | }else{ | ||
| 1023 | /* multi-part message, either multipart/* or message/rfc822 */ | ||
| 1024 | thisone = nil; | ||
| 1025 | if(strcmp(m->type, "multipart/alternative") == 0){ | ||
| 1026 | thisone = m->head; /* in case we can't find a good one */ | ||
| 1027 | for(mp=m->head; mp!=nil; mp=mp->next) | ||
| 1028 | if(isprintable(mp->type)){ | ||
| 1029 | thisone = mp; | ||
| 1030 | break; | ||
| 1031 | } | ||
| 1032 | } | ||
| 1033 | for(mp=m->head; mp!=nil; mp=mp->next){ | ||
| 1034 | if(thisone!=nil && mp!=thisone) | ||
| 1035 | continue; | ||
| 1036 | subdir = estrstrdup(dir, mp->name); | ||
| 1037 | name = estrstrdup(file, mp->name); | ||
| 1038 | /* skip first element in name because it's already in window name */ | ||
| 1039 | if(mp != m->head) | ||
| 1040 | Bprint(w->body, "\n===> %s (%s) [%s]\n", strchr(name, '/')+1, mp->type, mp->disposition); | ||
| 1041 | if(strcmp(mp->type, "text")==0 || strncmp(mp->type, "text/", 5)==0){ | ||
| 1042 | mimedisplay(mp, name, rootdir, w, 1); | ||
| 1043 | printheader(subdir, w->body, okheaders); | ||
| 1044 | printheader(subdir, w->body, extraheaders); | ||
| 1045 | winwritebody(w, "\n", 1); | ||
| 1046 | s = readbody(mp->type, subdir, &n); | ||
| 1047 | winwritebody(w, s, n); | ||
| 1048 | free(s); | ||
| 1049 | }else{ | ||
| 1050 | if(strncmp(mp->type, "multipart/", 10)==0 || strcmp(mp->type, "message/rfc822")==0){ | ||
| 1051 | mp->w = w; | ||
| 1052 | mesgload(mp, rootdir, name, w); | ||
| 1053 | mp->w = nil; | ||
| 1054 | }else | ||
| 1055 | mimedisplay(mp, name, rootdir, w, 0); | ||
| 1056 | } | ||
| 1057 | free(name); | ||
| 1058 | free(subdir); | ||
| 1059 | } | ||
| 1060 | } | ||
| 1061 | free(dir); | ||
| 1062 | } | ||
| 1063 | |||
| 1064 | int | ||
| 1065 | tokenizec(char *str, char **args, int max, char *splitc) | ||
| 1066 | { | ||
| 1067 | int na; | ||
| 1068 | int intok = 0; | ||
| 1069 | |||
| 1070 | if(max <= 0) | ||
| 1071 | return 0; | ||
| 1072 | for(na=0; *str != '\0';str++){ | ||
| 1073 | if(strchr(splitc, *str) == nil){ | ||
| 1074 | if(intok) | ||
| 1075 | continue; | ||
| 1076 | args[na++] = str; | ||
| 1077 | intok = 1; | ||
| 1078 | }else{ | ||
| 1079 | /* it's a separator/skip character */ | ||
| 1080 | *str = '\0'; | ||
| 1081 | if(intok){ | ||
| 1082 | intok = 0; | ||
| 1083 | if(na >= max) | ||
| 1084 | break; | ||
| 1085 | } | ||
| 1086 | } | ||
| 1087 | } | ||
| 1088 | return na; | ||
| 1089 | } | ||
| 1090 | |||
| 1091 | Message* | ||
| 1092 | mesglookup(Message *mbox, char *name, char *digest) | ||
| 1093 | { | ||
| 1094 | int n; | ||
| 1095 | Message *m; | ||
| 1096 | char *t; | ||
| 1097 | |||
| 1098 | if(digest){ | ||
| 1099 | /* can find exactly */ | ||
| 1100 | for(m=mbox->head; m!=nil; m=m->next) | ||
| 1101 | if(strcmp(digest, m->digest) == 0) | ||
| 1102 | break; | ||
| 1103 | return m; | ||
| 1104 | } | ||
| 1105 | |||
| 1106 | n = strlen(name); | ||
| 1107 | if(n == 0) | ||
| 1108 | return nil; | ||
| 1109 | if(name[n-1] == '/') | ||
| 1110 | t = estrdup(name); | ||
| 1111 | else | ||
| 1112 | t = estrstrdup(name, "/"); | ||
| 1113 | for(m=mbox->head; m!=nil; m=m->next) | ||
| 1114 | if(strcmp(t, m->name) == 0) | ||
| 1115 | break; | ||
| 1116 | free(t); | ||
| 1117 | return m; | ||
| 1118 | } | ||
| 1119 | |||
| 1120 | /* | ||
| 1121 | * Find plumb port, knowing type is text, given file name (by extension) | ||
| 1122 | */ | ||
| 1123 | int | ||
| 1124 | plumbportbysuffix(char *file) | ||
| 1125 | { | ||
| 1126 | char *suf; | ||
| 1127 | int i, nsuf, nfile; | ||
| 1128 | |||
| 1129 | nfile = strlen(file); | ||
| 1130 | for(i=0; ports[i].type!=nil; i++){ | ||
| 1131 | suf = ports[i].suffix; | ||
| 1132 | nsuf = strlen(suf); | ||
| 1133 | if(nfile > nsuf) | ||
| 1134 | if(cistrncmp(file+nfile-nsuf, suf, nsuf) == 0) | ||
| 1135 | return i; | ||
| 1136 | } | ||
| 1137 | return 0; | ||
| 1138 | } | ||
| 1139 | |||
| 1140 | /* | ||
| 1141 | * Find plumb port using type and file name (by extension) | ||
| 1142 | */ | ||
| 1143 | int | ||
| 1144 | plumbport(char *type, char *file) | ||
| 1145 | { | ||
| 1146 | int i; | ||
| 1147 | |||
| 1148 | for(i=0; ports[i].type!=nil; i++) | ||
| 1149 | if(strncmp(type, ports[i].type, strlen(ports[i].type)) == 0) | ||
| 1150 | return i; | ||
| 1151 | /* see if it's a text type */ | ||
| 1152 | for(i=0; goodtypes[i]!=nil; i++) | ||
| 1153 | if(strncmp(type, goodtypes[i], strlen(goodtypes[i])) == 0) | ||
| 1154 | return plumbportbysuffix(file); | ||
| 1155 | return -1; | ||
| 1156 | } | ||
| 1157 | |||
| 1158 | void | ||
| 1159 | plumb(Message *m, char *dir) | ||
| 1160 | { | ||
| 1161 | int i; | ||
| 1162 | char *port; | ||
| 1163 | Plumbmsg *pm; | ||
| 1164 | |||
| 1165 | if(strlen(m->type) == 0) | ||
| 1166 | return; | ||
| 1167 | i = plumbport(m->type, m->filename); | ||
| 1168 | if(i < 0) | ||
| 1169 | fprint(2, "can't find destination for message subpart\n"); | ||
| 1170 | else{ | ||
| 1171 | port = ports[i].port; | ||
| 1172 | pm = emalloc(sizeof(Plumbmsg)); | ||
| 1173 | pm->src = estrdup("Mail"); | ||
| 1174 | if(port) | ||
| 1175 | pm->dst = estrdup(port); | ||
| 1176 | else | ||
| 1177 | pm->dst = nil; | ||
| 1178 | pm->wdir = nil; | ||
| 1179 | pm->type = estrdup("text"); | ||
| 1180 | pm->ndata = -1; | ||
| 1181 | pm->data = estrstrdup(dir, "body"); | ||
| 1182 | pm->data = eappend(pm->data, "", ports[i].suffix); | ||
| 1183 | if(plumbsend(plumbsendfd, pm) < 0) | ||
| 1184 | fprint(2, "error writing plumb message: %r\n"); | ||
| 1185 | plumbfree(pm); | ||
| 1186 | } | ||
| 1187 | } | ||
| 1188 | |||
| 1189 | int | ||
| 1190 | mesgopen(Message *mbox, char *dir, char *s, Message *mesg, int plumbed, char *digest) | ||
| 1191 | { | ||
| 1192 | char *t, *u, *v; | ||
| 1193 | Message *m; | ||
| 1194 | char *direlem[10]; | ||
| 1195 | int i, ndirelem, reuse; | ||
| 1196 | |||
| 1197 | /* find white-space-delimited first word */ | ||
| 1198 | for(t=s; *t!='\0' && !isspace(*t); t++) | ||
| 1199 | ; | ||
| 1200 | u = emalloc(t-s+1); | ||
| 1201 | memmove(u, s, t-s); | ||
| 1202 | /* separate it on slashes */ | ||
| 1203 | ndirelem = tokenizec(u, direlem, nelem(direlem), "/"); | ||
| 1204 | if(ndirelem <= 0){ | ||
| 1205 | Error: | ||
| 1206 | free(u); | ||
| 1207 | return 0; | ||
| 1208 | } | ||
| 1209 | if(plumbed){ | ||
| 1210 | write(wctlfd, "top", 3); | ||
| 1211 | write(wctlfd, "current", 7); | ||
| 1212 | } | ||
| 1213 | /* open window for message */ | ||
| 1214 | m = mesglookup(mbox, direlem[0], digest); | ||
| 1215 | if(m == nil) | ||
| 1216 | goto Error; | ||
| 1217 | if(mesg!=nil && m!=mesg) /* string looked like subpart but isn't part of this message */ | ||
| 1218 | goto Error; | ||
| 1219 | if(m->opened == 0){ | ||
| 1220 | if(m->w == nil){ | ||
| 1221 | reuse = 0; | ||
| 1222 | m->w = newwindow(); | ||
| 1223 | }else{ | ||
| 1224 | reuse = 1; | ||
| 1225 | /* re-use existing window */ | ||
| 1226 | if(winsetaddr(m->w, "0,$", 1)){ | ||
| 1227 | if(m->w->data < 0) | ||
| 1228 | m->w->data = winopenfile(m->w, "data"); | ||
| 1229 | write(m->w->data, "", 0); | ||
| 1230 | } | ||
| 1231 | } | ||
| 1232 | v = estrstrdup(mbox->name, m->name); | ||
| 1233 | winname(m->w, v); | ||
| 1234 | free(v); | ||
| 1235 | if(!reuse){ | ||
| 1236 | if(m->deleted) | ||
| 1237 | wintagwrite(m->w, "Q Reply all UnDelmesg Save ", 2+6+4+10+5); | ||
| 1238 | else | ||
| 1239 | wintagwrite(m->w, "Q Reply all Delmesg Save ", 2+6+4+8+5); | ||
| 1240 | } | ||
| 1241 | threadcreate(mesgctl, m, STACK); | ||
| 1242 | winopenbody(m->w, OWRITE); | ||
| 1243 | mesgload(m, dir, m->name, m->w); | ||
| 1244 | winclosebody(m->w); | ||
| 1245 | winclean(m->w); | ||
| 1246 | m->opened = 1; | ||
| 1247 | if(ndirelem == 1){ | ||
| 1248 | free(u); | ||
| 1249 | return 1; | ||
| 1250 | } | ||
| 1251 | } | ||
| 1252 | if(ndirelem == 1 && plumbport(m->type, m->filename) <= 0){ | ||
| 1253 | /* make sure dot is visible */ | ||
| 1254 | ctlprint(m->w->ctl, "show\n"); | ||
| 1255 | return 0; | ||
| 1256 | } | ||
| 1257 | /* walk to subpart */ | ||
| 1258 | dir = estrstrdup(dir, m->name); | ||
| 1259 | for(i=1; i<ndirelem; i++){ | ||
| 1260 | m = mesglookup(m, direlem[i], digest); | ||
| 1261 | if(m == nil) | ||
| 1262 | break; | ||
| 1263 | dir = egrow(dir, m->name, nil); | ||
| 1264 | } | ||
| 1265 | if(m != nil && plumbport(m->type, m->filename) > 0) | ||
| 1266 | plumb(m, dir); | ||
| 1267 | free(dir); | ||
| 1268 | free(u); | ||
| 1269 | return 1; | ||
| 1270 | } | ||
| 1271 | |||
| 1272 | void | ||
| 1273 | rewritembox(Window *w, Message *mbox) | ||
| 1274 | { | ||
| 1275 | Message *m, *next; | ||
| 1276 | char *deletestr, *t; | ||
| 1277 | int nopen; | ||
| 1278 | |||
| 1279 | deletestr = estrstrdup("delete ", fsname); | ||
| 1280 | |||
| 1281 | nopen = 0; | ||
| 1282 | for(m=mbox->head; m!=nil; m=next){ | ||
| 1283 | next = m->next; | ||
| 1284 | if(m->deleted == 0) | ||
| 1285 | continue; | ||
| 1286 | if(m->opened){ | ||
| 1287 | nopen++; | ||
| 1288 | continue; | ||
| 1289 | } | ||
| 1290 | if(m->writebackdel){ | ||
| 1291 | /* messages deleted by plumb message are not removed again */ | ||
| 1292 | t = estrdup(m->name); | ||
| 1293 | if(strlen(t) > 0) | ||
| 1294 | t[strlen(t)-1] = '\0'; | ||
| 1295 | deletestr = egrow(deletestr, " ", t); | ||
| 1296 | } | ||
| 1297 | mesgmenudel(w, mbox, m); | ||
| 1298 | mesgdel(mbox, m); | ||
| 1299 | } | ||
| 1300 | if(write(mbox->ctlfd, deletestr, strlen(deletestr)) < 0) | ||
| 1301 | fprint(2, "Mail: warning: error removing mail message files: %r\n"); | ||
| 1302 | free(deletestr); | ||
| 1303 | winselect(w, "0", 0); | ||
| 1304 | if(nopen == 0) | ||
| 1305 | winclean(w); | ||
| 1306 | mbox->dirty = 0; | ||
| 1307 | } | ||
| 1308 | |||
| 1309 | /* name is a full file name, but it might not belong to us */ | ||
| 1310 | Message* | ||
| 1311 | mesglookupfile(Message *mbox, char *name, char *digest) | ||
| 1312 | { | ||
| 1313 | int k, n; | ||
| 1314 | |||
| 1315 | k = strlen(name); | ||
| 1316 | n = strlen(mbox->name); | ||
| 1317 | if(k==0 || strncmp(name, mbox->name, n) != 0){ | ||
| 1318 | // fprint(2, "Mail: message %s not in this mailbox\n", name); | ||
| 1319 | return nil; | ||
| 1320 | } | ||
| 1321 | return mesglookup(mbox, name+n, digest); | ||
| 1322 | } | ||
| @@ -0,0 +1,30 @@ | |||
| 1 | </$objtype/mkfile | ||
| 2 | |||
| 3 | TARG=Mail | ||
| 4 | OFILES=\ | ||
| 5 | html.$O\ | ||
| 6 | mail.$O\ | ||
| 7 | mesg.$O\ | ||
| 8 | reply.$O\ | ||
| 9 | util.$O\ | ||
| 10 | win.$O | ||
| 11 | |||
| 12 | HFILES=dat.h | ||
| 13 | LIB= | ||
| 14 | |||
| 15 | BIN=/acme/bin/$objtype | ||
| 16 | |||
| 17 | UPDATE=\ | ||
| 18 | mkfile\ | ||
| 19 | $HFILES\ | ||
| 20 | ${OFILES:%.$O=%.c}\ | ||
| 21 | |||
| 22 | </sys/src/cmd/mkone | ||
| 23 | |||
| 24 | $O.out: $OFILES | ||
| 25 | $LD -o $target $LDFLAGS $OFILES | ||
| 26 | |||
| 27 | syms:V: | ||
| 28 | 8c -a mail.c >syms | ||
| 29 | 8c -aa mesg.c reply.c util.c win.c >>syms | ||
| 30 | |||
Binary file not shown.
Binary file not shown.
| @@ -0,0 +1,567 @@ | |||
| 1 | #include <u.h> | ||
| 2 | #include <libc.h> | ||
| 3 | #include <bio.h> | ||
| 4 | #include <thread.h> | ||
| 5 | #include <ctype.h> | ||
| 6 | #include <plumb.h> | ||
| 7 | #include "dat.h" | ||
| 8 | |||
| 9 | static int replyid; | ||
| 10 | |||
| 11 | int | ||
| 12 | quote(Message *m, Biobuf *b, char *dir, char *quotetext) | ||
| 13 | { | ||
| 14 | char *body, *type; | ||
| 15 | int i, n, nlines; | ||
| 16 | char **lines; | ||
| 17 | |||
| 18 | if(quotetext){ | ||
| 19 | body = quotetext; | ||
| 20 | n = strlen(body); | ||
| 21 | type = nil; | ||
| 22 | }else{ | ||
| 23 | /* look for first textual component to quote */ | ||
| 24 | type = readfile(dir, "type", &n); | ||
| 25 | if(type == nil){ | ||
| 26 | print("no type in %s\n", dir); | ||
| 27 | return 0; | ||
| 28 | } | ||
| 29 | if(strncmp(type, "multipart/", 10)==0 || strncmp(type, "message/", 8)==0){ | ||
| 30 | dir = estrstrdup(dir, "1/"); | ||
| 31 | if(quote(m, b, dir, nil)){ | ||
| 32 | free(type); | ||
| 33 | free(dir); | ||
| 34 | return 1; | ||
| 35 | } | ||
| 36 | free(dir); | ||
| 37 | } | ||
| 38 | if(strncmp(type, "text", 4) != 0){ | ||
| 39 | free(type); | ||
| 40 | return 0; | ||
| 41 | } | ||
| 42 | body = readbody(m->type, dir, &n); | ||
| 43 | if(body == nil) | ||
| 44 | return 0; | ||
| 45 | } | ||
| 46 | nlines = 0; | ||
| 47 | for(i=0; i<n; i++) | ||
| 48 | if(body[i] == '\n') | ||
| 49 | nlines++; | ||
| 50 | nlines++; | ||
| 51 | lines = emalloc(nlines*sizeof(char*)); | ||
| 52 | nlines = getfields(body, lines, nlines, 0, "\n"); | ||
| 53 | /* delete leading and trailing blank lines */ | ||
| 54 | i = 0; | ||
| 55 | while(i<nlines && lines[i][0]=='\0') | ||
| 56 | i++; | ||
| 57 | while(i<nlines && lines[nlines-1][0]=='\0') | ||
| 58 | nlines--; | ||
| 59 | while(i < nlines){ | ||
| 60 | Bprint(b, ">%s%s\n", lines[i][0]=='>'? "" : " ", lines[i]); | ||
| 61 | i++; | ||
| 62 | } | ||
| 63 | free(lines); | ||
| 64 | free(body); /* will free quotetext if non-nil */ | ||
| 65 | free(type); | ||
| 66 | return 1; | ||
| 67 | } | ||
| 68 | |||
| 69 | void | ||
| 70 | mkreply(Message *m, char *label, char *to, Plumbattr *attr, char *quotetext) | ||
| 71 | { | ||
| 72 | Message *r; | ||
| 73 | char *dir, *t; | ||
| 74 | int quotereply; | ||
| 75 | Plumbattr *a; | ||
| 76 | |||
| 77 | quotereply = (label[0] == 'Q'); | ||
| 78 | r = emalloc(sizeof(Message)); | ||
| 79 | r->isreply = 1; | ||
| 80 | if(m != nil) | ||
| 81 | r->replyname = estrdup(m->name); | ||
| 82 | r->next = replies.head; | ||
| 83 | r->prev = nil; | ||
| 84 | if(replies.head != nil) | ||
| 85 | replies.head->prev = r; | ||
| 86 | replies.head = r; | ||
| 87 | if(replies.tail == nil) | ||
| 88 | replies.tail = r; | ||
| 89 | r->name = emalloc(strlen(mbox.name)+strlen(label)+10); | ||
| 90 | sprint(r->name, "%s%s%d", mbox.name, label, ++replyid); | ||
| 91 | r->w = newwindow(); | ||
| 92 | winname(r->w, r->name); | ||
| 93 | ctlprint(r->w->ctl, "cleartag"); | ||
| 94 | wintagwrite(r->w, "fmt Look Post Undo", 4+5+5+4); | ||
| 95 | r->tagposted = 1; | ||
| 96 | threadcreate(mesgctl, r, STACK); | ||
| 97 | winopenbody(r->w, OWRITE); | ||
| 98 | if(to!=nil && to[0]!='\0') | ||
| 99 | Bprint(r->w->body, "%s\n", to); | ||
| 100 | for(a=attr; a; a=a->next) | ||
| 101 | Bprint(r->w->body, "%s: %s\n", a->name, a->value); | ||
| 102 | dir = nil; | ||
| 103 | if(m != nil){ | ||
| 104 | dir = estrstrdup(mbox.name, m->name); | ||
| 105 | if(to == nil && attr == nil){ | ||
| 106 | /* Reply goes to replyto; Reply all goes to From and To and CC */ | ||
| 107 | if(strstr(label, "all") == nil) | ||
| 108 | Bprint(r->w->body, "To: %s\n", m->replyto); | ||
| 109 | else{ /* Replyall */ | ||
| 110 | if(strlen(m->from) > 0) | ||
| 111 | Bprint(r->w->body, "To: %s\n", m->from); | ||
| 112 | if(strlen(m->to) > 0) | ||
| 113 | Bprint(r->w->body, "To: %s\n", m->to); | ||
| 114 | if(strlen(m->cc) > 0) | ||
| 115 | Bprint(r->w->body, "CC: %s\n", m->cc); | ||
| 116 | } | ||
| 117 | } | ||
| 118 | if(strlen(m->subject) > 0){ | ||
| 119 | t = "Subject: Re: "; | ||
| 120 | if(strlen(m->subject) >= 3) | ||
| 121 | if(tolower(m->subject[0])=='r' && tolower(m->subject[1])=='e' && m->subject[2]==':') | ||
| 122 | t = "Subject: "; | ||
| 123 | Bprint(r->w->body, "%s%s\n", t, m->subject); | ||
| 124 | } | ||
| 125 | if(!quotereply){ | ||
| 126 | Bprint(r->w->body, "Include: %sraw\n", dir); | ||
| 127 | free(dir); | ||
| 128 | } | ||
| 129 | } | ||
| 130 | Bprint(r->w->body, "\n"); | ||
| 131 | if(m == nil) | ||
| 132 | Bprint(r->w->body, "\n"); | ||
| 133 | else if(quotereply){ | ||
| 134 | quote(m, r->w->body, dir, quotetext); | ||
| 135 | free(dir); | ||
| 136 | } | ||
| 137 | winclosebody(r->w); | ||
| 138 | if(m==nil && (to==nil || to[0]=='\0')) | ||
| 139 | winselect(r->w, "0", 0); | ||
| 140 | else | ||
| 141 | winselect(r->w, "$", 0); | ||
| 142 | winclean(r->w); | ||
| 143 | windormant(r->w); | ||
| 144 | } | ||
| 145 | |||
| 146 | void | ||
| 147 | delreply(Message *m) | ||
| 148 | { | ||
| 149 | if(m->next == nil) | ||
| 150 | replies.tail = m->prev; | ||
| 151 | else | ||
| 152 | m->next->prev = m->prev; | ||
| 153 | if(m->prev == nil) | ||
| 154 | replies.head = m->next; | ||
| 155 | else | ||
| 156 | m->prev->next = m->next; | ||
| 157 | mesgfreeparts(m); | ||
| 158 | free(m); | ||
| 159 | } | ||
| 160 | |||
| 161 | /* copy argv to stack and free the incoming strings, so we don't leak argument vectors */ | ||
| 162 | void | ||
| 163 | buildargv(char **inargv, char *argv[NARGS+1], char args[NARGCHAR]) | ||
| 164 | { | ||
| 165 | int i, n; | ||
| 166 | char *s, *a; | ||
| 167 | |||
| 168 | s = args; | ||
| 169 | for(i=0; i<NARGS; i++){ | ||
| 170 | a = inargv[i]; | ||
| 171 | if(a == nil) | ||
| 172 | break; | ||
| 173 | n = strlen(a)+1; | ||
| 174 | if((s-args)+n >= NARGCHAR) /* too many characters */ | ||
| 175 | break; | ||
| 176 | argv[i] = s; | ||
| 177 | memmove(s, a, n); | ||
| 178 | s += n; | ||
| 179 | free(a); | ||
| 180 | } | ||
| 181 | argv[i] = nil; | ||
| 182 | } | ||
| 183 | |||
| 184 | void | ||
| 185 | execproc(void *v) | ||
| 186 | { | ||
| 187 | struct Exec *e; | ||
| 188 | int p[2], q[2]; | ||
| 189 | char *prog; | ||
| 190 | char *argv[NARGS+1], args[NARGCHAR]; | ||
| 191 | |||
| 192 | e = v; | ||
| 193 | p[0] = e->p[0]; | ||
| 194 | p[1] = e->p[1]; | ||
| 195 | q[0] = e->q[0]; | ||
| 196 | q[1] = e->q[1]; | ||
| 197 | prog = e->prog; /* known not to be malloc'ed */ | ||
| 198 | rfork(RFFDG); | ||
| 199 | sendul(e->sync, 1); | ||
| 200 | buildargv(e->argv, argv, args); | ||
| 201 | free(e->argv); | ||
| 202 | chanfree(e->sync); | ||
| 203 | free(e); | ||
| 204 | dup(p[0], 0); | ||
| 205 | close(p[0]); | ||
| 206 | close(p[1]); | ||
| 207 | if(q[0]){ | ||
| 208 | dup(q[1], 1); | ||
| 209 | close(q[0]); | ||
| 210 | close(q[1]); | ||
| 211 | } | ||
| 212 | procexec(nil, prog, argv); | ||
| 213 | //fprint(2, "exec: %s", e->prog); | ||
| 214 | //{int i; | ||
| 215 | //for(i=0; argv[i]; i++) print(" '%s'", argv[i]); | ||
| 216 | //print("\n"); | ||
| 217 | //} | ||
| 218 | //argv[0] = "cat"; | ||
| 219 | //argv[1] = nil; | ||
| 220 | //procexec(nil, "/bin/cat", argv); | ||
| 221 | fprint(2, "Mail: can't exec %s: %r\n", prog); | ||
| 222 | threadexits("can't exec"); | ||
| 223 | } | ||
| 224 | |||
| 225 | enum{ | ||
| 226 | ATTACH, | ||
| 227 | BCC, | ||
| 228 | CC, | ||
| 229 | FROM, | ||
| 230 | INCLUDE, | ||
| 231 | TO, | ||
| 232 | }; | ||
| 233 | |||
| 234 | char *headers[] = { | ||
| 235 | "attach:", | ||
| 236 | "bcc:", | ||
| 237 | "cc:", | ||
| 238 | "from:", | ||
| 239 | "include:", | ||
| 240 | "to:", | ||
| 241 | nil, | ||
| 242 | }; | ||
| 243 | |||
| 244 | int | ||
| 245 | whichheader(char *h) | ||
| 246 | { | ||
| 247 | int i; | ||
| 248 | |||
| 249 | for(i=0; headers[i]!=nil; i++) | ||
| 250 | if(cistrcmp(h, headers[i]) == 0) | ||
| 251 | return i; | ||
| 252 | return -1; | ||
| 253 | } | ||
| 254 | |||
| 255 | char *tolist[200]; | ||
| 256 | char *cclist[200]; | ||
| 257 | char *bcclist[200]; | ||
| 258 | int ncc, nbcc, nto; | ||
| 259 | char *attlist[200]; | ||
| 260 | char included[200]; | ||
| 261 | |||
| 262 | int | ||
| 263 | addressed(char *name) | ||
| 264 | { | ||
| 265 | int i; | ||
| 266 | |||
| 267 | for(i=0; i<nto; i++) | ||
| 268 | if(strcmp(name, tolist[i]) == 0) | ||
| 269 | return 1; | ||
| 270 | for(i=0; i<ncc; i++) | ||
| 271 | if(strcmp(name, cclist[i]) == 0) | ||
| 272 | return 1; | ||
| 273 | for(i=0; i<nbcc; i++) | ||
| 274 | if(strcmp(name, bcclist[i]) == 0) | ||
| 275 | return 1; | ||
| 276 | return 0; | ||
| 277 | } | ||
| 278 | |||
| 279 | char* | ||
| 280 | skipbl(char *s, char *e) | ||
| 281 | { | ||
| 282 | while(s < e){ | ||
| 283 | if(*s!=' ' && *s!='\t' && *s!=',') | ||
| 284 | break; | ||
| 285 | s++; | ||
| 286 | } | ||
| 287 | return s; | ||
| 288 | } | ||
| 289 | |||
| 290 | char* | ||
| 291 | findbl(char *s, char *e) | ||
| 292 | { | ||
| 293 | while(s < e){ | ||
| 294 | if(*s==' ' || *s=='\t' || *s==',') | ||
| 295 | break; | ||
| 296 | s++; | ||
| 297 | } | ||
| 298 | return s; | ||
| 299 | } | ||
| 300 | |||
| 301 | /* | ||
| 302 | * comma-separate possibly blank-separated strings in line; e points before newline | ||
| 303 | */ | ||
| 304 | void | ||
| 305 | commas(char *s, char *e) | ||
| 306 | { | ||
| 307 | char *t; | ||
| 308 | |||
| 309 | /* may have initial blanks */ | ||
| 310 | s = skipbl(s, e); | ||
| 311 | while(s < e){ | ||
| 312 | s = findbl(s, e); | ||
| 313 | if(s == e) | ||
| 314 | break; | ||
| 315 | t = skipbl(s, e); | ||
| 316 | if(t == e) /* no more words */ | ||
| 317 | break; | ||
| 318 | /* patch comma */ | ||
| 319 | *s++ = ','; | ||
| 320 | while(s < t) | ||
| 321 | *s++ = ' '; | ||
| 322 | } | ||
| 323 | } | ||
| 324 | |||
| 325 | int | ||
| 326 | print2(int fd, int ofd, char *fmt, ...) | ||
| 327 | { | ||
| 328 | int m, n; | ||
| 329 | char *s; | ||
| 330 | va_list arg; | ||
| 331 | |||
| 332 | va_start(arg, fmt); | ||
| 333 | s = vsmprint(fmt, arg); | ||
| 334 | va_end(arg); | ||
| 335 | if(s == nil) | ||
| 336 | return -1; | ||
| 337 | m = strlen(s); | ||
| 338 | n = write(fd, s, m); | ||
| 339 | if(ofd > 0) | ||
| 340 | write(ofd, s, m); | ||
| 341 | return n; | ||
| 342 | } | ||
| 343 | |||
| 344 | void | ||
| 345 | write2(int fd, int ofd, char *buf, int n, int nofrom) | ||
| 346 | { | ||
| 347 | char *from, *p; | ||
| 348 | int m; | ||
| 349 | |||
| 350 | write(fd, buf, n); | ||
| 351 | |||
| 352 | if(ofd <= 0) | ||
| 353 | return; | ||
| 354 | |||
| 355 | if(nofrom == 0){ | ||
| 356 | write(ofd, buf, n); | ||
| 357 | return; | ||
| 358 | } | ||
| 359 | |||
| 360 | /* need to escape leading From lines to avoid corrupting 'outgoing' mailbox */ | ||
| 361 | for(p=buf; *p; p+=m){ | ||
| 362 | from = cistrstr(p, "from"); | ||
| 363 | if(from == nil) | ||
| 364 | m = n; | ||
| 365 | else | ||
| 366 | m = from - p; | ||
| 367 | if(m > 0) | ||
| 368 | write(ofd, p, m); | ||
| 369 | if(from){ | ||
| 370 | if(p==buf || from[-1]=='\n') | ||
| 371 | write(ofd, " ", 1); /* escape with space if From is at start of line */ | ||
| 372 | write(ofd, from, 4); | ||
| 373 | m += 4; | ||
| 374 | } | ||
| 375 | n -= m; | ||
| 376 | } | ||
| 377 | } | ||
| 378 | |||
| 379 | void | ||
| 380 | mesgsend(Message *m) | ||
| 381 | { | ||
| 382 | char *s, *body, *to; | ||
| 383 | int i, j, h, n, natt, p[2]; | ||
| 384 | struct Exec *e; | ||
| 385 | Channel *sync; | ||
| 386 | int first, nfld, delit, ofd; | ||
| 387 | char *copy, *fld[100], *now; | ||
| 388 | |||
| 389 | body = winreadbody(m->w, &n); | ||
| 390 | /* assemble to: list from first line, to: line, and cc: line */ | ||
| 391 | nto = 0; | ||
| 392 | natt = 0; | ||
| 393 | ncc = 0; | ||
| 394 | nbcc = 0; | ||
| 395 | first = 1; | ||
| 396 | to = body; | ||
| 397 | for(;;){ | ||
| 398 | for(s=to; *s!='\n'; s++) | ||
| 399 | if(*s == '\0'){ | ||
| 400 | free(body); | ||
| 401 | return; | ||
| 402 | } | ||
| 403 | if(s++ == to) /* blank line */ | ||
| 404 | break; | ||
| 405 | /* make copy of line to tokenize */ | ||
| 406 | copy = emalloc(s-to); | ||
| 407 | memmove(copy, to, s-to); | ||
| 408 | copy[s-to-1] = '\0'; | ||
| 409 | nfld = tokenizec(copy, fld, nelem(fld), ", \t"); | ||
| 410 | if(nfld == 0){ | ||
| 411 | free(copy); | ||
| 412 | break; | ||
| 413 | } | ||
| 414 | n -= s-to; | ||
| 415 | switch(h = whichheader(fld[0])){ | ||
| 416 | case TO: | ||
| 417 | case FROM: | ||
| 418 | delit = 1; | ||
| 419 | commas(to+strlen(fld[0]), s-1); | ||
| 420 | for(i=1; i<nfld && nto<nelem(tolist); i++) | ||
| 421 | if(!addressed(fld[i])) | ||
| 422 | tolist[nto++] = estrdup(fld[i]); | ||
| 423 | break; | ||
| 424 | case BCC: | ||
| 425 | delit = 1; | ||
| 426 | commas(to+strlen(fld[0]), s-1); | ||
| 427 | for(i=1; i<nfld && nbcc<nelem(bcclist); i++) | ||
| 428 | if(!addressed(fld[i])) | ||
| 429 | bcclist[nbcc++] = estrdup(fld[i]); | ||
| 430 | break; | ||
| 431 | case CC: | ||
| 432 | delit = 1; | ||
| 433 | commas(to+strlen(fld[0]), s-1); | ||
| 434 | for(i=1; i<nfld && ncc<nelem(cclist); i++) | ||
| 435 | if(!addressed(fld[i])) | ||
| 436 | cclist[ncc++] = estrdup(fld[i]); | ||
| 437 | break; | ||
| 438 | case ATTACH: | ||
| 439 | case INCLUDE: | ||
| 440 | delit = 1; | ||
| 441 | for(i=1; i<nfld && natt<nelem(attlist); i++){ | ||
| 442 | attlist[natt] = estrdup(fld[i]); | ||
| 443 | included[natt++] = (h == INCLUDE); | ||
| 444 | } | ||
| 445 | break; | ||
| 446 | default: | ||
| 447 | if(first){ | ||
| 448 | delit = 1; | ||
| 449 | for(i=0; i<nfld && nto<nelem(tolist); i++) | ||
| 450 | tolist[nto++] = estrdup(fld[i]); | ||
| 451 | }else /* ignore it */ | ||
| 452 | delit = 0; | ||
| 453 | break; | ||
| 454 | } | ||
| 455 | if(delit){ | ||
| 456 | /* delete line from body */ | ||
| 457 | memmove(to, s, n+1); | ||
| 458 | }else | ||
| 459 | to = s; | ||
| 460 | free(copy); | ||
| 461 | first = 0; | ||
| 462 | } | ||
| 463 | |||
| 464 | ofd = open(outgoing, OWRITE|OCEXEC); /* no error check necessary */ | ||
| 465 | if(ofd > 0){ | ||
| 466 | /* From dhog Fri Aug 24 22:13:00 EDT 2001 */ | ||
| 467 | now = ctime(time(0)); | ||
| 468 | fprint(ofd, "From %s %s", user, now); | ||
| 469 | fprint(ofd, "From: %s\n", user); | ||
| 470 | fprint(ofd, "Date: %s", now); | ||
| 471 | for(i=0; i<natt; i++) | ||
| 472 | if(included[i]) | ||
| 473 | fprint(ofd, "Include: %s\n", attlist[i]); | ||
| 474 | else | ||
| 475 | fprint(ofd, "Attach: %s\n", attlist[i]); | ||
| 476 | /* needed because mail is by default Latin-1 */ | ||
| 477 | fprint(ofd, "Content-Type: text/plain; charset=\"UTF-8\"\n"); | ||
| 478 | fprint(ofd, "Content-Transfer-Encoding: 8bit\n"); | ||
| 479 | } | ||
| 480 | |||
| 481 | e = emalloc(sizeof(struct Exec)); | ||
| 482 | if(pipe(p) < 0) | ||
| 483 | error("can't create pipe: %r"); | ||
| 484 | e->p[0] = p[0]; | ||
| 485 | e->p[1] = p[1]; | ||
| 486 | e->prog = "/bin/upas/marshal"; | ||
| 487 | e->argv = emalloc((1+1+2+4*natt+1)*sizeof(char*)); | ||
| 488 | e->argv[0] = estrdup("marshal"); | ||
| 489 | e->argv[1] = estrdup("-8"); | ||
| 490 | j = 2; | ||
| 491 | if(m->replyname){ | ||
| 492 | e->argv[j++] = estrdup("-R"); | ||
| 493 | e->argv[j++] = estrstrdup(mbox.name, m->replyname); | ||
| 494 | } | ||
| 495 | for(i=0; i<natt; i++){ | ||
| 496 | if(included[i]) | ||
| 497 | e->argv[j++] = estrdup("-A"); | ||
| 498 | else | ||
| 499 | e->argv[j++] = estrdup("-a"); | ||
| 500 | e->argv[j++] = estrdup(attlist[i]); | ||
| 501 | } | ||
| 502 | sync = chancreate(sizeof(int), 0); | ||
| 503 | e->sync = sync; | ||
| 504 | proccreate(execproc, e, EXECSTACK); | ||
| 505 | recvul(sync); | ||
| 506 | close(p[0]); | ||
| 507 | |||
| 508 | /* using marshal -8, so generate rfc822 headers */ | ||
| 509 | if(nto > 0){ | ||
| 510 | print2(p[1], ofd, "To: "); | ||
| 511 | for(i=0; i<nto-1; i++) | ||
| 512 | print2(p[1], ofd, "%s, ", tolist[i]); | ||
| 513 | print2(p[1], ofd, "%s\n", tolist[i]); | ||
| 514 | } | ||
| 515 | if(ncc > 0){ | ||
| 516 | print2(p[1], ofd, "CC: "); | ||
| 517 | for(i=0; i<ncc-1; i++) | ||
| 518 | print2(p[1], ofd, "%s, ", cclist[i]); | ||
| 519 | print2(p[1], ofd, "%s\n", cclist[i]); | ||
| 520 | } | ||
| 521 | if(nbcc > 0){ | ||
| 522 | print2(p[1], ofd, "BCC: "); | ||
| 523 | for(i=0; i<nbcc-1; i++) | ||
| 524 | print2(p[1], ofd, "%s, ", bcclist[i]); | ||
| 525 | print2(p[1], ofd, "%s\n", bcclist[i]); | ||
| 526 | } | ||
| 527 | |||
| 528 | i = strlen(body); | ||
| 529 | if(i > 0) | ||
| 530 | write2(p[1], ofd, body, i, 1); | ||
| 531 | |||
| 532 | /* guarantee a blank line, to ensure attachments are separated from body */ | ||
| 533 | if(i==0 || body[i-1]!='\n') | ||
| 534 | write2(p[1], ofd, "\n\n", 2, 0); | ||
| 535 | else if(i>1 && body[i-2]!='\n') | ||
| 536 | write2(p[1], ofd, "\n", 1, 0); | ||
| 537 | |||
| 538 | /* these look like pseudo-attachments in the "outgoing" box */ | ||
| 539 | if(ofd>0 && natt>0){ | ||
| 540 | for(i=0; i<natt; i++) | ||
| 541 | if(included[i]) | ||
| 542 | fprint(ofd, "=====> Include: %s\n", attlist[i]); | ||
| 543 | else | ||
| 544 | fprint(ofd, "=====> Attach: %s\n", attlist[i]); | ||
| 545 | } | ||
| 546 | if(ofd > 0) | ||
| 547 | write(ofd, "\n", 1); | ||
| 548 | |||
| 549 | for(i=0; i<natt; i++) | ||
| 550 | free(attlist[i]); | ||
| 551 | close(ofd); | ||
| 552 | close(p[1]); | ||
| 553 | free(body); | ||
| 554 | |||
| 555 | if(m->replyname != nil) | ||
| 556 | mesgmenumark(mbox.w, m->replyname, "\t[replied]"); | ||
| 557 | if(m->name[0] == '/') | ||
| 558 | s = estrdup(m->name); | ||
| 559 | else | ||
| 560 | s = estrstrdup(mbox.name, m->name); | ||
| 561 | s = egrow(s, "-R", nil); | ||
| 562 | winname(m->w, s); | ||
| 563 | free(s); | ||
| 564 | winclean(m->w); | ||
| 565 | /* mark message unopened because it's no longer the original message */ | ||
| 566 | m->opened = 0; | ||
| 567 | } | ||
Binary file not shown.
Binary file not shown.
| @@ -0,0 +1,105 @@ | |||
| 1 | #include <u.h> | ||
| 2 | #include <libc.h> | ||
| 3 | #include <bio.h> | ||
| 4 | #include <thread.h> | ||
| 5 | #include <plumb.h> | ||
| 6 | #include "dat.h" | ||
| 7 | |||
| 8 | void* | ||
| 9 | emalloc(uint n) | ||
| 10 | { | ||
| 11 | void *p; | ||
| 12 | |||
| 13 | p = malloc(n); | ||
| 14 | if(p == nil) | ||
| 15 | error("can't malloc: %r"); | ||
| 16 | memset(p, 0, n); | ||
| 17 | setmalloctag(p, getcallerpc(&n)); | ||
| 18 | return p; | ||
| 19 | } | ||
| 20 | |||
| 21 | void* | ||
| 22 | erealloc(void *p, uint n) | ||
| 23 | { | ||
| 24 | p = realloc(p, n); | ||
| 25 | if(p == nil) | ||
| 26 | error("can't realloc: %r"); | ||
| 27 | setmalloctag(p, getcallerpc(&n)); | ||
| 28 | return p; | ||
| 29 | } | ||
| 30 | |||
| 31 | char* | ||
| 32 | estrdup(char *s) | ||
| 33 | { | ||
| 34 | char *t; | ||
| 35 | |||
| 36 | t = emalloc(strlen(s)+1); | ||
| 37 | strcpy(t, s); | ||
| 38 | return t; | ||
| 39 | } | ||
| 40 | |||
| 41 | char* | ||
| 42 | estrstrdup(char *s, char *t) | ||
| 43 | { | ||
| 44 | char *u; | ||
| 45 | |||
| 46 | u = emalloc(strlen(s)+strlen(t)+1); | ||
| 47 | strcpy(u, s); | ||
| 48 | strcat(u, t); | ||
| 49 | return u; | ||
| 50 | } | ||
| 51 | |||
| 52 | char* | ||
| 53 | eappend(char *s, char *sep, char *t) | ||
| 54 | { | ||
| 55 | char *u; | ||
| 56 | |||
| 57 | if(t == nil) | ||
| 58 | u = estrstrdup(s, sep); | ||
| 59 | else{ | ||
| 60 | u = emalloc(strlen(s)+strlen(sep)+strlen(t)+1); | ||
| 61 | strcpy(u, s); | ||
| 62 | strcat(u, sep); | ||
| 63 | strcat(u, t); | ||
| 64 | } | ||
| 65 | free(s); | ||
| 66 | return u; | ||
| 67 | } | ||
| 68 | |||
| 69 | char* | ||
| 70 | egrow(char *s, char *sep, char *t) | ||
| 71 | { | ||
| 72 | s = eappend(s, sep, t); | ||
| 73 | free(t); | ||
| 74 | return s; | ||
| 75 | } | ||
| 76 | |||
| 77 | void | ||
| 78 | error(char *fmt, ...) | ||
| 79 | { | ||
| 80 | Fmt f; | ||
| 81 | char buf[64]; | ||
| 82 | va_list arg; | ||
| 83 | |||
| 84 | fmtfdinit(&f, 2, buf, sizeof buf); | ||
| 85 | fmtprint(&f, "Mail: "); | ||
| 86 | va_start(arg, fmt); | ||
| 87 | fmtvprint(&f, fmt, arg); | ||
| 88 | va_end(arg); | ||
| 89 | fmtprint(&f, "\n"); | ||
| 90 | fmtfdflush(&f); | ||
| 91 | threadexitsall(buf); | ||
| 92 | } | ||
| 93 | |||
| 94 | void | ||
| 95 | ctlprint(int fd, char *fmt, ...) | ||
| 96 | { | ||
| 97 | int n; | ||
| 98 | va_list arg; | ||
| 99 | |||
| 100 | va_start(arg, fmt); | ||
| 101 | n = vfprint(fd, fmt, arg); | ||
| 102 | va_end(arg); | ||
| 103 | if(n <= 0) | ||
| 104 | error("control file write error: %r"); | ||
| 105 | } | ||
Binary file not shown.
Binary file not shown.
| @@ -0,0 +1,341 @@ | |||
| 1 | #include <u.h> | ||
| 2 | #include <libc.h> | ||
| 3 | #include <bio.h> | ||
| 4 | #include <thread.h> | ||
| 5 | #include <plumb.h> | ||
| 6 | #include "dat.h" | ||
| 7 | |||
| 8 | Window* | ||
| 9 | newwindow(void) | ||
| 10 | { | ||
| 11 | char buf[12]; | ||
| 12 | Window *w; | ||
| 13 | |||
| 14 | w = emalloc(sizeof(Window)); | ||
| 15 | w->ctl = open("/mnt/wsys/new/ctl", ORDWR|OCEXEC); | ||
| 16 | if(w->ctl<0 || read(w->ctl, buf, 12)!=12) | ||
| 17 | error("can't open window ctl file: %r"); | ||
| 18 | ctlprint(w->ctl, "noscroll\n"); | ||
| 19 | w->id = atoi(buf); | ||
| 20 | w->event = winopenfile(w, "event"); | ||
| 21 | w->addr = -1; /* will be opened when needed */ | ||
| 22 | w->body = nil; | ||
| 23 | w->data = -1; | ||
| 24 | w->cevent = chancreate(sizeof(Event*), 0); | ||
| 25 | return w; | ||
| 26 | } | ||
| 27 | |||
| 28 | void | ||
| 29 | winsetdump(Window *w, char *dir, char *cmd) | ||
| 30 | { | ||
| 31 | if(dir != nil) | ||
| 32 | ctlprint(w->ctl, "dumpdir %s\n", dir); | ||
| 33 | if(cmd != nil) | ||
| 34 | ctlprint(w->ctl, "dump %s\n", cmd); | ||
| 35 | } | ||
| 36 | |||
| 37 | void | ||
| 38 | wineventproc(void *v) | ||
| 39 | { | ||
| 40 | Window *w; | ||
| 41 | int i; | ||
| 42 | |||
| 43 | w = v; | ||
| 44 | for(i=0; ; i++){ | ||
| 45 | if(i >= NEVENT) | ||
| 46 | i = 0; | ||
| 47 | wingetevent(w, &w->e[i]); | ||
| 48 | sendp(w->cevent, &w->e[i]); | ||
| 49 | } | ||
| 50 | } | ||
| 51 | |||
| 52 | static int | ||
| 53 | winopenfile1(Window *w, char *f, int m) | ||
| 54 | { | ||
| 55 | char buf[64]; | ||
| 56 | int fd; | ||
| 57 | |||
| 58 | sprint(buf, "/mnt/wsys/%d/%s", w->id, f); | ||
| 59 | fd = open(buf, m|OCEXEC); | ||
| 60 | if(fd < 0) | ||
| 61 | error("can't open window file %s: %r", f); | ||
| 62 | return fd; | ||
| 63 | } | ||
| 64 | |||
| 65 | int | ||
| 66 | winopenfile(Window *w, char *f) | ||
| 67 | { | ||
| 68 | return winopenfile1(w, f, ORDWR); | ||
| 69 | } | ||
| 70 | |||
| 71 | void | ||
| 72 | wintagwrite(Window *w, char *s, int n) | ||
| 73 | { | ||
| 74 | int fd; | ||
| 75 | |||
| 76 | fd = winopenfile(w, "tag"); | ||
| 77 | if(write(fd, s, n) != n) | ||
| 78 | error("tag write: %r"); | ||
| 79 | close(fd); | ||
| 80 | } | ||
| 81 | |||
| 82 | void | ||
| 83 | winname(Window *w, char *s) | ||
| 84 | { | ||
| 85 | ctlprint(w->ctl, "name %s\n", s); | ||
| 86 | } | ||
| 87 | |||
| 88 | void | ||
| 89 | winopenbody(Window *w, int mode) | ||
| 90 | { | ||
| 91 | char buf[256]; | ||
| 92 | |||
| 93 | sprint(buf, "/mnt/wsys/%d/body", w->id); | ||
| 94 | w->body = Bopen(buf, mode|OCEXEC); | ||
| 95 | if(w->body == nil) | ||
| 96 | error("can't open window body file: %r"); | ||
| 97 | } | ||
| 98 | |||
| 99 | void | ||
| 100 | winclosebody(Window *w) | ||
| 101 | { | ||
| 102 | if(w->body != nil){ | ||
| 103 | Bterm(w->body); | ||
| 104 | w->body = nil; | ||
| 105 | } | ||
| 106 | } | ||
| 107 | |||
| 108 | void | ||
| 109 | winwritebody(Window *w, char *s, int n) | ||
| 110 | { | ||
| 111 | if(w->body == nil) | ||
| 112 | winopenbody(w, OWRITE); | ||
| 113 | if(Bwrite(w->body, s, n) != n) | ||
| 114 | error("write error to window: %r"); | ||
| 115 | } | ||
| 116 | |||
| 117 | int | ||
| 118 | wingetec(Window *w) | ||
| 119 | { | ||
| 120 | if(w->nbuf == 0){ | ||
| 121 | w->nbuf = read(w->event, w->buf, sizeof w->buf); | ||
| 122 | if(w->nbuf <= 0){ | ||
| 123 | /* probably because window has exited, and only called by wineventproc, so just shut down */ | ||
| 124 | threadexits(nil); | ||
| 125 | } | ||
| 126 | w->bufp = w->buf; | ||
| 127 | } | ||
| 128 | w->nbuf--; | ||
| 129 | return *w->bufp++; | ||
| 130 | } | ||
| 131 | |||
| 132 | int | ||
| 133 | wingeten(Window *w) | ||
| 134 | { | ||
| 135 | int n, c; | ||
| 136 | |||
| 137 | n = 0; | ||
| 138 | while('0'<=(c=wingetec(w)) && c<='9') | ||
| 139 | n = n*10+(c-'0'); | ||
| 140 | if(c != ' ') | ||
| 141 | error("event number syntax"); | ||
| 142 | return n; | ||
| 143 | } | ||
| 144 | |||
| 145 | int | ||
| 146 | wingeter(Window *w, char *buf, int *nb) | ||
| 147 | { | ||
| 148 | Rune r; | ||
| 149 | int n; | ||
| 150 | |||
| 151 | r = wingetec(w); | ||
| 152 | buf[0] = r; | ||
| 153 | n = 1; | ||
| 154 | if(r >= Runeself) { | ||
| 155 | while(!fullrune(buf, n)) | ||
| 156 | buf[n++] = wingetec(w); | ||
| 157 | chartorune(&r, buf); | ||
| 158 | } | ||
| 159 | *nb = n; | ||
| 160 | return r; | ||
| 161 | } | ||
| 162 | |||
| 163 | void | ||
| 164 | wingetevent(Window *w, Event *e) | ||
| 165 | { | ||
| 166 | int i, nb; | ||
| 167 | |||
| 168 | e->c1 = wingetec(w); | ||
| 169 | e->c2 = wingetec(w); | ||
| 170 | e->q0 = wingeten(w); | ||
| 171 | e->q1 = wingeten(w); | ||
| 172 | e->flag = wingeten(w); | ||
| 173 | e->nr = wingeten(w); | ||
| 174 | if(e->nr > EVENTSIZE) | ||
| 175 | error("event string too long"); | ||
| 176 | e->nb = 0; | ||
| 177 | for(i=0; i<e->nr; i++){ | ||
| 178 | e->r[i] = wingeter(w, e->b+e->nb, &nb); | ||
| 179 | e->nb += nb; | ||
| 180 | } | ||
| 181 | e->r[e->nr] = 0; | ||
| 182 | e->b[e->nb] = 0; | ||
| 183 | if(wingetec(w) != '\n') | ||
| 184 | error("event syntax error"); | ||
| 185 | } | ||
| 186 | |||
| 187 | void | ||
| 188 | winwriteevent(Window *w, Event *e) | ||
| 189 | { | ||
| 190 | fprint(w->event, "%c%c%d %d\n", e->c1, e->c2, e->q0, e->q1); | ||
| 191 | } | ||
| 192 | |||
| 193 | void | ||
| 194 | winread(Window *w, uint q0, uint q1, char *data) | ||
| 195 | { | ||
| 196 | int m, n, nr; | ||
| 197 | char buf[256]; | ||
| 198 | |||
| 199 | if(w->addr < 0) | ||
| 200 | w->addr = winopenfile(w, "addr"); | ||
| 201 | if(w->data < 0) | ||
| 202 | w->data = winopenfile(w, "data"); | ||
| 203 | m = q0; | ||
| 204 | while(m < q1){ | ||
| 205 | n = sprint(buf, "#%d", m); | ||
| 206 | if(write(w->addr, buf, n) != n) | ||
| 207 | error("error writing addr: %r"); | ||
| 208 | n = read(w->data, buf, sizeof buf); | ||
| 209 | if(n <= 0) | ||
| 210 | error("reading data: %r"); | ||
| 211 | nr = utfnlen(buf, n); | ||
| 212 | while(m+nr >q1){ | ||
| 213 | do; while(n>0 && (buf[--n]&0xC0)==0x80); | ||
| 214 | --nr; | ||
| 215 | } | ||
| 216 | if(n == 0) | ||
| 217 | break; | ||
| 218 | memmove(data, buf, n); | ||
| 219 | data += n; | ||
| 220 | *data = 0; | ||
| 221 | m += nr; | ||
| 222 | } | ||
| 223 | } | ||
| 224 | |||
| 225 | void | ||
| 226 | windormant(Window *w) | ||
| 227 | { | ||
| 228 | if(w->addr >= 0){ | ||
| 229 | close(w->addr); | ||
| 230 | w->addr = -1; | ||
| 231 | } | ||
| 232 | if(w->body != nil){ | ||
| 233 | Bterm(w->body); | ||
| 234 | w->body = nil; | ||
| 235 | } | ||
| 236 | if(w->data >= 0){ | ||
| 237 | close(w->data); | ||
| 238 | w->data = -1; | ||
| 239 | } | ||
| 240 | } | ||
| 241 | |||
| 242 | |||
| 243 | int | ||
| 244 | windel(Window *w, int sure) | ||
| 245 | { | ||
| 246 | if(sure) | ||
| 247 | write(w->ctl, "delete\n", 7); | ||
| 248 | else if(write(w->ctl, "del\n", 4) != 4) | ||
| 249 | return 0; | ||
| 250 | /* event proc will die due to read error from event file */ | ||
| 251 | windormant(w); | ||
| 252 | close(w->ctl); | ||
| 253 | w->ctl = -1; | ||
| 254 | close(w->event); | ||
| 255 | w->event = -1; | ||
| 256 | return 1; | ||
| 257 | } | ||
| 258 | |||
| 259 | void | ||
| 260 | winclean(Window *w) | ||
| 261 | { | ||
| 262 | if(w->body) | ||
| 263 | Bflush(w->body); | ||
| 264 | ctlprint(w->ctl, "clean\n"); | ||
| 265 | } | ||
| 266 | |||
| 267 | int | ||
| 268 | winsetaddr(Window *w, char *addr, int errok) | ||
| 269 | { | ||
| 270 | if(w->addr < 0) | ||
| 271 | w->addr = winopenfile(w, "addr"); | ||
| 272 | if(write(w->addr, addr, strlen(addr)) < 0){ | ||
| 273 | if(!errok) | ||
| 274 | error("error writing addr(%s): %r", addr); | ||
| 275 | return 0; | ||
| 276 | } | ||
| 277 | return 1; | ||
| 278 | } | ||
| 279 | |||
| 280 | int | ||
| 281 | winselect(Window *w, char *addr, int errok) | ||
| 282 | { | ||
| 283 | if(winsetaddr(w, addr, errok)){ | ||
| 284 | ctlprint(w->ctl, "dot=addr\n"); | ||
| 285 | return 1; | ||
| 286 | } | ||
| 287 | return 0; | ||
| 288 | } | ||
| 289 | |||
| 290 | char* | ||
| 291 | winreadbody(Window *w, int *np) /* can't use readfile because acme doesn't report the length */ | ||
| 292 | { | ||
| 293 | char *s; | ||
| 294 | int m, na, n; | ||
| 295 | |||
| 296 | if(w->body != nil) | ||
| 297 | winclosebody(w); | ||
| 298 | winopenbody(w, OREAD); | ||
| 299 | s = nil; | ||
| 300 | na = 0; | ||
| 301 | n = 0; | ||
| 302 | for(;;){ | ||
| 303 | if(na < n+512){ | ||
| 304 | na += 1024; | ||
| 305 | s = realloc(s, na+1); | ||
| 306 | } | ||
| 307 | m = Bread(w->body, s+n, na-n); | ||
| 308 | if(m <= 0) | ||
| 309 | break; | ||
| 310 | n += m; | ||
| 311 | } | ||
| 312 | s[n] = 0; | ||
| 313 | winclosebody(w); | ||
| 314 | *np = n; | ||
| 315 | return s; | ||
| 316 | } | ||
| 317 | |||
| 318 | char* | ||
| 319 | winselection(Window *w) | ||
| 320 | { | ||
| 321 | int fd, m, n; | ||
| 322 | char *buf; | ||
| 323 | char tmp[256]; | ||
| 324 | |||
| 325 | fd = winopenfile1(w, "rdsel", OREAD); | ||
| 326 | if(fd < 0) | ||
| 327 | error("can't open rdsel: %r"); | ||
| 328 | n = 0; | ||
| 329 | buf = nil; | ||
| 330 | for(;;){ | ||
| 331 | m = read(fd, tmp, sizeof tmp); | ||
| 332 | if(m <= 0) | ||
| 333 | break; | ||
| 334 | buf = erealloc(buf, n+m+1); | ||
| 335 | memmove(buf+n, tmp, m); | ||
| 336 | n += m; | ||
| 337 | buf[n] = '\0'; | ||
| 338 | } | ||
| 339 | close(fd); | ||
| 340 | return buf; | ||
| 341 | } | ||
| @@ -0,0 +1,10 @@ | |||
| 1 | </$objtype/mkfile | ||
| 2 | |||
| 3 | none:VQ: | ||
| 4 | echo mk all, install, clean, nuke, installall, update | ||
| 5 | |||
| 6 | all install clean nuke installall update:V: | ||
| 7 | @{cd bin/source; mk $target} | ||
| 8 | @{cd mail/src; mk $target} | ||
| 9 | @{cd news/src; mk $target} | ||
| 10 | @{cd wiki/src; mk $target} | ||
| @@ -0,0 +1,2 @@ | |||
| 1 | Local nntpfs | ||
| 2 | News comp.os.plan9 | ||
Binary file not shown.
Binary file not shown.
| @@ -0,0 +1,18 @@ | |||
| 1 | </$objtype/mkfile | ||
| 2 | |||
| 3 | TARG=News | ||
| 4 | OFILES=\ | ||
| 5 | news.$O\ | ||
| 6 | util.$O\ | ||
| 7 | win.$O\ | ||
| 8 | |||
| 9 | HFILES= | ||
| 10 | |||
| 11 | BIN=/acme/bin/$objtype | ||
| 12 | UPDATE=\ | ||
| 13 | mkfile\ | ||
| 14 | $HFILES\ | ||
| 15 | ${OFILES:%.$O=%.c}\ | ||
| 16 | ${TARG:%=/acme/bin/386/%}\ | ||
| 17 | |||
| 18 | </sys/src/cmd/mkone | ||
Binary file not shown.
Binary file not shown.
| @@ -0,0 +1,1007 @@ | |||
| 1 | /* | ||
| 2 | * Acme interface to nntpfs. | ||
| 3 | */ | ||
| 4 | #include <u.h> | ||
| 5 | #include <libc.h> | ||
| 6 | #include <bio.h> | ||
| 7 | #include <thread.h> | ||
| 8 | #include "win.h" | ||
| 9 | #include <ctype.h> | ||
| 10 | |||
| 11 | int canpost; | ||
| 12 | int debug; | ||
| 13 | int nshow = 20; | ||
| 14 | |||
| 15 | int lo; /* next message to look at in dir */ | ||
| 16 | int hi; /* current hi message in dir */ | ||
| 17 | char *dir = "/mnt/news"; | ||
| 18 | char *group; | ||
| 19 | char *from; | ||
| 20 | |||
| 21 | typedef struct Article Article; | ||
| 22 | struct Article { | ||
| 23 | Ref; | ||
| 24 | Article *prev; | ||
| 25 | Article *next; | ||
| 26 | Window *w; | ||
| 27 | int n; | ||
| 28 | int dead; | ||
| 29 | int dirtied; | ||
| 30 | int sayspost; | ||
| 31 | int headers; | ||
| 32 | int ispost; | ||
| 33 | }; | ||
| 34 | |||
| 35 | Article *mlist; | ||
| 36 | Window *root; | ||
| 37 | |||
| 38 | int | ||
| 39 | cistrncmp(char *a, char *b, int n) | ||
| 40 | { | ||
| 41 | while(n-- > 0){ | ||
| 42 | if(tolower(*a++) != tolower(*b++)) | ||
| 43 | return -1; | ||
| 44 | } | ||
| 45 | return 0; | ||
| 46 | } | ||
| 47 | |||
| 48 | int | ||
| 49 | cistrcmp(char *a, char *b) | ||
| 50 | { | ||
| 51 | for(;;){ | ||
| 52 | if(tolower(*a) != tolower(*b++)) | ||
| 53 | return -1; | ||
| 54 | if(*a++ == 0) | ||
| 55 | break; | ||
| 56 | } | ||
| 57 | return 0; | ||
| 58 | } | ||
| 59 | |||
| 60 | char* | ||
| 61 | skipwhite(char *p) | ||
| 62 | { | ||
| 63 | while(isspace(*p)) | ||
| 64 | p++; | ||
| 65 | return p; | ||
| 66 | } | ||
| 67 | |||
| 68 | int | ||
| 69 | gethi(void) | ||
| 70 | { | ||
| 71 | Dir *d; | ||
| 72 | int hi; | ||
| 73 | |||
| 74 | if((d = dirstat(dir)) == nil) | ||
| 75 | return -1; | ||
| 76 | hi = d->qid.vers; | ||
| 77 | free(d); | ||
| 78 | return hi; | ||
| 79 | } | ||
| 80 | |||
| 81 | char* | ||
| 82 | fixfrom(char *s) | ||
| 83 | { | ||
| 84 | char *r, *w; | ||
| 85 | |||
| 86 | s = estrdup(s); | ||
| 87 | /* remove quotes */ | ||
| 88 | for(r=w=s; *r; r++) | ||
| 89 | if(*r != '"') | ||
| 90 | *w++ = *r; | ||
| 91 | *w = '\0'; | ||
| 92 | return s; | ||
| 93 | } | ||
| 94 | |||
| 95 | char *day[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", }; | ||
| 96 | char *mon[] = { | ||
| 97 | "Jan", "Feb", "Mar", "Apr", | ||
| 98 | "May", "Jun", "Jul", "Aug", | ||
| 99 | "Sep", "Oct", "Nov", "Dec", | ||
| 100 | }; | ||
| 101 | |||
| 102 | char* | ||
| 103 | fixdate(char *s) | ||
| 104 | { | ||
| 105 | char *f[10], *m, *t, *wd, tmp[40]; | ||
| 106 | int d, i, j, nf, hh, mm; | ||
| 107 | |||
| 108 | nf = tokenize(s, f, nelem(f)); | ||
| 109 | |||
| 110 | wd = nil; | ||
| 111 | d = 0; | ||
| 112 | m = nil; | ||
| 113 | t = nil; | ||
| 114 | for(i=0; i<nf; i++){ | ||
| 115 | for(j=0; j<7; j++) | ||
| 116 | if(cistrncmp(day[j], f[i], 3)==0) | ||
| 117 | wd = day[j]; | ||
| 118 | for(j=0; j<12; j++) | ||
| 119 | if(cistrncmp(mon[j], f[i], 3)==0) | ||
| 120 | m = mon[j]; | ||
| 121 | j = atoi(f[i]); | ||
| 122 | if(1 <= j && j <= 31 && d != 0) | ||
| 123 | d = j; | ||
| 124 | if(strchr(f[i], ':')) | ||
| 125 | t = f[i]; | ||
| 126 | } | ||
| 127 | |||
| 128 | if(d==0 || wd==nil || m==nil || t==nil) | ||
| 129 | return nil; | ||
| 130 | |||
| 131 | hh = strtol(t, 0, 10); | ||
| 132 | mm = strtol(strchr(t, ':')+1, 0, 10); | ||
| 133 | sprint(tmp, "%s %d %s %d:%.2d", wd, d, m, hh, mm); | ||
| 134 | return estrdup(tmp); | ||
| 135 | } | ||
| 136 | |||
| 137 | void | ||
| 138 | msgheadline(Biobuf *bin, int n, Biobuf *bout) | ||
| 139 | { | ||
| 140 | char *p, *q; | ||
| 141 | char *date; | ||
| 142 | char *from; | ||
| 143 | char *subject; | ||
| 144 | |||
| 145 | date = nil; | ||
| 146 | from = nil; | ||
| 147 | subject = nil; | ||
| 148 | while(p = Brdline(bin, '\n')){ | ||
| 149 | p[Blinelen(bin)-1] = '\0'; | ||
| 150 | if((q = strchr(p, ':')) == nil) | ||
| 151 | continue; | ||
| 152 | *q++ = '\0'; | ||
| 153 | if(cistrcmp(p, "from")==0) | ||
| 154 | from = fixfrom(skipwhite(q)); | ||
| 155 | else if(cistrcmp(p, "subject")==0) | ||
| 156 | subject = estrdup(skipwhite(q)); | ||
| 157 | else if(cistrcmp(p, "date")==0) | ||
| 158 | date = fixdate(skipwhite(q)); | ||
| 159 | } | ||
| 160 | |||
| 161 | Bprint(bout, "%d/\t%s", n, from ? from : ""); | ||
| 162 | if(date) | ||
| 163 | Bprint(bout, "\t%s", date); | ||
| 164 | if(subject) | ||
| 165 | Bprint(bout, "\n\t%s", subject); | ||
| 166 | Bprint(bout, "\n"); | ||
| 167 | |||
| 168 | free(date); | ||
| 169 | free(from); | ||
| 170 | free(subject); | ||
| 171 | } | ||
| 172 | |||
| 173 | /* | ||
| 174 | * Write the headers for at most nshow messages to b, | ||
| 175 | * starting with hi and working down to lo. | ||
| 176 | * Return number of first message not scanned. | ||
| 177 | */ | ||
| 178 | int | ||
| 179 | adddir(Biobuf *body, int hi, int lo, int nshow) | ||
| 180 | { | ||
| 181 | char *p, *q, tmp[40]; | ||
| 182 | int i, n; | ||
| 183 | Biobuf *b; | ||
| 184 | |||
| 185 | n = 0; | ||
| 186 | for(i=hi; i>=lo && n<nshow; i--){ | ||
| 187 | sprint(tmp, "%d", i); | ||
| 188 | p = estrstrdup(dir, tmp); | ||
| 189 | if(access(p, OREAD) < 0){ | ||
| 190 | free(p); | ||
| 191 | break; | ||
| 192 | } | ||
| 193 | q = estrstrdup(p, "/header"); | ||
| 194 | free(p); | ||
| 195 | b = Bopen(q, OREAD); | ||
| 196 | free(q); | ||
| 197 | if(b == nil) | ||
| 198 | continue; | ||
| 199 | msgheadline(b, i, body); | ||
| 200 | Bterm(b); | ||
| 201 | n++; | ||
| 202 | } | ||
| 203 | return i; | ||
| 204 | } | ||
| 205 | |||
| 206 | /* | ||
| 207 | * Show the first nshow messages in the window. | ||
| 208 | * This depends on nntpfs presenting contiguously | ||
| 209 | * numbered directories, and on the qid version being | ||
| 210 | * the topmost numbered directory. | ||
| 211 | */ | ||
| 212 | void | ||
| 213 | dirwindow(Window *w) | ||
| 214 | { | ||
| 215 | if((hi=gethi()) < 0) | ||
| 216 | return; | ||
| 217 | |||
| 218 | if(w->data < 0) | ||
| 219 | w->data = winopenfile(w, "data"); | ||
| 220 | |||
| 221 | fprint(w->ctl, "dirty\n"); | ||
| 222 | |||
| 223 | winopenbody(w, OWRITE); | ||
| 224 | lo = adddir(w->body, hi, 0, nshow); | ||
| 225 | winclean(w); | ||
| 226 | } | ||
| 227 | |||
| 228 | /* return 1 if handled, 0 otherwise */ | ||
| 229 | static int | ||
| 230 | iscmd(char *s, char *cmd) | ||
| 231 | { | ||
| 232 | int len; | ||
| 233 | |||
| 234 | len = strlen(cmd); | ||
| 235 | return strncmp(s, cmd, len)==0 && (s[len]=='\0' || s[len]==' ' || s[len]=='\t' || s[len]=='\n'); | ||
| 236 | } | ||
| 237 | |||
| 238 | static char* | ||
| 239 | skip(char *s, char *cmd) | ||
| 240 | { | ||
| 241 | s += strlen(cmd); | ||
| 242 | while(*s==' ' || *s=='\t' || *s=='\n') | ||
| 243 | s++; | ||
| 244 | return s; | ||
| 245 | } | ||
| 246 | |||
| 247 | void | ||
| 248 | unlink(Article *m) | ||
| 249 | { | ||
| 250 | if(mlist == m) | ||
| 251 | mlist = m->next; | ||
| 252 | |||
| 253 | if(m->next) | ||
| 254 | m->next->prev = m->prev; | ||
| 255 | if(m->prev) | ||
| 256 | m->prev->next = m->next; | ||
| 257 | m->next = m->prev = nil; | ||
| 258 | } | ||
| 259 | |||
| 260 | int mesgopen(char*); | ||
| 261 | int fillmesgwindow(int, Article*); | ||
| 262 | Article *newpost(void); | ||
| 263 | void replywindow(Article*); | ||
| 264 | void mesgpost(Article*); | ||
| 265 | |||
| 266 | /* | ||
| 267 | * Depends on d.qid.vers being highest numbered message in dir. | ||
| 268 | */ | ||
| 269 | void | ||
| 270 | acmetimer(Article *m, Window *w) | ||
| 271 | { | ||
| 272 | Biobuf *b; | ||
| 273 | Dir *d; | ||
| 274 | |||
| 275 | assert(m==nil && w==root); | ||
| 276 | |||
| 277 | if((d = dirstat(dir))==nil | hi==d->qid.vers){ | ||
| 278 | free(d); | ||
| 279 | return; | ||
| 280 | } | ||
| 281 | |||
| 282 | if(w->data < 0) | ||
| 283 | w->data = winopenfile(w, "data"); | ||
| 284 | if(winsetaddr(w, "0", 0)) | ||
| 285 | write(w->data, "", 0); | ||
| 286 | |||
| 287 | b = emalloc(sizeof(*b)); | ||
| 288 | Binit(b, w->data, OWRITE); | ||
| 289 | adddir(b, d->qid.vers, hi+1, d->qid.vers); | ||
| 290 | hi = d->qid.vers; | ||
| 291 | Bterm(b); | ||
| 292 | free(b); | ||
| 293 | free(d); | ||
| 294 | winselect(w, "0,.", 0); | ||
| 295 | } | ||
| 296 | |||
| 297 | int | ||
| 298 | acmeload(Article*, Window*, char *s) | ||
| 299 | { | ||
| 300 | int nopen; | ||
| 301 | |||
| 302 | //fprint(2, "load %s\n", s); | ||
| 303 | |||
| 304 | nopen = 0; | ||
| 305 | while(*s){ | ||
| 306 | /* skip directory name */ | ||
| 307 | if(strncmp(s, dir, strlen(dir))==0) | ||
| 308 | s += strlen(dir); | ||
| 309 | nopen += mesgopen(s); | ||
| 310 | if((s = strchr(s, '\n')) == nil) | ||
| 311 | break; | ||
| 312 | s = skip(s, ""); | ||
| 313 | } | ||
| 314 | return nopen; | ||
| 315 | } | ||
| 316 | |||
| 317 | int | ||
| 318 | acmecmd(Article *m, Window *w, char *s) | ||
| 319 | { | ||
| 320 | int n; | ||
| 321 | Biobuf *b; | ||
| 322 | |||
| 323 | //fprint(2, "cmd %s\n", s); | ||
| 324 | |||
| 325 | s = skip(s, ""); | ||
| 326 | |||
| 327 | if(iscmd(s, "Del")){ | ||
| 328 | if(m == nil){ /* don't close dir until messages close */ | ||
| 329 | if(mlist != nil){ | ||
| 330 | ctlprint(mlist->w->ctl, "show\n"); | ||
| 331 | return 1; | ||
| 332 | } | ||
| 333 | if(windel(w, 0)) | ||
| 334 | threadexitsall(nil); | ||
| 335 | return 1; | ||
| 336 | }else{ | ||
| 337 | if(windel(w, 0)) | ||
| 338 | m->dead = 1; | ||
| 339 | return 1; | ||
| 340 | } | ||
| 341 | } | ||
| 342 | if(m==nil && iscmd(s, "More")){ | ||
| 343 | s = skip(s, "More"); | ||
| 344 | if(n = atoi(s)) | ||
| 345 | nshow = n; | ||
| 346 | |||
| 347 | if(w->data < 0) | ||
| 348 | w->data = winopenfile(w, "data"); | ||
| 349 | winsetaddr(w, "$", 1); | ||
| 350 | |||
| 351 | fprint(w->ctl, "dirty\n"); | ||
| 352 | |||
| 353 | b = emalloc(sizeof(*b)); | ||
| 354 | Binit(b, w->data, OWRITE); | ||
| 355 | lo = adddir(b, lo, 0, nshow); | ||
| 356 | Bterm(b); | ||
| 357 | free(b); | ||
| 358 | winclean(w); | ||
| 359 | winsetaddr(w, ".,", 0); | ||
| 360 | } | ||
| 361 | if(m!=nil && !m->ispost && iscmd(s, "Headers")){ | ||
| 362 | m->headers = !m->headers; | ||
| 363 | fillmesgwindow(-1, m); | ||
| 364 | return 1; | ||
| 365 | } | ||
| 366 | if(iscmd(s, "Newpost")){ | ||
| 367 | m = newpost(); | ||
| 368 | winopenbody(m->w, OWRITE); | ||
| 369 | Bprint(m->w->body, "%s\nsubject: \n\n", group); | ||
| 370 | winclean(m->w); | ||
| 371 | winselect(m->w, "$", 0); | ||
| 372 | return 1; | ||
| 373 | } | ||
| 374 | if(m!=nil && !m->ispost && iscmd(s, "Reply")){ | ||
| 375 | replywindow(m); | ||
| 376 | return 1; | ||
| 377 | } | ||
| 378 | // if(m!=nil && iscmd(s, "Replymail")){ | ||
| 379 | // fprint(2, "no replymail yet\n"); | ||
| 380 | // return 1; | ||
| 381 | // } | ||
| 382 | if(iscmd(s, "Post")){ | ||
| 383 | mesgpost(m); | ||
| 384 | return 1; | ||
| 385 | } | ||
| 386 | return 0; | ||
| 387 | } | ||
| 388 | |||
| 389 | void | ||
| 390 | acmeevent(Article *m, Window *w, Event *e) | ||
| 391 | { | ||
| 392 | Event *ea, *e2, *eq; | ||
| 393 | char *s, *t, *buf; | ||
| 394 | int na; | ||
| 395 | //int n; | ||
| 396 | //ulong q0, q1; | ||
| 397 | |||
| 398 | switch(e->c1){ /* origin of action */ | ||
| 399 | default: | ||
| 400 | Unknown: | ||
| 401 | fprint(2, "unknown message %c%c\n", e->c1, e->c2); | ||
| 402 | break; | ||
| 403 | |||
| 404 | case 'T': /* bogus timer event! */ | ||
| 405 | acmetimer(m, w); | ||
| 406 | break; | ||
| 407 | |||
| 408 | case 'F': /* generated by our actions; ignore */ | ||
| 409 | break; | ||
| 410 | |||
| 411 | case 'E': /* write to body or tag; can't affect us */ | ||
| 412 | break; | ||
| 413 | |||
| 414 | case 'K': /* type away; we don't care */ | ||
| 415 | if(m && (e->c2 == 'I' || e->c2 == 'D')){ | ||
| 416 | m->dirtied = 1; | ||
| 417 | if(!m->sayspost){ | ||
| 418 | wintagwrite(w, "Post ", 5); | ||
| 419 | m->sayspost = 1; | ||
| 420 | } | ||
| 421 | } | ||
| 422 | break; | ||
| 423 | |||
| 424 | case 'M': /* mouse event */ | ||
| 425 | switch(e->c2){ /* type of action */ | ||
| 426 | case 'x': /* mouse: button 2 in tag */ | ||
| 427 | case 'X': /* mouse: button 2 in body */ | ||
| 428 | ea = nil; | ||
| 429 | //e2 = nil; | ||
| 430 | s = e->b; | ||
| 431 | if(e->flag & 2){ /* null string with non-null expansion */ | ||
| 432 | e2 = recvp(w->cevent); | ||
| 433 | if(e->nb==0) | ||
| 434 | s = e2->b; | ||
| 435 | } | ||
| 436 | if(e->flag & 8){ /* chorded argument */ | ||
| 437 | ea = recvp(w->cevent); /* argument */ | ||
| 438 | na = ea->nb; | ||
| 439 | recvp(w->cevent); /* ignore origin */ | ||
| 440 | }else | ||
| 441 | na = 0; | ||
| 442 | |||
| 443 | /* append chorded arguments */ | ||
| 444 | if(na){ | ||
| 445 | t = emalloc(strlen(s)+1+na+1); | ||
| 446 | sprint(t, "%s %s", s, ea->b); | ||
| 447 | s = t; | ||
| 448 | } | ||
| 449 | /* if it's a known command, do it */ | ||
| 450 | /* if it's a long message, it can't be for us anyway */ | ||
| 451 | // DPRINT(2, "exec: %s\n", s); | ||
| 452 | if(!acmecmd(m, w, s)) /* send it back */ | ||
| 453 | winwriteevent(w, e); | ||
| 454 | if(na) | ||
| 455 | free(s); | ||
| 456 | break; | ||
| 457 | |||
| 458 | case 'l': /* mouse: button 3 in tag */ | ||
| 459 | case 'L': /* mouse: button 3 in body */ | ||
| 460 | //buf = nil; | ||
| 461 | eq = e; | ||
| 462 | if(e->flag & 2){ | ||
| 463 | e2 = recvp(w->cevent); | ||
| 464 | eq = e2; | ||
| 465 | } | ||
| 466 | s = eq->b; | ||
| 467 | if(eq->q1>eq->q0 && eq->nb==0){ | ||
| 468 | buf = emalloc((eq->q1-eq->q0)*UTFmax+1); | ||
| 469 | winread(w, eq->q0, eq->q1, buf); | ||
| 470 | s = buf; | ||
| 471 | } | ||
| 472 | if(!acmeload(m, w, s)) | ||
| 473 | winwriteevent(w, e); | ||
| 474 | break; | ||
| 475 | |||
| 476 | case 'i': /* mouse: text inserted in tag */ | ||
| 477 | case 'd': /* mouse: text deleted from tag */ | ||
| 478 | break; | ||
| 479 | |||
| 480 | case 'I': /* mouse: text inserted in body */ | ||
| 481 | case 'D': /* mouse: text deleted from body */ | ||
| 482 | if(m == nil) | ||
| 483 | break; | ||
| 484 | |||
| 485 | m->dirtied = 1; | ||
| 486 | if(!m->sayspost){ | ||
| 487 | wintagwrite(w, "Post ", 5); | ||
| 488 | m->sayspost = 1; | ||
| 489 | } | ||
| 490 | break; | ||
| 491 | |||
| 492 | default: | ||
| 493 | goto Unknown; | ||
| 494 | } | ||
| 495 | } | ||
| 496 | } | ||
| 497 | |||
| 498 | void | ||
| 499 | dirthread(void *v) | ||
| 500 | { | ||
| 501 | Event *e; | ||
| 502 | Window *w; | ||
| 503 | |||
| 504 | w = v; | ||
| 505 | while(e = recvp(w->cevent)) | ||
| 506 | acmeevent(nil, w, e); | ||
| 507 | |||
| 508 | threadexitsall(nil); | ||
| 509 | } | ||
| 510 | |||
| 511 | void | ||
| 512 | mesgthread(void *v) | ||
| 513 | { | ||
| 514 | Event *e; | ||
| 515 | Article *m; | ||
| 516 | |||
| 517 | m = v; | ||
| 518 | while(!m->dead && (e = recvp(m->w->cevent))) | ||
| 519 | acmeevent(m, m->w, e); | ||
| 520 | |||
| 521 | //fprint(2, "msg %p exits\n", m); | ||
| 522 | unlink(m); | ||
| 523 | free(m->w); | ||
| 524 | free(m); | ||
| 525 | threadexits(nil); | ||
| 526 | } | ||
| 527 | |||
| 528 | /* | ||
| 529 | Xref: news.research.att.com comp.os.plan9:7360 | ||
| 530 | Newsgroups: comp.os.plan9 | ||
| 531 | Path: news.research.att.com!batch0!uunet!ffx.uu.net!finch!news.mindspring.net!newsfeed.mathworks.com!fu-berlin.de!server1.netnews.ja.net!hgmp.mrc.ac.uk!pegasus.csx.cam.ac.uk!bath.ac.uk!ccsdhd | ||
| 532 | From: Stephen Adam <saadam@bigpond.com> | ||
| 533 | Subject: Future of Plan9 | ||
| 534 | Approved: plan9mod@bath.ac.uk | ||
| 535 | X-Newsreader: Microsoft Outlook Express 5.00.2014.211 | ||
| 536 | X-Mimeole: Produced By Microsoft MimeOLE V5.00.2014.211 | ||
| 537 | Sender: ccsdhd@bath.ac.uk (Dennis Davis) | ||
| 538 | Nntp-Posting-Date: Wed, 13 Dec 2000 21:28:45 EST | ||
| 539 | NNTP-Posting-Host: 203.54.121.233 | ||
| 540 | Organization: Telstra BigPond Internet Services (http://www.bigpond.com) | ||
| 541 | X-Date: Wed, 13 Dec 2000 20:43:37 +1000 | ||
| 542 | Lines: 12 | ||
| 543 | Message-ID: <xbIZ5.157945$e5.114349@newsfeeds.bigpond.com> | ||
| 544 | References: <95pghu$3lf$1@news.fas.harvard.edu> <95ph36$3m9$1@news.fas.harvard.edu> <slrn980iic.u5q.mperrin@hcs.harvard.edu> <95png6$4ln$1@news.fas.harvard.edu> <95poqg$4rq$1@news.fas.harvard.edu> <slrn980vh8.2gb.myLastName@is07.fas.harvard.edu> <95q40h$66c$2@news.fas.harvard.edu> <95qjhu$8ke$1@news.fas.harvard.edu> <95riue$bu2$1@news.fas.harvard.edu> <95rnar$cbu$1@news.fas.harvard.edu> | ||
| 545 | X-Msmail-Priority: Normal | ||
| 546 | X-Trace: newsfeeds.bigpond.com 976703325 203.54.121.233 (Wed, 13 Dec 2000 21:28:45 EST) | ||
| 547 | X-Priority: 3 | ||
| 548 | Date: Wed, 13 Dec 2000 10:49:50 GMT | ||
| 549 | */ | ||
| 550 | |||
| 551 | char *skipheader[] = | ||
| 552 | { | ||
| 553 | "x-", | ||
| 554 | "path:", | ||
| 555 | "xref:", | ||
| 556 | "approved:", | ||
| 557 | "sender:", | ||
| 558 | "nntp-", | ||
| 559 | "organization:", | ||
| 560 | "lines:", | ||
| 561 | "message-id:", | ||
| 562 | "references:", | ||
| 563 | "reply-to:", | ||
| 564 | "mime-", | ||
| 565 | "content-", | ||
| 566 | }; | ||
| 567 | |||
| 568 | int | ||
| 569 | fillmesgwindow(int fd, Article *m) | ||
| 570 | { | ||
| 571 | Biobuf *b; | ||
| 572 | char *p, tmp[40]; | ||
| 573 | int i, inhdr, copy, xfd; | ||
| 574 | Window *w; | ||
| 575 | |||
| 576 | xfd = -1; | ||
| 577 | if(fd == -1){ | ||
| 578 | sprint(tmp, "%d/article", m->n); | ||
| 579 | p = estrstrdup(dir, tmp); | ||
| 580 | if((xfd = open(p, OREAD)) < 0){ | ||
| 581 | free(p); | ||
| 582 | return 0; | ||
| 583 | } | ||
| 584 | free(p); | ||
| 585 | fd = xfd; | ||
| 586 | } | ||
| 587 | |||
| 588 | w = m->w; | ||
| 589 | if(w->data < 0) | ||
| 590 | w->data = winopenfile(w, "data"); | ||
| 591 | if(winsetaddr(w, ",", 0)) | ||
| 592 | write(w->data, "", 0); | ||
| 593 | |||
| 594 | winopenbody(m->w, OWRITE); | ||
| 595 | b = emalloc(sizeof(*b)); | ||
| 596 | Binit(b, fd, OREAD); | ||
| 597 | |||
| 598 | inhdr = 1; | ||
| 599 | copy = 1; | ||
| 600 | while(p = Brdline(b, '\n')){ | ||
| 601 | if(Blinelen(b)==1) | ||
| 602 | inhdr = 0, copy=1; | ||
| 603 | if(inhdr && !isspace(p[0])){ | ||
| 604 | copy = 1; | ||
| 605 | if(!m->headers){ | ||
| 606 | if(cistrncmp(p, "from:", 5)==0){ | ||
| 607 | p[Blinelen(b)-1] = '\0'; | ||
| 608 | p = fixfrom(skip(p, "from:")); | ||
| 609 | Bprint(m->w->body, "From: %s\n", p); | ||
| 610 | free(p); | ||
| 611 | copy = 0; | ||
| 612 | continue; | ||
| 613 | } | ||
| 614 | for(i=0; i<nelem(skipheader); i++) | ||
| 615 | if(cistrncmp(p, skipheader[i], strlen(skipheader[i]))==0) | ||
| 616 | copy=0; | ||
| 617 | } | ||
| 618 | } | ||
| 619 | if(copy) | ||
| 620 | Bwrite(m->w->body, p, Blinelen(b)); | ||
| 621 | } | ||
| 622 | Bterm(b); | ||
| 623 | free(b); | ||
| 624 | winclean(m->w); | ||
| 625 | if(xfd != -1) | ||
| 626 | close(xfd); | ||
| 627 | return 1; | ||
| 628 | } | ||
| 629 | |||
| 630 | Article* | ||
| 631 | newpost(void) | ||
| 632 | { | ||
| 633 | Article *m; | ||
| 634 | char *p, tmp[40]; | ||
| 635 | static int nnew; | ||
| 636 | |||
| 637 | m = emalloc(sizeof *m); | ||
| 638 | sprint(tmp, "Post%d", ++nnew); | ||
| 639 | p = estrstrdup(dir, tmp); | ||
| 640 | |||
| 641 | m->w = newwindow(); | ||
| 642 | proccreate(wineventproc, m->w, STACK); | ||
| 643 | winname(m->w, p); | ||
| 644 | wintagwrite(m->w, "Post ", 5); | ||
| 645 | m->sayspost = 1; | ||
| 646 | m->ispost = 1; | ||
| 647 | threadcreate(mesgthread, m, STACK); | ||
| 648 | |||
| 649 | if(mlist){ | ||
| 650 | m->next = mlist; | ||
| 651 | mlist->prev = m; | ||
| 652 | } | ||
| 653 | mlist = m; | ||
| 654 | return m; | ||
| 655 | } | ||
| 656 | |||
| 657 | void | ||
| 658 | replywindow(Article *m) | ||
| 659 | { | ||
| 660 | Biobuf *b; | ||
| 661 | char *p, *ep, *q, tmp[40]; | ||
| 662 | int fd, copy; | ||
| 663 | Article *reply; | ||
| 664 | |||
| 665 | sprint(tmp, "%d/article", m->n); | ||
| 666 | p = estrstrdup(dir, tmp); | ||
| 667 | if((fd = open(p, OREAD)) < 0){ | ||
| 668 | free(p); | ||
| 669 | return; | ||
| 670 | } | ||
| 671 | free(p); | ||
| 672 | |||
| 673 | reply = newpost(); | ||
| 674 | winopenbody(reply->w, OWRITE); | ||
| 675 | b = emalloc(sizeof(*b)); | ||
| 676 | Binit(b, fd, OREAD); | ||
| 677 | copy = 0; | ||
| 678 | while(p = Brdline(b, '\n')){ | ||
| 679 | if(Blinelen(b)==1) | ||
| 680 | break; | ||
| 681 | ep = p+Blinelen(b); | ||
| 682 | if(!isspace(*p)){ | ||
| 683 | copy = 0; | ||
| 684 | if(cistrncmp(p, "newsgroups:", 11)==0){ | ||
| 685 | for(q=p+11; *q!='\n'; q++) | ||
| 686 | if(*q==',') | ||
| 687 | *q = ' '; | ||
| 688 | copy = 1; | ||
| 689 | }else if(cistrncmp(p, "subject:", 8)==0){ | ||
| 690 | if(!strstr(p, " Re:") && !strstr(p, " RE:") && !strstr(p, " re:")){ | ||
| 691 | p = skip(p, "subject:"); | ||
| 692 | ep[-1] = '\0'; | ||
| 693 | Bprint(reply->w->body, "Subject: Re: %s\n", p); | ||
| 694 | }else | ||
| 695 | copy = 1; | ||
| 696 | }else if(cistrncmp(p, "message-id:", 11)==0){ | ||
| 697 | Bprint(reply->w->body, "References: "); | ||
| 698 | p += 11; | ||
| 699 | copy = 1; | ||
| 700 | } | ||
| 701 | } | ||
| 702 | if(copy) | ||
| 703 | Bwrite(reply->w->body, p, ep-p); | ||
| 704 | } | ||
| 705 | Bterm(b); | ||
| 706 | close(fd); | ||
| 707 | free(b); | ||
| 708 | Bprint(reply->w->body, "\n"); | ||
| 709 | winclean(reply->w); | ||
| 710 | winselect(reply->w, "$", 0); | ||
| 711 | } | ||
| 712 | |||
| 713 | char* | ||
| 714 | skipbl(char *s, char *e) | ||
| 715 | { | ||
| 716 | while(s < e){ | ||
| 717 | if(*s!=' ' && *s!='\t' && *s!=',') | ||
| 718 | break; | ||
| 719 | s++; | ||
| 720 | } | ||
| 721 | return s; | ||
| 722 | } | ||
| 723 | |||
| 724 | char* | ||
| 725 | findbl(char *s, char *e) | ||
| 726 | { | ||
| 727 | while(s < e){ | ||
| 728 | if(*s==' ' || *s=='\t' || *s==',') | ||
| 729 | break; | ||
| 730 | s++; | ||
| 731 | } | ||
| 732 | return s; | ||
| 733 | } | ||
| 734 | |||
| 735 | /* | ||
| 736 | * comma-separate possibly blank-separated strings in line; e points before newline | ||
| 737 | */ | ||
| 738 | void | ||
| 739 | commas(char *s, char *e) | ||
| 740 | { | ||
| 741 | char *t; | ||
| 742 | |||
| 743 | /* may have initial blanks */ | ||
| 744 | s = skipbl(s, e); | ||
| 745 | while(s < e){ | ||
| 746 | s = findbl(s, e); | ||
| 747 | if(s == e) | ||
| 748 | break; | ||
| 749 | t = skipbl(s, e); | ||
| 750 | if(t == e) /* no more words */ | ||
| 751 | break; | ||
| 752 | /* patch comma */ | ||
| 753 | *s++ = ','; | ||
| 754 | while(s < t) | ||
| 755 | *s++ = ' '; | ||
| 756 | } | ||
| 757 | } | ||
| 758 | void | ||
| 759 | mesgpost(Article *m) | ||
| 760 | { | ||
| 761 | Biobuf *b; | ||
| 762 | char *p, *ep; | ||
| 763 | int isfirst, ishdr, havegroup, havefrom; | ||
| 764 | |||
| 765 | p = estrstrdup(dir, "post"); | ||
| 766 | if((b = Bopen(p, OWRITE)) == nil){ | ||
| 767 | fprint(2, "cannot open %s: %r\n", p); | ||
| 768 | free(p); | ||
| 769 | return; | ||
| 770 | } | ||
| 771 | free(p); | ||
| 772 | |||
| 773 | winopenbody(m->w, OREAD); | ||
| 774 | ishdr = 1; | ||
| 775 | isfirst = 1; | ||
| 776 | havegroup = havefrom = 0; | ||
| 777 | while(p = Brdline(m->w->body, '\n')){ | ||
| 778 | ep = p+Blinelen(m->w->body); | ||
| 779 | if(ishdr && p+1==ep){ | ||
| 780 | if(!havegroup) | ||
| 781 | Bprint(b, "Newsgroups: %s\n", group); | ||
| 782 | if(!havefrom) | ||
| 783 | Bprint(b, "From: %s\n", from); | ||
| 784 | ishdr = 0; | ||
| 785 | } | ||
| 786 | if(ishdr){ | ||
| 787 | ep[-1] = '\0'; | ||
| 788 | if(isfirst && strchr(p, ':')==0){ /* group list */ | ||
| 789 | commas(p, ep); | ||
| 790 | Bprint(b, "newsgroups: %s\n", p); | ||
| 791 | havegroup = 1; | ||
| 792 | isfirst = 0; | ||
| 793 | continue; | ||
| 794 | } | ||
| 795 | if(cistrncmp(p, "newsgroup:", 10)==0){ | ||
| 796 | commas(skip(p, "newsgroup:"), ep); | ||
| 797 | Bprint(b, "newsgroups: %s\n", skip(p, "newsgroup:")); | ||
| 798 | havegroup = 1; | ||
| 799 | continue; | ||
| 800 | } | ||
| 801 | if(cistrncmp(p, "newsgroups:", 11)==0){ | ||
| 802 | commas(skip(p, "newsgroups:"), ep); | ||
| 803 | Bprint(b, "newsgroups: %s\n", skip(p, "newsgroups:")); | ||
| 804 | havegroup = 1; | ||
| 805 | continue; | ||
| 806 | } | ||
| 807 | if(cistrncmp(p, "from:", 5)==0) | ||
| 808 | havefrom = 1; | ||
| 809 | ep[-1] = '\n'; | ||
| 810 | } | ||
| 811 | Bwrite(b, p, ep-p); | ||
| 812 | } | ||
| 813 | winclosebody(m->w); | ||
| 814 | Bflush(b); | ||
| 815 | if(write(Bfildes(b), "", 0) == 0) | ||
| 816 | winclean(m->w); | ||
| 817 | else | ||
| 818 | fprint(2, "post: %r\n"); | ||
| 819 | Bterm(b); | ||
| 820 | } | ||
| 821 | |||
| 822 | int | ||
| 823 | mesgopen(char *s) | ||
| 824 | { | ||
| 825 | char *p, tmp[40]; | ||
| 826 | int fd, n; | ||
| 827 | Article *m; | ||
| 828 | |||
| 829 | n = atoi(s); | ||
| 830 | if(n==0) | ||
| 831 | return 0; | ||
| 832 | |||
| 833 | for(m=mlist; m; m=m->next){ | ||
| 834 | if(m->n == n){ | ||
| 835 | ctlprint(m->w->ctl, "show\n"); | ||
| 836 | return 1; | ||
| 837 | } | ||
| 838 | } | ||
| 839 | |||
| 840 | sprint(tmp, "%d/article", n); | ||
| 841 | p = estrstrdup(dir, tmp); | ||
| 842 | if((fd = open(p, OREAD)) < 0){ | ||
| 843 | free(p); | ||
| 844 | return 0; | ||
| 845 | } | ||
| 846 | |||
| 847 | m = emalloc(sizeof(*m)); | ||
| 848 | m->w = newwindow(); | ||
| 849 | m->n = n; | ||
| 850 | proccreate(wineventproc, m->w, STACK); | ||
| 851 | p[strlen(p)-strlen("article")] = '\0'; | ||
| 852 | winname(m->w, p); | ||
| 853 | if(canpost) | ||
| 854 | wintagwrite(m->w, "Reply ", 6); | ||
| 855 | wintagwrite(m->w, "Headers ", 8); | ||
| 856 | |||
| 857 | free(p); | ||
| 858 | if(mlist){ | ||
| 859 | m->next = mlist; | ||
| 860 | mlist->prev = m; | ||
| 861 | } | ||
| 862 | mlist = m; | ||
| 863 | threadcreate(mesgthread, m, STACK); | ||
| 864 | |||
| 865 | fillmesgwindow(fd, m); | ||
| 866 | close(fd); | ||
| 867 | windormant(m->w); | ||
| 868 | return 1; | ||
| 869 | } | ||
| 870 | |||
| 871 | void | ||
| 872 | usage(void) | ||
| 873 | { | ||
| 874 | fprint(2, "usage: News [-d /mnt/news] comp.os.plan9\n"); | ||
| 875 | exits("usage"); | ||
| 876 | } | ||
| 877 | |||
| 878 | void | ||
| 879 | timerproc(void *v) | ||
| 880 | { | ||
| 881 | Event e; | ||
| 882 | Window *w; | ||
| 883 | |||
| 884 | memset(&e, 0, sizeof e); | ||
| 885 | e.c1 = 'T'; | ||
| 886 | w = v; | ||
| 887 | |||
| 888 | for(;;){ | ||
| 889 | sleep(60*1000); | ||
| 890 | sendp(w->cevent, &e); | ||
| 891 | } | ||
| 892 | } | ||
| 893 | |||
| 894 | char* | ||
| 895 | findfrom(void) | ||
| 896 | { | ||
| 897 | char *p, *u; | ||
| 898 | Biobuf *b; | ||
| 899 | |||
| 900 | u = getuser(); | ||
| 901 | if(u==nil) | ||
| 902 | return "glenda"; | ||
| 903 | |||
| 904 | p = estrstrstrdup("/usr/", u, "/lib/newsfrom"); | ||
| 905 | b = Bopen(p, OREAD); | ||
| 906 | free(p); | ||
| 907 | if(b){ | ||
| 908 | p = Brdline(b, '\n'); | ||
| 909 | if(p){ | ||
| 910 | p[Blinelen(b)-1] = '\0'; | ||
| 911 | p = estrdup(p); | ||
| 912 | Bterm(b); | ||
| 913 | return p; | ||
| 914 | } | ||
| 915 | Bterm(b); | ||
| 916 | } | ||
| 917 | |||
| 918 | p = estrstrstrdup("/mail/box/", u, "/headers"); | ||
| 919 | b = Bopen(p, OREAD); | ||
| 920 | free(p); | ||
| 921 | if(b){ | ||
| 922 | while(p = Brdline(b, '\n')){ | ||
| 923 | p[Blinelen(b)-1] = '\0'; | ||
| 924 | if(cistrncmp(p, "from:", 5)==0){ | ||
| 925 | p = estrdup(skip(p, "from:")); | ||
| 926 | Bterm(b); | ||
| 927 | return p; | ||
| 928 | } | ||
| 929 | } | ||
| 930 | Bterm(b); | ||
| 931 | } | ||
| 932 | |||
| 933 | return u; | ||
| 934 | } | ||
| 935 | |||
| 936 | void | ||
| 937 | threadmain(int argc, char **argv) | ||
| 938 | { | ||
| 939 | char *p, *q; | ||
| 940 | Dir *d; | ||
| 941 | Window *w; | ||
| 942 | |||
| 943 | ARGBEGIN{ | ||
| 944 | case 'D': | ||
| 945 | debug++; | ||
| 946 | break; | ||
| 947 | case 'd': | ||
| 948 | dir = EARGF(usage()); | ||
| 949 | break; | ||
| 950 | default: | ||
| 951 | usage(); | ||
| 952 | break; | ||
| 953 | }ARGEND | ||
| 954 | |||
| 955 | if(argc != 1) | ||
| 956 | usage(); | ||
| 957 | |||
| 958 | from = findfrom(); | ||
| 959 | |||
| 960 | group = estrdup(argv[0]); /* someone will be cute */ | ||
| 961 | while(q=strchr(group, '/')) | ||
| 962 | *q = '.'; | ||
| 963 | |||
| 964 | p = estrdup(argv[0]); | ||
| 965 | while(q=strchr(p, '.')) | ||
| 966 | *q = '/'; | ||
| 967 | p = estrstrstrdup(dir, "/", p); | ||
| 968 | cleanname(p); | ||
| 969 | |||
| 970 | if((d = dirstat(p)) == nil){ /* maybe it is a new group */ | ||
| 971 | if((d = dirstat(dir)) == nil){ | ||
| 972 | fprint(2, "dirstat(%s) fails: %r\n", dir); | ||
| 973 | threadexitsall(nil); | ||
| 974 | } | ||
| 975 | if((d->mode&DMDIR)==0){ | ||
| 976 | fprint(2, "%s not a directory\n", dir); | ||
| 977 | threadexitsall(nil); | ||
| 978 | } | ||
| 979 | free(d); | ||
| 980 | if((d = dirstat(p)) == nil){ | ||
| 981 | fprint(2, "stat %s: %r\n", p); | ||
| 982 | threadexitsall(nil); | ||
| 983 | } | ||
| 984 | } | ||
| 985 | if((d->mode&DMDIR)==0){ | ||
| 986 | fprint(2, "%s not a directory\n", dir); | ||
| 987 | threadexitsall(nil); | ||
| 988 | } | ||
| 989 | free(d); | ||
| 990 | dir = estrstrdup(p, "/"); | ||
| 991 | |||
| 992 | q = estrstrdup(dir, "post"); | ||
| 993 | canpost = access(q, AWRITE)==0; | ||
| 994 | |||
| 995 | w = newwindow(); | ||
| 996 | root = w; | ||
| 997 | proccreate(wineventproc, w, STACK); | ||
| 998 | proccreate(timerproc, w, STACK); | ||
| 999 | |||
| 1000 | winname(w, dir); | ||
| 1001 | if(canpost) | ||
| 1002 | wintagwrite(w, "Newpost ", 8); | ||
| 1003 | wintagwrite(w, "More ", 5); | ||
| 1004 | dirwindow(w); | ||
| 1005 | threadcreate(dirthread, w, STACK); | ||
| 1006 | threadexits(nil); | ||
| 1007 | } | ||
Binary file not shown.
Binary file not shown.
| @@ -0,0 +1,106 @@ | |||
| 1 | #include <u.h> | ||
| 2 | #include <libc.h> | ||
| 3 | #include <bio.h> | ||
| 4 | #include <thread.h> | ||
| 5 | #include "win.h" | ||
| 6 | |||
| 7 | void* | ||
| 8 | emalloc(uint n) | ||
| 9 | { | ||
| 10 | void *p; | ||
| 11 | |||
| 12 | p = malloc(n); | ||
| 13 | if(p == nil) | ||
| 14 | error("can't malloc: %r"); | ||
| 15 | memset(p, 0, n); | ||
| 16 | return p; | ||
| 17 | } | ||
| 18 | |||
| 19 | char* | ||
| 20 | estrdup(char *s) | ||
| 21 | { | ||
| 22 | char *t; | ||
| 23 | |||
| 24 | t = emalloc(strlen(s)+1); | ||
| 25 | strcpy(t, s); | ||
| 26 | return t; | ||
| 27 | } | ||
| 28 | |||
| 29 | char* | ||
| 30 | estrstrdup(char *s, char *t) | ||
| 31 | { | ||
| 32 | char *u; | ||
| 33 | |||
| 34 | u = emalloc(strlen(s)+strlen(t)+1); | ||
| 35 | strcpy(u, s); | ||
| 36 | strcat(u, t); | ||
| 37 | return u; | ||
| 38 | } | ||
| 39 | |||
| 40 | char* | ||
| 41 | estrstrstrdup(char *r, char *s, char *t) | ||
| 42 | { | ||
| 43 | char *u; | ||
| 44 | |||
| 45 | u = emalloc(strlen(r)+strlen(s)+strlen(t)+1); | ||
| 46 | strcpy(u, r); | ||
| 47 | strcat(u, s); | ||
| 48 | strcat(u, t); | ||
| 49 | return u; | ||
| 50 | } | ||
| 51 | |||
| 52 | char* | ||
| 53 | eappend(char *s, char *sep, char *t) | ||
| 54 | { | ||
| 55 | char *u; | ||
| 56 | |||
| 57 | if(t == nil) | ||
| 58 | u = estrstrdup(s, sep); | ||
| 59 | else{ | ||
| 60 | u = emalloc(strlen(s)+strlen(sep)+strlen(t)+1); | ||
| 61 | strcpy(u, s); | ||
| 62 | strcat(u, sep); | ||
| 63 | strcat(u, t); | ||
| 64 | } | ||
| 65 | free(s); | ||
| 66 | return u; | ||
| 67 | } | ||
| 68 | |||
| 69 | char* | ||
| 70 | egrow(char *s, char *sep, char *t) | ||
| 71 | { | ||
| 72 | s = eappend(s, sep, t); | ||
| 73 | free(t); | ||
| 74 | return s; | ||
| 75 | } | ||
| 76 | |||
| 77 | void | ||
| 78 | error(char *fmt, ...) | ||
| 79 | { | ||
| 80 | va_list arg; | ||
| 81 | char buf[256]; | ||
| 82 | Fmt f; | ||
| 83 | |||
| 84 | fmtfdinit(&f, 2, buf, sizeof buf); | ||
| 85 | fmtprint(&f, "%s: ", argv0); | ||
| 86 | va_start(arg, fmt); | ||
| 87 | fmtprint(&f, fmt, arg); | ||
| 88 | va_end(arg); | ||
| 89 | fmtprint(&f, "\n"); | ||
| 90 | fmtfdflush(&f); | ||
| 91 | threadexitsall(buf); | ||
| 92 | } | ||
| 93 | |||
| 94 | void | ||
| 95 | ctlprint(int fd, char *fmt, ...) | ||
| 96 | { | ||
| 97 | int n; | ||
| 98 | va_list arg; | ||
| 99 | char buf[256]; | ||
| 100 | |||
| 101 | va_start(arg, fmt); | ||
| 102 | n = vfprint(fd, fmt, arg); | ||
| 103 | va_end(arg); | ||
| 104 | if(n < 0) | ||
| 105 | error("control file write(%s) error: %r", buf); | ||
| 106 | } | ||
Binary file not shown.
Binary file not shown.
| @@ -0,0 +1,324 @@ | |||
| 1 | #include <u.h> | ||
| 2 | #include <libc.h> | ||
| 3 | #include <bio.h> | ||
| 4 | #include <thread.h> | ||
| 5 | #include "win.h" | ||
| 6 | |||
| 7 | Window* | ||
| 8 | newwindow(void) | ||
| 9 | { | ||
| 10 | char buf[12]; | ||
| 11 | Window *w; | ||
| 12 | |||
| 13 | w = emalloc(sizeof(Window)); | ||
| 14 | w->ctl = open("/mnt/wsys/new/ctl", ORDWR|OCEXEC); | ||
| 15 | if(w->ctl<0 || read(w->ctl, buf, 12)!=12) | ||
| 16 | error("can't open window ctl file: %r"); | ||
| 17 | ctlprint(w->ctl, "noscroll\n"); | ||
| 18 | w->id = atoi(buf); | ||
| 19 | w->event = winopenfile(w, "event"); | ||
| 20 | w->addr = -1; /* will be opened when needed */ | ||
| 21 | w->body = nil; | ||
| 22 | w->data = -1; | ||
| 23 | w->cevent = chancreate(sizeof(Event*), 0); | ||
| 24 | if(w->cevent == nil) | ||
| 25 | error("cevent is nil: %r"); | ||
| 26 | return w; | ||
| 27 | } | ||
| 28 | |||
| 29 | void | ||
| 30 | winsetdump(Window *w, char *dir, char *cmd) | ||
| 31 | { | ||
| 32 | if(dir != nil) | ||
| 33 | ctlprint(w->ctl, "dumpdir %s\n", dir); | ||
| 34 | if(cmd != nil) | ||
| 35 | ctlprint(w->ctl, "dump %s\n", cmd); | ||
| 36 | } | ||
| 37 | |||
| 38 | void | ||
| 39 | wineventproc(void *v) | ||
| 40 | { | ||
| 41 | Window *w; | ||
| 42 | int i; | ||
| 43 | |||
| 44 | threadsetname("wineventproc"); | ||
| 45 | w = v; | ||
| 46 | for(i=0; ; i++){ | ||
| 47 | if(i >= NEVENT) | ||
| 48 | i = 0; | ||
| 49 | wingetevent(w, &w->e[i]); | ||
| 50 | sendp(w->cevent, &w->e[i]); | ||
| 51 | } | ||
| 52 | } | ||
| 53 | |||
| 54 | int | ||
| 55 | winopenfile(Window *w, char *f) | ||
| 56 | { | ||
| 57 | char buf[64]; | ||
| 58 | int fd; | ||
| 59 | |||
| 60 | sprint(buf, "/mnt/wsys/%d/%s", w->id, f); | ||
| 61 | fd = open(buf, ORDWR|OCEXEC); | ||
| 62 | if(fd < 0) | ||
| 63 | error("can't open window file %s: %r", f); | ||
| 64 | return fd; | ||
| 65 | } | ||
| 66 | |||
| 67 | void | ||
| 68 | wintagwrite(Window *w, char *s, int n) | ||
| 69 | { | ||
| 70 | int fd; | ||
| 71 | |||
| 72 | fd = winopenfile(w, "tag"); | ||
| 73 | if(write(fd, s, n) != n) | ||
| 74 | error("tag write: %r"); | ||
| 75 | close(fd); | ||
| 76 | } | ||
| 77 | |||
| 78 | void | ||
| 79 | winname(Window *w, char *s) | ||
| 80 | { | ||
| 81 | ctlprint(w->ctl, "name %s\n", s); | ||
| 82 | } | ||
| 83 | |||
| 84 | void | ||
| 85 | winopenbody(Window *w, int mode) | ||
| 86 | { | ||
| 87 | char buf[256]; | ||
| 88 | |||
| 89 | sprint(buf, "/mnt/wsys/%d/body", w->id); | ||
| 90 | w->body = Bopen(buf, mode|OCEXEC); | ||
| 91 | if(w->body == nil) | ||
| 92 | error("can't open window body file: %r"); | ||
| 93 | } | ||
| 94 | |||
| 95 | void | ||
| 96 | winclosebody(Window *w) | ||
| 97 | { | ||
| 98 | if(w->body != nil){ | ||
| 99 | Bterm(w->body); | ||
| 100 | w->body = nil; | ||
| 101 | } | ||
| 102 | } | ||
| 103 | |||
| 104 | void | ||
| 105 | winwritebody(Window *w, char *s, int n) | ||
| 106 | { | ||
| 107 | if(w->body == nil) | ||
| 108 | winopenbody(w, OWRITE); | ||
| 109 | if(Bwrite(w->body, s, n) != n) | ||
| 110 | error("write error to window: %r"); | ||
| 111 | } | ||
| 112 | |||
| 113 | int | ||
| 114 | wingetec(Window *w) | ||
| 115 | { | ||
| 116 | if(w->nbuf == 0){ | ||
| 117 | w->nbuf = read(w->event, w->buf, sizeof w->buf); | ||
| 118 | if(w->nbuf <= 0){ | ||
| 119 | /* probably because window has exited, and only called by wineventproc, so just shut down */ | ||
| 120 | threadexits(nil); | ||
| 121 | } | ||
| 122 | w->bufp = w->buf; | ||
| 123 | } | ||
| 124 | w->nbuf--; | ||
| 125 | return *w->bufp++; | ||
| 126 | } | ||
| 127 | |||
| 128 | int | ||
| 129 | wingeten(Window *w) | ||
| 130 | { | ||
| 131 | int n, c; | ||
| 132 | |||
| 133 | n = 0; | ||
| 134 | while('0'<=(c=wingetec(w)) && c<='9') | ||
| 135 | n = n*10+(c-'0'); | ||
| 136 | if(c != ' ') | ||
| 137 | error("event number syntax"); | ||
| 138 | return n; | ||
| 139 | } | ||
| 140 | |||
| 141 | int | ||
| 142 | wingeter(Window *w, char *buf, int *nb) | ||
| 143 | { | ||
| 144 | Rune r; | ||
| 145 | int n; | ||
| 146 | |||
| 147 | r = wingetec(w); | ||
| 148 | buf[0] = r; | ||
| 149 | n = 1; | ||
| 150 | if(r >= Runeself) { | ||
| 151 | while(!fullrune(buf, n)) | ||
| 152 | buf[n++] = wingetec(w); | ||
| 153 | chartorune(&r, buf); | ||
| 154 | } | ||
| 155 | *nb = n; | ||
| 156 | return r; | ||
| 157 | } | ||
| 158 | |||
| 159 | void | ||
| 160 | wingetevent(Window *w, Event *e) | ||
| 161 | { | ||
| 162 | int i, nb; | ||
| 163 | |||
| 164 | e->c1 = wingetec(w); | ||
| 165 | e->c2 = wingetec(w); | ||
| 166 | e->q0 = wingeten(w); | ||
| 167 | e->q1 = wingeten(w); | ||
| 168 | e->flag = wingeten(w); | ||
| 169 | e->nr = wingeten(w); | ||
| 170 | if(e->nr > EVENTSIZE) | ||
| 171 | error("event string too long"); | ||
| 172 | e->nb = 0; | ||
| 173 | for(i=0; i<e->nr; i++){ | ||
| 174 | e->r[i] = wingeter(w, e->b+e->nb, &nb); | ||
| 175 | e->nb += nb; | ||
| 176 | } | ||
| 177 | e->r[e->nr] = 0; | ||
| 178 | e->b[e->nb] = 0; | ||
| 179 | if(wingetec(w) != '\n') | ||
| 180 | error("event syntax error"); | ||
| 181 | } | ||
| 182 | |||
| 183 | void | ||
| 184 | winwriteevent(Window *w, Event *e) | ||
| 185 | { | ||
| 186 | fprint(w->event, "%c%c%d %d\n", e->c1, e->c2, e->q0, e->q1); | ||
| 187 | } | ||
| 188 | |||
| 189 | static int | ||
| 190 | nrunes(char *s, int nb) | ||
| 191 | { | ||
| 192 | int i, n; | ||
| 193 | Rune r; | ||
| 194 | |||
| 195 | n = 0; | ||
| 196 | for(i=0; i<nb; n++) | ||
| 197 | i += chartorune(&r, s+i); | ||
| 198 | return n; | ||
| 199 | } | ||
| 200 | |||
| 201 | void | ||
| 202 | winread(Window *w, uint q0, uint q1, char *data) | ||
| 203 | { | ||
| 204 | int m, n, nr; | ||
| 205 | char buf[256]; | ||
| 206 | |||
| 207 | if(w->addr < 0) | ||
| 208 | w->addr = winopenfile(w, "addr"); | ||
| 209 | if(w->data < 0) | ||
| 210 | w->data = winopenfile(w, "data"); | ||
| 211 | m = q0; | ||
| 212 | while(m < q1){ | ||
| 213 | n = sprint(buf, "#%d", m); | ||
| 214 | if(write(w->addr, buf, n) != n) | ||
| 215 | error("error writing addr: %r"); | ||
| 216 | n = read(w->data, buf, sizeof buf); | ||
| 217 | if(n <= 0) | ||
| 218 | error("reading data: %r"); | ||
| 219 | nr = nrunes(buf, n); | ||
| 220 | while(m+nr >q1){ | ||
| 221 | do; while(n>0 && (buf[--n]&0xC0)==0x80); | ||
| 222 | --nr; | ||
| 223 | } | ||
| 224 | if(n == 0) | ||
| 225 | break; | ||
| 226 | memmove(data, buf, n); | ||
| 227 | data += n; | ||
| 228 | *data = 0; | ||
| 229 | m += nr; | ||
| 230 | } | ||
| 231 | } | ||
| 232 | |||
| 233 | void | ||
| 234 | windormant(Window *w) | ||
| 235 | { | ||
| 236 | if(w->addr >= 0){ | ||
| 237 | close(w->addr); | ||
| 238 | w->addr = -1; | ||
| 239 | } | ||
| 240 | if(w->body != nil){ | ||
| 241 | Bterm(w->body); | ||
| 242 | w->body = nil; | ||
| 243 | } | ||
| 244 | if(w->data >= 0){ | ||
| 245 | close(w->data); | ||
| 246 | w->data = -1; | ||
| 247 | } | ||
| 248 | } | ||
| 249 | |||
| 250 | |||
| 251 | int | ||
| 252 | windel(Window *w, int sure) | ||
| 253 | { | ||
| 254 | if(sure) | ||
| 255 | write(w->ctl, "delete\n", 7); | ||
| 256 | else if(write(w->ctl, "del\n", 4) != 4) | ||
| 257 | return 0; | ||
| 258 | /* event proc will die due to read error from event file */ | ||
| 259 | windormant(w); | ||
| 260 | close(w->ctl); | ||
| 261 | w->ctl = -1; | ||
| 262 | close(w->event); | ||
| 263 | w->event = -1; | ||
| 264 | return 1; | ||
| 265 | } | ||
| 266 | |||
| 267 | void | ||
| 268 | winclean(Window *w) | ||
| 269 | { | ||
| 270 | if(w->body) | ||
| 271 | Bflush(w->body); | ||
| 272 | ctlprint(w->ctl, "clean\n"); | ||
| 273 | } | ||
| 274 | |||
| 275 | int | ||
| 276 | winsetaddr(Window *w, char *addr, int errok) | ||
| 277 | { | ||
| 278 | if(w->addr < 0) | ||
| 279 | w->addr = winopenfile(w, "addr"); | ||
| 280 | if(write(w->addr, addr, strlen(addr)) < 0){ | ||
| 281 | if(!errok) | ||
| 282 | error("error writing addr(%s): %r", addr); | ||
| 283 | return 0; | ||
| 284 | } | ||
| 285 | return 1; | ||
| 286 | } | ||
| 287 | |||
| 288 | int | ||
| 289 | winselect(Window *w, char *addr, int errok) | ||
| 290 | { | ||
| 291 | if(winsetaddr(w, addr, errok)){ | ||
| 292 | ctlprint(w->ctl, "dot=addr\n"); | ||
| 293 | return 1; | ||
| 294 | } | ||
| 295 | return 0; | ||
| 296 | } | ||
| 297 | |||
| 298 | char* | ||
| 299 | winreadbody(Window *w, int *np) /* can't use readfile because acme doesn't report the length */ | ||
| 300 | { | ||
| 301 | char *s; | ||
| 302 | int m, na, n; | ||
| 303 | |||
| 304 | if(w->body != nil) | ||
| 305 | winclosebody(w); | ||
| 306 | winopenbody(w, OREAD); | ||
| 307 | s = nil; | ||
| 308 | na = 0; | ||
| 309 | n = 0; | ||
| 310 | for(;;){ | ||
| 311 | if(na < n+512){ | ||
| 312 | na += 1024; | ||
| 313 | s = realloc(s, na+1); | ||
| 314 | } | ||
| 315 | m = Bread(w->body, s+n, na-n); | ||
| 316 | if(m <= 0) | ||
| 317 | break; | ||
| 318 | n += m; | ||
| 319 | } | ||
| 320 | s[n] = 0; | ||
| 321 | winclosebody(w); | ||
| 322 | *np = n; | ||
| 323 | return s; | ||
| 324 | } | ||
| @@ -0,0 +1,75 @@ | |||
| 1 | /* acme */ | ||
| 2 | typedef struct Event Event; | ||
| 3 | typedef struct Window Window; | ||
| 4 | |||
| 5 | enum | ||
| 6 | { | ||
| 7 | STACK = 8192, | ||
| 8 | EVENTSIZE = 256, | ||
| 9 | NEVENT = 5, | ||
| 10 | }; | ||
| 11 | |||
| 12 | struct Event | ||
| 13 | { | ||
| 14 | int c1; | ||
| 15 | int c2; | ||
| 16 | int q0; | ||
| 17 | int q1; | ||
| 18 | int flag; | ||
| 19 | int nb; | ||
| 20 | int nr; | ||
| 21 | char b[EVENTSIZE*UTFmax+1]; | ||
| 22 | Rune r[EVENTSIZE+1]; | ||
| 23 | }; | ||
| 24 | |||
| 25 | struct Window | ||
| 26 | { | ||
| 27 | /* file descriptors */ | ||
| 28 | int ctl; | ||
| 29 | int event; | ||
| 30 | int addr; | ||
| 31 | int data; | ||
| 32 | Biobuf *body; | ||
| 33 | |||
| 34 | /* event input */ | ||
| 35 | char buf[512]; | ||
| 36 | char *bufp; | ||
| 37 | int nbuf; | ||
| 38 | Event e[NEVENT]; | ||
| 39 | |||
| 40 | int dirtied; | ||
| 41 | int id; | ||
| 42 | int open; | ||
| 43 | Channel *cevent; /* chan(Event*) */ | ||
| 44 | }; | ||
| 45 | |||
| 46 | extern Window* newwindow(void); | ||
| 47 | extern int winopenfile(Window*, char*); | ||
| 48 | extern void winopenbody(Window*, int); | ||
| 49 | extern void winclosebody(Window*); | ||
| 50 | extern void wintagwrite(Window*, char*, int); | ||
| 51 | extern void winname(Window*, char*); | ||
| 52 | extern void winwriteevent(Window*, Event*); | ||
| 53 | extern void winread(Window*, uint, uint, char*); | ||
| 54 | extern int windel(Window*, int); | ||
| 55 | extern void wingetevent(Window*, Event*); | ||
| 56 | extern void wineventproc(void*); | ||
| 57 | extern void winwritebody(Window*, char*, int); | ||
| 58 | extern void winclean(Window*); | ||
| 59 | extern int winselect(Window*, char*, int); | ||
| 60 | extern int winsetaddr(Window*, char*, int); | ||
| 61 | extern char* winreadbody(Window*, int*); | ||
| 62 | extern void windormant(Window*); | ||
| 63 | extern void winsetdump(Window*, char*, char*); | ||
| 64 | |||
| 65 | extern char* readfile(char*, char*, int*); | ||
| 66 | extern void ctlprint(int, char*, ...); | ||
| 67 | extern void* emalloc(uint); | ||
| 68 | extern char* estrdup(char*); | ||
| 69 | extern char* estrstrdup(char*, char*); | ||
| 70 | extern char* estrstrstrdup(char*, char*, char*); | ||
| 71 | extern char* egrow(char*, char*, char*); | ||
| 72 | extern char* eappend(char*, char*, char*); | ||
| 73 | extern void error(char*, ...); | ||
| 74 | extern int tokenizec(char*, char**, int, char*); | ||
| 75 | |||
| @@ -0,0 +1,3 @@ | |||
| 1 | Local 9fs wiki | ||
| 2 | # Local wikifs /sys/lib/wiki | ||
| 3 | Wiki /mnt/wiki | ||
Binary file not shown.
Binary file not shown.
| @@ -0,0 +1,114 @@ | |||
| 1 | #include <u.h> | ||
| 2 | #include <libc.h> | ||
| 3 | #include <bio.h> | ||
| 4 | #include <thread.h> | ||
| 5 | |||
| 6 | /* acme */ | ||
| 7 | typedef struct Event Event; | ||
| 8 | typedef struct Window Window; | ||
| 9 | |||
| 10 | enum | ||
| 11 | { | ||
| 12 | STACK = 8192, | ||
| 13 | EVENTSIZE = 256, | ||
| 14 | NEVENT = 5, | ||
| 15 | }; | ||
| 16 | |||
| 17 | struct Event | ||
| 18 | { | ||
| 19 | int c1; | ||
| 20 | int c2; | ||
| 21 | int q0; | ||
| 22 | int q1; | ||
| 23 | int flag; | ||
| 24 | int nb; | ||
| 25 | int nr; | ||
| 26 | char b[EVENTSIZE*UTFmax+1]; | ||
| 27 | Rune r[EVENTSIZE+1]; | ||
| 28 | }; | ||
| 29 | |||
| 30 | struct Window | ||
| 31 | { | ||
| 32 | /* file descriptors */ | ||
| 33 | int ctl; | ||
| 34 | int event; | ||
| 35 | int addr; | ||
| 36 | int data; | ||
| 37 | Biobuf *body; | ||
| 38 | |||
| 39 | /* event input */ | ||
| 40 | char buf[512]; | ||
| 41 | char *bufp; | ||
| 42 | int nbuf; | ||
| 43 | Event e[NEVENT]; | ||
| 44 | |||
| 45 | int warned; | ||
| 46 | int id; | ||
| 47 | int open; | ||
| 48 | Channel *cevent; /* chan(Event*) */ | ||
| 49 | }; | ||
| 50 | |||
| 51 | extern Window* newwindow(void); | ||
| 52 | extern int winopenfile(Window*, char*); | ||
| 53 | extern void winopenbody(Window*, int); | ||
| 54 | extern void winclosebody(Window*); | ||
| 55 | extern void wintagwrite(Window*, char*, int); | ||
| 56 | extern void winname(Window*, char*); | ||
| 57 | extern void winwriteevent(Window*, Event*); | ||
| 58 | extern void winread(Window*, uint, uint, char*); | ||
| 59 | extern int windel(Window*, int); | ||
| 60 | extern void wingetevent(Window*, Event*); | ||
| 61 | extern void wineventproc(void*); | ||
| 62 | extern void winwritebody(Window*, char*, int); | ||
| 63 | extern void winclean(Window*); | ||
| 64 | extern int winisdirty(Window*); | ||
| 65 | extern int winselect(Window*, char*, int); | ||
| 66 | extern int winsetaddr(Window*, char*, int); | ||
| 67 | extern char* winreadbody(Window*, int*); | ||
| 68 | extern void windormant(Window*); | ||
| 69 | extern void winsetdump(Window*, char*, char*); | ||
| 70 | |||
| 71 | extern char* readfile(char*, char*, int*); | ||
| 72 | extern void ctlprint(int, char*, ...); | ||
| 73 | extern void* emalloc(uint); | ||
| 74 | extern char* estrdup(char*); | ||
| 75 | extern char* estrstrdup(char*, char*); | ||
| 76 | extern char* egrow(char*, char*, char*); | ||
| 77 | extern char* eappend(char*, char*, char*); | ||
| 78 | extern void error(char*, ...); | ||
| 79 | extern int tokenizec(char*, char**, int, char*); | ||
| 80 | |||
| 81 | typedef struct Treq Treq; | ||
| 82 | typedef struct Wiki Wiki; | ||
| 83 | |||
| 84 | struct Treq { | ||
| 85 | char *title; | ||
| 86 | Channel *c; /* chan(int) */ | ||
| 87 | }; | ||
| 88 | |||
| 89 | struct Wiki { | ||
| 90 | QLock; | ||
| 91 | int isnew; | ||
| 92 | int special; | ||
| 93 | char *arg; | ||
| 94 | char *addr; | ||
| 95 | int n; | ||
| 96 | int dead; | ||
| 97 | Window *win; | ||
| 98 | ulong time; | ||
| 99 | int linked; | ||
| 100 | Wiki *next; | ||
| 101 | Wiki *prev; | ||
| 102 | }; | ||
| 103 | |||
| 104 | extern int debug; | ||
| 105 | extern int mapfd; | ||
| 106 | extern char *email; | ||
| 107 | extern char *dir; | ||
| 108 | |||
| 109 | void wikinew(char*); | ||
| 110 | int wikiopen(char*, char*); | ||
| 111 | int wikiput(Wiki*); | ||
| 112 | void wikiget(Wiki*); | ||
| 113 | int wikidiff(Wiki*); | ||
| 114 | |||
Binary file not shown.
Binary file not shown.
| @@ -0,0 +1,60 @@ | |||
| 1 | #include "awiki.h" | ||
| 2 | |||
| 3 | int debug; | ||
| 4 | int mapfd; | ||
| 5 | char *email; | ||
| 6 | char *dir; | ||
| 7 | |||
| 8 | void | ||
| 9 | usage(void) | ||
| 10 | { | ||
| 11 | fprint(2, "usage: Wiki [-e email] [dir]\n"); | ||
| 12 | exits("usage"); | ||
| 13 | } | ||
| 14 | |||
| 15 | void | ||
| 16 | threadmain(int argc, char **argv) | ||
| 17 | { | ||
| 18 | char *s; | ||
| 19 | Dir *d; | ||
| 20 | |||
| 21 | rfork(RFNAMEG); | ||
| 22 | ARGBEGIN{ | ||
| 23 | case 'D': | ||
| 24 | debug++; | ||
| 25 | break; | ||
| 26 | case 'e': | ||
| 27 | email = EARGF(usage()); | ||
| 28 | break; | ||
| 29 | default: | ||
| 30 | usage(); | ||
| 31 | break; | ||
| 32 | }ARGEND | ||
| 33 | |||
| 34 | if(argc > 1) | ||
| 35 | usage(); | ||
| 36 | if(argc == 1) | ||
| 37 | dir = argv[0]; | ||
| 38 | else | ||
| 39 | dir = "/mnt/wiki"; | ||
| 40 | |||
| 41 | if(chdir(dir) < 0){ | ||
| 42 | fprint(2, "chdir(%s) fails: %r\n", dir); | ||
| 43 | threadexitsall(nil); | ||
| 44 | } | ||
| 45 | |||
| 46 | if((mapfd = open("map", ORDWR)) < 0){ | ||
| 47 | fprint(2, "open(map): %r\n"); | ||
| 48 | threadexitsall(nil); | ||
| 49 | } | ||
| 50 | |||
| 51 | if((d = dirstat("1")) == nil){ | ||
| 52 | fprint(2, "dirstat(%s/1) fails: %r\n", dir); | ||
| 53 | threadexitsall(nil); | ||
| 54 | } | ||
| 55 | s = emalloc(strlen(d->name)+2); | ||
| 56 | strcpy(s, d->name); | ||
| 57 | strcat(s, "/"); | ||
| 58 | wikiopen(s, nil); | ||
| 59 | threadexits(nil); | ||
| 60 | } | ||
| @@ -0,0 +1,14 @@ | |||
| 1 | </$objtype/mkfile | ||
| 2 | |||
| 3 | TARG=Wiki | ||
| 4 | |||
| 5 | OFILES=\ | ||
| 6 | main.$O\ | ||
| 7 | util.$O\ | ||
| 8 | wiki.$O\ | ||
| 9 | win.$O\ | ||
| 10 | |||
| 11 | HFILES=awiki.h | ||
| 12 | BIN=../../bin/$objtype | ||
| 13 | |||
| 14 | </sys/src/cmd/mkone | ||
Binary file not shown.
Binary file not shown.
| @@ -0,0 +1,89 @@ | |||
| 1 | #include "awiki.h" | ||
| 2 | |||
| 3 | void* | ||
| 4 | emalloc(uint n) | ||
| 5 | { | ||
| 6 | void *p; | ||
| 7 | |||
| 8 | p = malloc(n); | ||
| 9 | if(p == nil) | ||
| 10 | error("can't malloc: %r"); | ||
| 11 | memset(p, 0, n); | ||
| 12 | return p; | ||
| 13 | } | ||
| 14 | |||
| 15 | char* | ||
| 16 | estrdup(char *s) | ||
| 17 | { | ||
| 18 | char *t; | ||
| 19 | |||
| 20 | t = emalloc(strlen(s)+1); | ||
| 21 | strcpy(t, s); | ||
| 22 | return t; | ||
| 23 | } | ||
| 24 | |||
| 25 | char* | ||
| 26 | estrstrdup(char *s, char *t) | ||
| 27 | { | ||
| 28 | char *u; | ||
| 29 | |||
| 30 | u = emalloc(strlen(s)+strlen(t)+1); | ||
| 31 | strcpy(u, s); | ||
| 32 | strcat(u, t); | ||
| 33 | return u; | ||
| 34 | } | ||
| 35 | |||
| 36 | char* | ||
| 37 | eappend(char *s, char *sep, char *t) | ||
| 38 | { | ||
| 39 | char *u; | ||
| 40 | |||
| 41 | if(t == nil) | ||
| 42 | u = estrstrdup(s, sep); | ||
| 43 | else{ | ||
| 44 | u = emalloc(strlen(s)+strlen(sep)+strlen(t)+1); | ||
| 45 | strcpy(u, s); | ||
| 46 | strcat(u, sep); | ||
| 47 | strcat(u, t); | ||
| 48 | } | ||
| 49 | free(s); | ||
| 50 | return u; | ||
| 51 | } | ||
| 52 | |||
| 53 | char* | ||
| 54 | egrow(char *s, char *sep, char *t) | ||
| 55 | { | ||
| 56 | s = eappend(s, sep, t); | ||
| 57 | free(t); | ||
| 58 | return s; | ||
| 59 | } | ||
| 60 | |||
| 61 | void | ||
| 62 | error(char *fmt, ...) | ||
| 63 | { | ||
| 64 | int n; | ||
| 65 | va_list arg; | ||
| 66 | char buf[256]; | ||
| 67 | |||
| 68 | fprint(2, "Wiki: "); | ||
| 69 | va_start(arg, fmt); | ||
| 70 | n = vseprint(buf, buf+sizeof buf, fmt, arg) - buf; | ||
| 71 | va_end(arg); | ||
| 72 | write(2, buf, n); | ||
| 73 | write(2, "\n", 1); | ||
| 74 | threadexitsall(buf); | ||
| 75 | } | ||
| 76 | |||
| 77 | void | ||
| 78 | ctlprint(int fd, char *fmt, ...) | ||
| 79 | { | ||
| 80 | int n; | ||
| 81 | va_list arg; | ||
| 82 | char buf[256]; | ||
| 83 | |||
| 84 | va_start(arg, fmt); | ||
| 85 | n = vseprint(buf, buf+sizeof buf, fmt, arg) - buf; | ||
| 86 | va_end(arg); | ||
| 87 | if(write(fd, buf, n) != n) | ||
| 88 | error("control file write(%s) error: %r", buf); | ||
| 89 | } | ||
Binary file not shown.
Binary file not shown.
| @@ -0,0 +1,602 @@ | |||
| 1 | #include "awiki.h" | ||
| 2 | |||
| 3 | Wiki *wlist; | ||
| 4 | |||
| 5 | void | ||
| 6 | link(Wiki *w) | ||
| 7 | { | ||
| 8 | if(w->linked) | ||
| 9 | return; | ||
| 10 | w->linked = 1; | ||
| 11 | w->prev = nil; | ||
| 12 | w->next = wlist; | ||
| 13 | if(wlist) | ||
| 14 | wlist->prev = w; | ||
| 15 | wlist = w; | ||
| 16 | } | ||
| 17 | |||
| 18 | void | ||
| 19 | unlink(Wiki *w) | ||
| 20 | { | ||
| 21 | if(!w->linked) | ||
| 22 | return; | ||
| 23 | w->linked = 0; | ||
| 24 | |||
| 25 | if(w->next) | ||
| 26 | w->next->prev = w->prev; | ||
| 27 | if(w->prev) | ||
| 28 | w->prev->next = w->next; | ||
| 29 | else | ||
| 30 | wlist = w->next; | ||
| 31 | |||
| 32 | w->next = nil; | ||
| 33 | w->prev = nil; | ||
| 34 | } | ||
| 35 | |||
| 36 | void | ||
| 37 | wikiname(Window *w, char *name) | ||
| 38 | { | ||
| 39 | char *p, *q; | ||
| 40 | |||
| 41 | p = emalloc(strlen(dir)+1+strlen(name)+1+1); | ||
| 42 | strcpy(p, dir); | ||
| 43 | strcat(p, "/"); | ||
| 44 | strcat(p, name); | ||
| 45 | for(q=p; *q; q++) | ||
| 46 | if(*q==' ') | ||
| 47 | *q = '_'; | ||
| 48 | winname(w, p); | ||
| 49 | free(p); | ||
| 50 | } | ||
| 51 | |||
| 52 | int | ||
| 53 | wikiput(Wiki *w) | ||
| 54 | { | ||
| 55 | int fd, n; | ||
| 56 | char buf[1024], *p; | ||
| 57 | Biobuf *b; | ||
| 58 | |||
| 59 | if((fd = open("new", ORDWR)) < 0){ | ||
| 60 | fprint(2, "Wiki: cannot open raw: %r\n"); | ||
| 61 | return -1; | ||
| 62 | } | ||
| 63 | |||
| 64 | winopenbody(w->win, OREAD); | ||
| 65 | b = w->win->body; | ||
| 66 | if((p = Brdline(b, '\n'))==nil){ | ||
| 67 | Short: | ||
| 68 | winclosebody(w->win); | ||
| 69 | fprint(2, "Wiki: no data\n"); | ||
| 70 | close(fd); | ||
| 71 | return -1; | ||
| 72 | } | ||
| 73 | write(fd, p, Blinelen(b)); | ||
| 74 | |||
| 75 | snprint(buf, sizeof buf, "D%lud\n", w->time); | ||
| 76 | if(email) | ||
| 77 | snprint(buf+strlen(buf), sizeof(buf)-strlen(buf), "A%s\n", email); | ||
| 78 | |||
| 79 | if(Bgetc(b) == '#'){ | ||
| 80 | p = Brdline(b, '\n'); | ||
| 81 | if(p == nil) | ||
| 82 | goto Short; | ||
| 83 | snprint(buf+strlen(buf), sizeof(buf)-strlen(buf), "C%s\n", p); | ||
| 84 | } | ||
| 85 | write(fd, buf, strlen(buf)); | ||
| 86 | write(fd, "\n\n", 2); | ||
| 87 | |||
| 88 | while((n = Bread(b, buf, sizeof buf)) > 0) | ||
| 89 | write(fd, buf, n); | ||
| 90 | winclosebody(w->win); | ||
| 91 | |||
| 92 | werrstr(""); | ||
| 93 | if((n=write(fd, "", 0)) != 0){ | ||
| 94 | fprint(2, "Wiki commit %lud %d %d: %r\n", w->time, fd, n); | ||
| 95 | close(fd); | ||
| 96 | return -1; | ||
| 97 | } | ||
| 98 | seek(fd, 0, 0); | ||
| 99 | if((n = read(fd, buf, 300)) < 0){ | ||
| 100 | fprint(2, "Wiki readback: %r\n"); | ||
| 101 | close(fd); | ||
| 102 | return -1; | ||
| 103 | } | ||
| 104 | close(fd); | ||
| 105 | buf[n] = '\0'; | ||
| 106 | sprint(buf, "%s/", buf); | ||
| 107 | free(w->arg); | ||
| 108 | w->arg = estrdup(buf); | ||
| 109 | w->isnew = 0; | ||
| 110 | wikiget(w); | ||
| 111 | wikiname(w->win, w->arg); | ||
| 112 | return n; | ||
| 113 | } | ||
| 114 | |||
| 115 | void | ||
| 116 | wikiget(Wiki *w) | ||
| 117 | { | ||
| 118 | char *p; | ||
| 119 | int fd, normal; | ||
| 120 | Biobuf *bin; | ||
| 121 | |||
| 122 | fprint(w->win->ctl, "dirty\n"); | ||
| 123 | |||
| 124 | p = emalloc(strlen(w->arg)+8+1); | ||
| 125 | strcpy(p, w->arg); | ||
| 126 | normal = 1; | ||
| 127 | if(p[strlen(p)-1] == '/'){ | ||
| 128 | normal = 0; | ||
| 129 | strcat(p, "current"); | ||
| 130 | }else if(strlen(p)>8 && strcmp(p+strlen(p)-8, "/current")==0){ | ||
| 131 | normal = 0; | ||
| 132 | w->arg[strlen(w->arg)-7] = '\0'; | ||
| 133 | } | ||
| 134 | |||
| 135 | if((fd = open(p, OREAD)) < 0){ | ||
| 136 | fprint(2, "Wiki: cannot read %s: %r\n", p); | ||
| 137 | winclean(w->win); | ||
| 138 | return; | ||
| 139 | } | ||
| 140 | free(p); | ||
| 141 | |||
| 142 | winopenbody(w->win, OWRITE); | ||
| 143 | bin = emalloc(sizeof(*bin)); | ||
| 144 | Binit(bin, fd, OREAD); | ||
| 145 | |||
| 146 | p = nil; | ||
| 147 | if(!normal){ | ||
| 148 | if((p = Brdline(bin, '\n')) == nil){ | ||
| 149 | fprint(2, "Wiki: cannot read title: %r\n"); | ||
| 150 | winclean(w->win); | ||
| 151 | close(fd); | ||
| 152 | free(bin); | ||
| 153 | return; | ||
| 154 | } | ||
| 155 | p[Blinelen(bin)-1] = '\0'; | ||
| 156 | } | ||
| 157 | /* clear window */ | ||
| 158 | if(w->win->data < 0) | ||
| 159 | w->win->data = winopenfile(w->win, "data"); | ||
| 160 | if(winsetaddr(w->win, ",", 0)) | ||
| 161 | write(w->win->data, "", 0); | ||
| 162 | |||
| 163 | if(!normal) | ||
| 164 | Bprint(w->win->body, "%s\n\n", p); | ||
| 165 | |||
| 166 | while(p = Brdline(bin, '\n')){ | ||
| 167 | p[Blinelen(bin)-1] = '\0'; | ||
| 168 | if(normal) | ||
| 169 | Bprint(w->win->body, "%s\n", p); | ||
| 170 | else{ | ||
| 171 | if(p[0]=='D') | ||
| 172 | w->time = strtoul(p+1, 0, 10); | ||
| 173 | else if(p[0]=='#') | ||
| 174 | Bprint(w->win->body, "%s\n", p+1); | ||
| 175 | } | ||
| 176 | } | ||
| 177 | winclean(w->win); | ||
| 178 | free(bin); | ||
| 179 | close(fd); | ||
| 180 | } | ||
| 181 | |||
| 182 | static int | ||
| 183 | iscmd(char *s, char *cmd) | ||
| 184 | { | ||
| 185 | int len; | ||
| 186 | |||
| 187 | len = strlen(cmd); | ||
| 188 | return strncmp(s, cmd, len)==0 && (s[len]=='\0' || s[len]==' ' || s[len]=='\t' || s[len]=='\n'); | ||
| 189 | } | ||
| 190 | |||
| 191 | static char* | ||
| 192 | skip(char *s, char *cmd) | ||
| 193 | { | ||
| 194 | s += strlen(cmd); | ||
| 195 | while(*s==' ' || *s=='\t' || *s=='\n') | ||
| 196 | s++; | ||
| 197 | return s; | ||
| 198 | } | ||
| 199 | |||
| 200 | int | ||
| 201 | wikiload(Wiki *w, char *arg) | ||
| 202 | { | ||
| 203 | char *p, *q, *path, *addr; | ||
| 204 | int rv; | ||
| 205 | |||
| 206 | p = nil; | ||
| 207 | if(arg[0] == '/') | ||
| 208 | path = arg; | ||
| 209 | else{ | ||
| 210 | p = emalloc(strlen(w->arg)+1+strlen(arg)+1); | ||
| 211 | strcpy(p, w->arg); | ||
| 212 | if(q = strrchr(p, '/')){ | ||
| 213 | ++q; | ||
| 214 | *q = '\0'; | ||
| 215 | }else | ||
| 216 | *p = '\0'; | ||
| 217 | strcat(p, arg); | ||
| 218 | cleanname(p); | ||
| 219 | path = p; | ||
| 220 | } | ||
| 221 | if(addr=strchr(path, ':')) | ||
| 222 | *addr++ = '\0'; | ||
| 223 | |||
| 224 | rv = wikiopen(path, addr)==0; | ||
| 225 | free(p); | ||
| 226 | if(rv) | ||
| 227 | return 1; | ||
| 228 | return wikiopen(arg, 0)==0; | ||
| 229 | } | ||
| 230 | |||
| 231 | /* return 1 if handled, 0 otherwise */ | ||
| 232 | int | ||
| 233 | wikicmd(Wiki *w, char *s) | ||
| 234 | { | ||
| 235 | char *p; | ||
| 236 | s = skip(s, ""); | ||
| 237 | |||
| 238 | if(iscmd(s, "Del")){ | ||
| 239 | if(windel(w->win, 0)) | ||
| 240 | w->dead = 1; | ||
| 241 | return 1; | ||
| 242 | } | ||
| 243 | if(iscmd(s, "New")){ | ||
| 244 | wikinew(skip(s, "New")); | ||
| 245 | return 1; | ||
| 246 | } | ||
| 247 | if(iscmd(s, "History")) | ||
| 248 | return wikiload(w, "history.txt"); | ||
| 249 | if(iscmd(s, "Diff")) | ||
| 250 | return wikidiff(w); | ||
| 251 | if(iscmd(s, "Get")){ | ||
| 252 | if(winisdirty(w->win) && !w->win->warned){ | ||
| 253 | w->win->warned = 1; | ||
| 254 | fprint(2, "%s/%s modified\n", dir, w->arg); | ||
| 255 | }else{ | ||
| 256 | w->win->warned = 0; | ||
| 257 | wikiget(w); | ||
| 258 | } | ||
| 259 | return 1; | ||
| 260 | } | ||
| 261 | if(iscmd(s, "Put")){ | ||
| 262 | if((p=strchr(w->arg, '/')) && p[1]!='\0') | ||
| 263 | fprint(2, "%s/%s is read-only\n", dir, w->arg); | ||
| 264 | else | ||
| 265 | wikiput(w); | ||
| 266 | return 1; | ||
| 267 | } | ||
| 268 | return 0; | ||
| 269 | } | ||
| 270 | |||
| 271 | /* need to expand selection more than default word */ | ||
| 272 | static long | ||
| 273 | eval(Window *w, char *s, ...) | ||
| 274 | { | ||
| 275 | char buf[64]; | ||
| 276 | va_list arg; | ||
| 277 | |||
| 278 | va_start(arg, s); | ||
| 279 | vsnprint(buf, sizeof buf, s, arg); | ||
| 280 | va_end(arg); | ||
| 281 | |||
| 282 | if(winsetaddr(w, buf, 1)==0) | ||
| 283 | return -1; | ||
| 284 | |||
| 285 | if(pread(w->addr, buf, 24, 0) != 24) | ||
| 286 | return -1; | ||
| 287 | return strtol(buf, 0, 10); | ||
| 288 | } | ||
| 289 | |||
| 290 | static int | ||
| 291 | getdot(Window *w, long *q0, long *q1) | ||
| 292 | { | ||
| 293 | char buf[24]; | ||
| 294 | |||
| 295 | ctlprint(w->ctl, "addr=dot\n"); | ||
| 296 | if(pread(w->addr, buf, 24, 0) != 24) | ||
| 297 | return -1; | ||
| 298 | *q0 = atoi(buf); | ||
| 299 | *q1 = atoi(buf+12); | ||
| 300 | return 0; | ||
| 301 | } | ||
| 302 | |||
| 303 | static Event* | ||
| 304 | expand(Window *w, Event *e, Event *eacme) | ||
| 305 | { | ||
| 306 | long q0, q1, x; | ||
| 307 | |||
| 308 | if(getdot(w, &q0, &q1)==0 && q0 <= e->q0 && e->q0 <= q1){ | ||
| 309 | e->q0 = q0; | ||
| 310 | e->q1 = q1; | ||
| 311 | return e; | ||
| 312 | } | ||
| 313 | |||
| 314 | q0 = eval(w, "#%lud-/\\[/", e->q0); | ||
| 315 | if(q0 < 0) | ||
| 316 | return eacme; | ||
| 317 | if(eval(w, "#%lud+/\\]/", q0) < e->q0) /* [ closes before us */ | ||
| 318 | return eacme; | ||
| 319 | q1 = eval(w, "#%lud+/\\]/", e->q1); | ||
| 320 | if(q1 < 0) | ||
| 321 | return eacme; | ||
| 322 | if((x=eval(w, "#%lud-/\\[/", q1))==-1 || x > e->q1) /* ] opens after us */ | ||
| 323 | return eacme; | ||
| 324 | e->q0 = q0+1; | ||
| 325 | e->q1 = q1; | ||
| 326 | return e; | ||
| 327 | } | ||
| 328 | |||
| 329 | void | ||
| 330 | acmeevent(Wiki *wiki, Event *e) | ||
| 331 | { | ||
| 332 | Event *ea, *e2, *eq; | ||
| 333 | Window *w; | ||
| 334 | char *s, *t, *buf; | ||
| 335 | int na; | ||
| 336 | |||
| 337 | w = wiki->win; | ||
| 338 | switch(e->c1){ /* origin of action */ | ||
| 339 | default: | ||
| 340 | Unknown: | ||
| 341 | fprint(2, "unknown message %c%c\n", e->c1, e->c2); | ||
| 342 | break; | ||
| 343 | |||
| 344 | case 'F': /* generated by our actions; ignore */ | ||
| 345 | break; | ||
| 346 | |||
| 347 | case 'E': /* write to body or tag; can't affect us */ | ||
| 348 | break; | ||
| 349 | |||
| 350 | case 'K': /* type away; we don't care */ | ||
| 351 | if(e->c2 == 'I' || e->c2 == 'D') | ||
| 352 | w->warned = 0; | ||
| 353 | break; | ||
| 354 | |||
| 355 | case 'M': /* mouse event */ | ||
| 356 | switch(e->c2){ /* type of action */ | ||
| 357 | case 'x': /* mouse: button 2 in tag */ | ||
| 358 | case 'X': /* mouse: button 2 in body */ | ||
| 359 | ea = nil; | ||
| 360 | //e2 = nil; | ||
| 361 | s = e->b; | ||
| 362 | if(e->flag & 2){ /* null string with non-null expansion */ | ||
| 363 | e2 = recvp(w->cevent); | ||
| 364 | if(e->nb==0) | ||
| 365 | s = e2->b; | ||
| 366 | } | ||
| 367 | if(e->flag & 8){ /* chorded argument */ | ||
| 368 | ea = recvp(w->cevent); /* argument */ | ||
| 369 | na = ea->nb; | ||
| 370 | recvp(w->cevent); /* ignore origin */ | ||
| 371 | }else | ||
| 372 | na = 0; | ||
| 373 | |||
| 374 | /* append chorded arguments */ | ||
| 375 | if(na){ | ||
| 376 | t = emalloc(strlen(s)+1+na+1); | ||
| 377 | sprint(t, "%s %s", s, ea->b); | ||
| 378 | s = t; | ||
| 379 | } | ||
| 380 | /* if it's a known command, do it */ | ||
| 381 | /* if it's a long message, it can't be for us anyway */ | ||
| 382 | // DPRINT(2, "exec: %s\n", s); | ||
| 383 | if(!wikicmd(wiki, s)) /* send it back */ | ||
| 384 | winwriteevent(w, e); | ||
| 385 | if(na) | ||
| 386 | free(s); | ||
| 387 | break; | ||
| 388 | |||
| 389 | case 'l': /* mouse: button 3 in tag */ | ||
| 390 | case 'L': /* mouse: button 3 in body */ | ||
| 391 | //buf = nil; | ||
| 392 | eq = e; | ||
| 393 | if(e->flag & 2){ /* we do our own expansion for loads */ | ||
| 394 | e2 = recvp(w->cevent); | ||
| 395 | eq = expand(w, eq, e2); | ||
| 396 | } | ||
| 397 | s = eq->b; | ||
| 398 | if(eq->q1>eq->q0 && eq->nb==0){ | ||
| 399 | buf = emalloc((eq->q1-eq->q0)*UTFmax+1); | ||
| 400 | winread(w, eq->q0, eq->q1, buf); | ||
| 401 | s = buf; | ||
| 402 | } | ||
| 403 | if(!wikiload(wiki, s)) | ||
| 404 | winwriteevent(w, e); | ||
| 405 | break; | ||
| 406 | |||
| 407 | case 'i': /* mouse: text inserted in tag */ | ||
| 408 | case 'd': /* mouse: text deleted from tag */ | ||
| 409 | break; | ||
| 410 | |||
| 411 | case 'I': /* mouse: text inserted in body */ | ||
| 412 | case 'D': /* mouse: text deleted from body */ | ||
| 413 | w->warned = 0; | ||
| 414 | break; | ||
| 415 | |||
| 416 | default: | ||
| 417 | goto Unknown; | ||
| 418 | } | ||
| 419 | } | ||
| 420 | } | ||
| 421 | |||
| 422 | void | ||
| 423 | wikithread(void *v) | ||
| 424 | { | ||
| 425 | char tmp[40]; | ||
| 426 | Event *e; | ||
| 427 | Wiki *w; | ||
| 428 | |||
| 429 | w = v; | ||
| 430 | |||
| 431 | if(w->isnew){ | ||
| 432 | sprint(tmp, "+new+%d", w->isnew); | ||
| 433 | wikiname(w->win, tmp); | ||
| 434 | if(w->arg){ | ||
| 435 | winopenbody(w->win, OWRITE); | ||
| 436 | Bprint(w->win->body, "%s\n\n", w->arg); | ||
| 437 | } | ||
| 438 | winclean(w->win); | ||
| 439 | }else if(!w->special){ | ||
| 440 | wikiget(w); | ||
| 441 | wikiname(w->win, w->arg); | ||
| 442 | if(w->addr) | ||
| 443 | winselect(w->win, w->addr, 1); | ||
| 444 | } | ||
| 445 | fprint(w->win->ctl, "menu\n"); | ||
| 446 | wintagwrite(w->win, "Get History Diff New", 4+8+4+4); | ||
| 447 | winclean(w->win); | ||
| 448 | |||
| 449 | while(!w->dead && (e = recvp(w->win->cevent))) | ||
| 450 | acmeevent(w, e); | ||
| 451 | |||
| 452 | windormant(w->win); | ||
| 453 | unlink(w); | ||
| 454 | free(w->win); | ||
| 455 | free(w->arg); | ||
| 456 | free(w); | ||
| 457 | threadexits(nil); | ||
| 458 | } | ||
| 459 | |||
| 460 | int | ||
| 461 | wikiopen(char *arg, char *addr) | ||
| 462 | { | ||
| 463 | Dir *d; | ||
| 464 | char *p; | ||
| 465 | Wiki *w; | ||
| 466 | |||
| 467 | /* | ||
| 468 | if(arg==nil){ | ||
| 469 | if(write(mapfd, title, strlen(title)) < 0 | ||
| 470 | || seek(mapfd, 0, 0) < 0 || (n=read(mapfd, tmp, sizeof(tmp)-2)) < 0){ | ||
| 471 | fprint(2, "Wiki: no page '%s' found: %r\n", title); | ||
| 472 | return -1; | ||
| 473 | } | ||
| 474 | if(tmp[n-1] == '\n') | ||
| 475 | tmp[--n] = '\0'; | ||
| 476 | tmp[n++] = '/'; | ||
| 477 | tmp[n] = '\0'; | ||
| 478 | arg = tmp; | ||
| 479 | } | ||
| 480 | */ | ||
| 481 | |||
| 482 | /* replace embedded '\n' in links by ' ' */ | ||
| 483 | for(p=arg; *p; p++) | ||
| 484 | if(*p=='\n') | ||
| 485 | *p = ' '; | ||
| 486 | |||
| 487 | if(strncmp(arg, dir, strlen(dir))==0 && arg[strlen(dir)]=='/' && arg[strlen(dir)+1]) | ||
| 488 | arg += strlen(dir)+1; | ||
| 489 | else if(arg[0] == '/') | ||
| 490 | return -1; | ||
| 491 | |||
| 492 | if((d = dirstat(arg)) == nil) | ||
| 493 | return -1; | ||
| 494 | |||
| 495 | if((d->mode&DMDIR) && arg[strlen(arg)-1] != '/'){ | ||
| 496 | p = emalloc(strlen(arg)+2); | ||
| 497 | strcpy(p, arg); | ||
| 498 | strcat(p, "/"); | ||
| 499 | arg = p; | ||
| 500 | }else if(!(d->mode&DMDIR) && arg[strlen(arg)-1]=='/'){ | ||
| 501 | arg = estrdup(arg); | ||
| 502 | arg[strlen(arg)-1] = '\0'; | ||
| 503 | }else | ||
| 504 | arg = estrdup(arg); | ||
| 505 | free(d); | ||
| 506 | |||
| 507 | /* rewrite /current into / */ | ||
| 508 | if(strlen(arg) > 8 && strcmp(arg+strlen(arg)-8, "/current")==0) | ||
| 509 | arg[strlen(arg)-8+1] = '\0'; | ||
| 510 | |||
| 511 | /* look for window already open */ | ||
| 512 | for(w=wlist; w; w=w->next){ | ||
| 513 | if(strcmp(w->arg, arg)==0){ | ||
| 514 | ctlprint(w->win->ctl, "show\n"); | ||
| 515 | return 0; | ||
| 516 | } | ||
| 517 | } | ||
| 518 | |||
| 519 | w = emalloc(sizeof *w); | ||
| 520 | w->arg = arg; | ||
| 521 | w->addr = addr; | ||
| 522 | w->win = newwindow(); | ||
| 523 | link(w); | ||
| 524 | |||
| 525 | proccreate(wineventproc, w->win, STACK); | ||
| 526 | threadcreate(wikithread, w, STACK); | ||
| 527 | return 0; | ||
| 528 | } | ||
| 529 | |||
| 530 | void | ||
| 531 | wikinew(char *arg) | ||
| 532 | { | ||
| 533 | static int n; | ||
| 534 | Wiki *w; | ||
| 535 | |||
| 536 | w = emalloc(sizeof *w); | ||
| 537 | if(arg) | ||
| 538 | arg = estrdup(arg); | ||
| 539 | w->arg = arg; | ||
| 540 | w->win = newwindow(); | ||
| 541 | w->isnew = ++n; | ||
| 542 | proccreate(wineventproc, w->win, STACK); | ||
| 543 | threadcreate(wikithread, w, STACK); | ||
| 544 | } | ||
| 545 | |||
| 546 | typedef struct Diffarg Diffarg; | ||
| 547 | struct Diffarg { | ||
| 548 | Wiki *w; | ||
| 549 | char *dir; | ||
| 550 | }; | ||
| 551 | |||
| 552 | void | ||
| 553 | execdiff(void *v) | ||
| 554 | { | ||
| 555 | char buf[64]; | ||
| 556 | Diffarg *a; | ||
| 557 | |||
| 558 | a = v; | ||
| 559 | |||
| 560 | rfork(RFFDG); | ||
| 561 | close(0); | ||
| 562 | open("/dev/null", OREAD); | ||
| 563 | sprint(buf, "/mnt/wsys/%d/body", a->w->win->id); | ||
| 564 | close(1); | ||
| 565 | open(buf, OWRITE); | ||
| 566 | close(2); | ||
| 567 | open(buf, OWRITE); | ||
| 568 | sprint(buf, "/mnt/wsys/%d", a->w->win->id); | ||
| 569 | bind(buf, "/dev", MBEFORE); | ||
| 570 | |||
| 571 | procexecl(nil, "/acme/wiki/wiki.diff", "wiki.diff", a->dir, nil); | ||
| 572 | } | ||
| 573 | |||
| 574 | int | ||
| 575 | wikidiff(Wiki *w) | ||
| 576 | { | ||
| 577 | Diffarg *d; | ||
| 578 | char *p, *q, *r; | ||
| 579 | Wiki *nw; | ||
| 580 | |||
| 581 | p = emalloc(strlen(w->arg)+10); | ||
| 582 | strcpy(p, w->arg); | ||
| 583 | if(q = strchr(p, '/')) | ||
| 584 | *q = '\0'; | ||
| 585 | r = estrdup(p); | ||
| 586 | strcat(p, "/+Diff"); | ||
| 587 | |||
| 588 | nw = emalloc(sizeof *w); | ||
| 589 | nw->arg = p; | ||
| 590 | nw->win = newwindow(); | ||
| 591 | nw->special = 1; | ||
| 592 | |||
| 593 | d = emalloc(sizeof(*d)); | ||
| 594 | d->w = nw; | ||
| 595 | d->dir = r; | ||
| 596 | wikiname(nw->win, p); | ||
| 597 | proccreate(wineventproc, nw->win, STACK); | ||
| 598 | proccreate(execdiff, d, STACK); | ||
| 599 | threadcreate(wikithread, nw, STACK); | ||
| 600 | return 1; | ||
| 601 | } | ||
| 602 | |||
Binary file not shown.
Binary file not shown.
| @@ -0,0 +1,341 @@ | |||
| 1 | #include "awiki.h" | ||
| 2 | |||
| 3 | Window* | ||
| 4 | newwindow(void) | ||
| 5 | { | ||
| 6 | char buf[12]; | ||
| 7 | Window *w; | ||
| 8 | |||
| 9 | w = emalloc(sizeof(Window)); | ||
| 10 | w->ctl = open("/mnt/wsys/new/ctl", ORDWR|OCEXEC); | ||
| 11 | if(w->ctl<0 || read(w->ctl, buf, 12)!=12) | ||
| 12 | error("can't open window ctl file: %r"); | ||
| 13 | ctlprint(w->ctl, "noscroll\n"); | ||
| 14 | w->id = atoi(buf); | ||
| 15 | w->event = winopenfile(w, "event"); | ||
| 16 | w->addr = -1; /* will be opened when needed */ | ||
| 17 | w->body = nil; | ||
| 18 | w->data = -1; | ||
| 19 | w->cevent = chancreate(sizeof(Event*), 0); | ||
| 20 | if(w->cevent == nil) | ||
| 21 | error("cevent is nil: %r"); | ||
| 22 | return w; | ||
| 23 | } | ||
| 24 | |||
| 25 | void | ||
| 26 | winsetdump(Window *w, char *dir, char *cmd) | ||
| 27 | { | ||
| 28 | if(dir != nil) | ||
| 29 | ctlprint(w->ctl, "dumpdir %s\n", dir); | ||
| 30 | if(cmd != nil) | ||
| 31 | ctlprint(w->ctl, "dump %s\n", cmd); | ||
| 32 | } | ||
| 33 | |||
| 34 | void | ||
| 35 | wineventproc(void *v) | ||
| 36 | { | ||
| 37 | Window *w; | ||
| 38 | int i; | ||
| 39 | |||
| 40 | threadsetname("wineventproc"); | ||
| 41 | w = v; | ||
| 42 | for(i=0; ; i++){ | ||
| 43 | if(i >= NEVENT) | ||
| 44 | i = 0; | ||
| 45 | wingetevent(w, &w->e[i]); | ||
| 46 | sendp(w->cevent, &w->e[i]); | ||
| 47 | } | ||
| 48 | } | ||
| 49 | |||
| 50 | int | ||
| 51 | winopenfile(Window *w, char *f) | ||
| 52 | { | ||
| 53 | char buf[64]; | ||
| 54 | int fd; | ||
| 55 | |||
| 56 | sprint(buf, "/mnt/wsys/%d/%s", w->id, f); | ||
| 57 | fd = open(buf, ORDWR|OCEXEC); | ||
| 58 | if(fd < 0) | ||
| 59 | error("can't open window file %s: %r", f); | ||
| 60 | return fd; | ||
| 61 | } | ||
| 62 | |||
| 63 | void | ||
| 64 | wintagwrite(Window *w, char *s, int n) | ||
| 65 | { | ||
| 66 | int fd; | ||
| 67 | |||
| 68 | fd = winopenfile(w, "tag"); | ||
| 69 | if(write(fd, s, n) != n) | ||
| 70 | error("tag write: %r"); | ||
| 71 | close(fd); | ||
| 72 | } | ||
| 73 | |||
| 74 | void | ||
| 75 | winname(Window *w, char *s) | ||
| 76 | { | ||
| 77 | ctlprint(w->ctl, "name %s\n", s); | ||
| 78 | } | ||
| 79 | |||
| 80 | void | ||
| 81 | winopenbody(Window *w, int mode) | ||
| 82 | { | ||
| 83 | char buf[256]; | ||
| 84 | |||
| 85 | sprint(buf, "/mnt/wsys/%d/body", w->id); | ||
| 86 | w->body = Bopen(buf, mode|OCEXEC); | ||
| 87 | if(w->body == nil) | ||
| 88 | error("can't open window body file: %r"); | ||
| 89 | } | ||
| 90 | |||
| 91 | void | ||
| 92 | winclosebody(Window *w) | ||
| 93 | { | ||
| 94 | if(w->body != nil){ | ||
| 95 | Bterm(w->body); | ||
| 96 | w->body = nil; | ||
| 97 | } | ||
| 98 | } | ||
| 99 | |||
| 100 | void | ||
| 101 | winwritebody(Window *w, char *s, int n) | ||
| 102 | { | ||
| 103 | if(w->body == nil) | ||
| 104 | winopenbody(w, OWRITE); | ||
| 105 | if(Bwrite(w->body, s, n) != n) | ||
| 106 | error("write error to window: %r"); | ||
| 107 | } | ||
| 108 | |||
| 109 | int | ||
| 110 | wingetec(Window *w) | ||
| 111 | { | ||
| 112 | if(w->nbuf == 0){ | ||
| 113 | w->nbuf = read(w->event, w->buf, sizeof w->buf); | ||
| 114 | if(w->nbuf <= 0){ | ||
| 115 | /* probably because window has exited, and only called by wineventproc, so just shut down */ | ||
| 116 | threadexits(nil); | ||
| 117 | } | ||
| 118 | w->bufp = w->buf; | ||
| 119 | } | ||
| 120 | w->nbuf--; | ||
| 121 | return *w->bufp++; | ||
| 122 | } | ||
| 123 | |||
| 124 | int | ||
| 125 | wingeten(Window *w) | ||
| 126 | { | ||
| 127 | int n, c; | ||
| 128 | |||
| 129 | n = 0; | ||
| 130 | while('0'<=(c=wingetec(w)) && c<='9') | ||
| 131 | n = n*10+(c-'0'); | ||
| 132 | if(c != ' ') | ||
| 133 | error("event number syntax"); | ||
| 134 | return n; | ||
| 135 | } | ||
| 136 | |||
| 137 | int | ||
| 138 | wingeter(Window *w, char *buf, int *nb) | ||
| 139 | { | ||
| 140 | Rune r; | ||
| 141 | int n; | ||
| 142 | |||
| 143 | r = wingetec(w); | ||
| 144 | buf[0] = r; | ||
| 145 | n = 1; | ||
| 146 | if(r >= Runeself) { | ||
| 147 | while(!fullrune(buf, n)) | ||
| 148 | buf[n++] = wingetec(w); | ||
| 149 | chartorune(&r, buf); | ||
| 150 | } | ||
| 151 | *nb = n; | ||
| 152 | return r; | ||
| 153 | } | ||
| 154 | |||
| 155 | void | ||
| 156 | wingetevent(Window *w, Event *e) | ||
| 157 | { | ||
| 158 | int i, nb; | ||
| 159 | |||
| 160 | e->c1 = wingetec(w); | ||
| 161 | e->c2 = wingetec(w); | ||
| 162 | e->q0 = wingeten(w); | ||
| 163 | e->q1 = wingeten(w); | ||
| 164 | e->flag = wingeten(w); | ||
| 165 | e->nr = wingeten(w); | ||
| 166 | if(e->nr > EVENTSIZE) | ||
| 167 | error("event string too long"); | ||
| 168 | e->nb = 0; | ||
| 169 | for(i=0; i<e->nr; i++){ | ||
| 170 | e->r[i] = wingeter(w, e->b+e->nb, &nb); | ||
| 171 | e->nb += nb; | ||
| 172 | } | ||
| 173 | e->r[e->nr] = 0; | ||
| 174 | e->b[e->nb] = 0; | ||
| 175 | if(wingetec(w) != '\n') | ||
| 176 | error("event syntax error"); | ||
| 177 | } | ||
| 178 | |||
| 179 | void | ||
| 180 | winwriteevent(Window *w, Event *e) | ||
| 181 | { | ||
| 182 | fprint(w->event, "%c%c%d %d\n", e->c1, e->c2, e->q0, e->q1); | ||
| 183 | } | ||
| 184 | |||
| 185 | static int | ||
| 186 | nrunes(char *s, int nb) | ||
| 187 | { | ||
| 188 | int i, n; | ||
| 189 | Rune r; | ||
| 190 | |||
| 191 | n = 0; | ||
| 192 | for(i=0; i<nb; n++) | ||
| 193 | i += chartorune(&r, s+i); | ||
| 194 | return n; | ||
| 195 | } | ||
| 196 | |||
| 197 | void | ||
| 198 | winread(Window *w, uint q0, uint q1, char *data) | ||
| 199 | { | ||
| 200 | int m, n, nr; | ||
| 201 | char buf[256]; | ||
| 202 | |||
| 203 | if(w->addr < 0) | ||
| 204 | w->addr = winopenfile(w, "addr"); | ||
| 205 | if(w->data < 0) | ||
| 206 | w->data = winopenfile(w, "data"); | ||
| 207 | m = q0; | ||
| 208 | while(m < q1){ | ||
| 209 | n = sprint(buf, "#%d", m); | ||
| 210 | if(write(w->addr, buf, n) != n) | ||
| 211 | error("error writing addr: %r"); | ||
| 212 | n = read(w->data, buf, sizeof buf); | ||
| 213 | if(n <= 0) | ||
| 214 | error("reading data: %r"); | ||
| 215 | nr = nrunes(buf, n); | ||
| 216 | while(m+nr >q1){ | ||
| 217 | do; while(n>0 && (buf[--n]&0xC0)==0x80); | ||
| 218 | --nr; | ||
| 219 | } | ||
| 220 | if(n == 0) | ||
| 221 | break; | ||
| 222 | memmove(data, buf, n); | ||
| 223 | data += n; | ||
| 224 | *data = 0; | ||
| 225 | m += nr; | ||
| 226 | } | ||
| 227 | } | ||
| 228 | |||
| 229 | void | ||
| 230 | windormant(Window *w) | ||
| 231 | { | ||
| 232 | if(w->addr >= 0){ | ||
| 233 | close(w->addr); | ||
| 234 | w->addr = -1; | ||
| 235 | } | ||
| 236 | if(w->body != nil){ | ||
| 237 | Bterm(w->body); | ||
| 238 | w->body = nil; | ||
| 239 | } | ||
| 240 | if(w->data >= 0){ | ||
| 241 | close(w->data); | ||
| 242 | w->data = -1; | ||
| 243 | } | ||
| 244 | } | ||
| 245 | |||
| 246 | |||
| 247 | int | ||
| 248 | windel(Window *w, int sure) | ||
| 249 | { | ||
| 250 | if(sure) | ||
| 251 | write(w->ctl, "delete\n", 7); | ||
| 252 | else if(write(w->ctl, "del\n", 4) != 4) | ||
| 253 | return 0; | ||
| 254 | /* event proc will die due to read error from event file */ | ||
| 255 | windormant(w); | ||
| 256 | close(w->ctl); | ||
| 257 | w->ctl = -1; | ||
| 258 | close(w->event); | ||
| 259 | w->event = -1; | ||
| 260 | return 1; | ||
| 261 | } | ||
| 262 | |||
| 263 | void | ||
| 264 | winclean(Window *w) | ||
| 265 | { | ||
| 266 | if(w->body) | ||
| 267 | Bflush(w->body); | ||
| 268 | ctlprint(w->ctl, "clean\n"); | ||
| 269 | } | ||
| 270 | |||
| 271 | int | ||
| 272 | winisdirty(Window *w) | ||
| 273 | { | ||
| 274 | char m; | ||
| 275 | |||
| 276 | if (seek(w->ctl, 4*(11+1) + 10, 0) < 0) | ||
| 277 | error("control file seek error: %r"); | ||
| 278 | |||
| 279 | if(read(w->ctl, &m, 1) != 1) | ||
| 280 | error("control file read error: %r"); | ||
| 281 | |||
| 282 | if (m == '0') | ||
| 283 | return 0; | ||
| 284 | else if (m == '1') | ||
| 285 | return 1; | ||
| 286 | else | ||
| 287 | error("can't parse ismodified field: %c", m); | ||
| 288 | return 1; // better safe than sorry | ||
| 289 | |||
| 290 | } | ||
| 291 | |||
| 292 | int | ||
| 293 | winsetaddr(Window *w, char *addr, int errok) | ||
| 294 | { | ||
| 295 | if(w->addr < 0) | ||
| 296 | w->addr = winopenfile(w, "addr"); | ||
| 297 | if(write(w->addr, addr, strlen(addr)) < 0){ | ||
| 298 | if(!errok) | ||
| 299 | error("error writing addr(%s): %r", addr); | ||
| 300 | return 0; | ||
| 301 | } | ||
| 302 | return 1; | ||
| 303 | } | ||
| 304 | |||
| 305 | int | ||
| 306 | winselect(Window *w, char *addr, int errok) | ||
| 307 | { | ||
| 308 | if(winsetaddr(w, addr, errok)){ | ||
| 309 | ctlprint(w->ctl, "dot=addr\n"); | ||
| 310 | return 1; | ||
| 311 | } | ||
| 312 | return 0; | ||
| 313 | } | ||
| 314 | |||
| 315 | char* | ||
| 316 | winreadbody(Window *w, int *np) /* can't use readfile because acme doesn't report the length */ | ||
| 317 | { | ||
| 318 | char *s; | ||
| 319 | int m, na, n; | ||
| 320 | |||
| 321 | if(w->body != nil) | ||
| 322 | winclosebody(w); | ||
| 323 | winopenbody(w, OREAD); | ||
| 324 | s = nil; | ||
| 325 | na = 0; | ||
| 326 | n = 0; | ||
| 327 | for(;;){ | ||
| 328 | if(na < n+512){ | ||
| 329 | na += 1024; | ||
| 330 | s = realloc(s, na+1); | ||
| 331 | } | ||
| 332 | m = Bread(w->body, s+n, na-n); | ||
| 333 | if(m <= 0) | ||
| 334 | break; | ||
| 335 | n += m; | ||
| 336 | } | ||
| 337 | s[n] = 0; | ||
| 338 | winclosebody(w); | ||
| 339 | *np = n; | ||
| 340 | return s; | ||
| 341 | } | ||
| @@ -0,0 +1,27 @@ | |||
| 1 | #!/bin/rc | ||
| 2 | |||
| 3 | rfork n | ||
| 4 | cd $1 | ||
| 5 | *=(`{ls -drp [0-9]*}) | ||
| 6 | |||
| 7 | while(! ~ $#* 0 1){ | ||
| 8 | diff -n $2/index.txt $1/index.txt | awk -F'[\/ :]' ' | ||
| 9 | $1 ~/^[0-9]+$/ { | ||
| 10 | getA = "cat "$5"/current | sed -n -e ''1d; /^A/s/^A//p; /^#/q''" | ||
| 11 | getA | getline A; close getA | ||
| 12 | $1 = t2d($1) | ||
| 13 | $5 = t2d($5) | ||
| 14 | print "\n" A ":\n" $1":"$3" "$4" "$5":"$7 | ||
| 15 | next | ||
| 16 | } | ||
| 17 | { print } | ||
| 18 | |||
| 19 | function t2d(t) { | ||
| 20 | c = "date "t; c|getline l; close c | ||
| 21 | split(l, a, "[ :]+") | ||
| 22 | return a[1]" "a[2]" "a[3]" "a[4]":"a[5]" "a[8]"("t")" | ||
| 23 | }' | ||
| 24 | shift | ||
| 25 | } | ||
| 26 | |||
| 27 | echo clean >/dev/ctl >[2]/dev/null | ||
Empty file deleted.
Empty file deleted.
| @@ -1,18766 +0,0 @@ | |||
| 1 | a | ||
| 2 | aback | ||
| 3 | abacus | ||
| 4 | abaft | ||
| 5 | abandon | ||
| 6 | abase | ||
| 7 | abash | ||
| 8 | abate | ||
| 9 | abattoir | ||
| 10 | abbe | ||
| 11 | abbess | ||
| 12 | abbey | ||
| 13 | abbot | ||
| 14 | abbreviate | ||
| 15 | abc | ||
| 16 | abdicate | ||
| 17 | abdomen | ||
| 18 | abdominal | ||
| 19 | abduct | ||
| 20 | abeam | ||
| 21 | abed | ||
| 22 | aberration | ||
| 23 | abet | ||
| 24 | abeyance | ||
| 25 | abhor | ||
| 26 | abide | ||
| 27 | ability | ||
| 28 | abject | ||
| 29 | abjure | ||
| 30 | ablative | ||
| 31 | ablaut | ||
| 32 | ablaze | ||
| 33 | able | ||
| 34 | ablution | ||
| 35 | abnegation | ||
| 36 | abnormal | ||
| 37 | abo | ||
| 38 | aboard | ||
| 39 | abode | ||
| 40 | abolish | ||
| 41 | abominable | ||
| 42 | abominate | ||
| 43 | aboriginal | ||
| 44 | abort | ||
| 45 | abortion | ||
| 46 | abortive | ||
| 47 | abound | ||
| 48 | about | ||
| 49 | above | ||
| 50 | abracadabra | ||
| 51 | abrade | ||
| 52 | abrasion | ||
| 53 | abrasive | ||
| 54 | abreast | ||
| 55 | abridge | ||
| 56 | abroad | ||
| 57 | abrogate | ||
| 58 | abrupt | ||
| 59 | abscess | ||
| 60 | abscond | ||
| 61 | absence | ||
| 62 | absent | ||
| 63 | absentee | ||
| 64 | absinth | ||
| 65 | absinthe | ||
| 66 | absolute | ||
| 67 | absolution | ||
| 68 | absolve | ||
| 69 | absorb | ||
| 70 | abstain | ||
| 71 | abstemious | ||
| 72 | abstention | ||
| 73 | abstinence | ||
| 74 | abstract | ||
| 75 | abstraction | ||
| 76 | abstruse | ||
| 77 | absurd | ||
| 78 | abundance | ||
| 79 | abundant | ||
| 80 | abuse | ||
| 81 | abusive | ||
| 82 | abut | ||
| 83 | abysm | ||
| 84 | abysmal | ||
| 85 | abyss | ||
| 86 | acacia | ||
| 87 | academic | ||
| 88 | academicals | ||
| 89 | academy | ||
| 90 | accede | ||
| 91 | accelerando | ||
| 92 | accelerate | ||
| 93 | accelerator | ||
| 94 | accent | ||
| 95 | accentuate | ||
| 96 | accept | ||
| 97 | access | ||
| 98 | accessary | ||
| 99 | accession | ||
| 100 | accessory | ||
| 101 | accidence | ||
| 102 | accident | ||
| 103 | accidental | ||
| 104 | acclaim | ||
| 105 | acclamation | ||
| 106 | acclimate | ||
| 107 | acclimatize | ||
| 108 | acclivity | ||
| 109 | accolade | ||
| 110 | accommodate | ||
| 111 | accommodation | ||
| 112 | accompaniment | ||
| 113 | accompany | ||
| 114 | accomplice | ||
| 115 | accomplish | ||
| 116 | accord | ||
| 117 | accordance | ||
| 118 | according | ||
| 119 | accordion | ||
| 120 | accost | ||
| 121 | accouchement | ||
| 122 | account | ||
| 123 | accountancy | ||
| 124 | accountant | ||
| 125 | accoutrements | ||
| 126 | accredit | ||
| 127 | accretion | ||
| 128 | accrue | ||
| 129 | accumulate | ||
| 130 | accumulation | ||
| 131 | accumulator | ||
| 132 | accurate | ||
| 133 | accursed | ||
| 134 | accusation | ||
| 135 | accusative | ||
| 136 | accuse | ||
| 137 | accustom | ||
| 138 | ace | ||
| 139 | acerbity | ||
| 140 | acetic | ||
| 141 | acetylene | ||
| 142 | ache | ||
| 143 | achieve | ||
| 144 | achilles | ||
| 145 | acid | ||
| 146 | acknowledge | ||
| 147 | acme | ||
| 148 | acne | ||
| 149 | acolyte | ||
| 150 | aconite | ||
| 151 | acorn | ||
| 152 | acoustic | ||
| 153 | acquaint | ||
| 154 | acquaintance | ||
| 155 | acquiesce | ||
| 156 | acquire | ||
| 157 | acquisition | ||
| 158 | acquisitive | ||
| 159 | acquit | ||
| 160 | acre | ||
| 161 | acrid | ||
| 162 | acrimony | ||
| 163 | acrobat | ||
| 164 | acronym | ||
| 165 | acropolis | ||
| 166 | across | ||
| 167 | acrostic | ||
| 168 | acrylic | ||
| 169 | act | ||
| 170 | acting | ||
| 171 | actinism | ||
| 172 | action | ||
| 173 | activate | ||
| 174 | active | ||
| 175 | activist | ||
| 176 | activity | ||
| 177 | actor | ||
| 178 | actress | ||
| 179 | actual | ||
| 180 | actuary | ||
| 181 | actuate | ||
| 182 | acuity | ||
| 183 | acumen | ||
| 184 | acupuncture | ||
| 185 | acute | ||
| 186 | ad | ||
| 187 | adage | ||
| 188 | adagio | ||
| 189 | adam | ||
| 190 | adamant | ||
| 191 | adapt | ||
| 192 | add | ||
| 193 | addendum | ||
| 194 | adder | ||
| 195 | addict | ||
| 196 | addition | ||
| 197 | additive | ||
| 198 | addle | ||
| 199 | address | ||
| 200 | adduce | ||
| 201 | adenoids | ||
| 202 | adept | ||
| 203 | adequate | ||
| 204 | adhere | ||
| 205 | adherent | ||
| 206 | adhesion | ||
| 207 | adhesive | ||
| 208 | adieu | ||
| 209 | adipose | ||
| 210 | adjacent | ||
| 211 | adjective | ||
| 212 | adjoin | ||
| 213 | adjourn | ||
| 214 | adjudge | ||
| 215 | adjudicate | ||
| 216 | adjunct | ||
| 217 | adjure | ||
| 218 | adjust | ||
| 219 | adjutant | ||
| 220 | admass | ||
| 221 | administer | ||
| 222 | administration | ||
| 223 | administrative | ||
| 224 | administrator | ||
| 225 | admirable | ||
| 226 | admiral | ||
| 227 | admiration | ||
| 228 | admire | ||
| 229 | admissible | ||
| 230 | admission | ||
| 231 | admit | ||
| 232 | admittance | ||
| 233 | admix | ||
| 234 | admixture | ||
| 235 | admonish | ||
| 236 | ado | ||
| 237 | adobe | ||
| 238 | adolescence | ||
| 239 | adopt | ||
| 240 | adore | ||
| 241 | adorn | ||
| 242 | adrenal | ||
| 243 | adrenalin | ||
| 244 | adrift | ||
| 245 | adroit | ||
| 246 | adulation | ||
| 247 | adult | ||
| 248 | adulterate | ||
| 249 | adultery | ||
| 250 | adumbrate | ||
| 251 | advance | ||
| 252 | advantage | ||
| 253 | advantageous | ||
| 254 | advent | ||
| 255 | adventitious | ||
| 256 | adventure | ||
| 257 | adverb | ||
| 258 | adversary | ||
| 259 | adverse | ||
| 260 | adversity | ||
| 261 | advert | ||
| 262 | advertise | ||
| 263 | advice | ||
| 264 | advisable | ||
| 265 | advise | ||
| 266 | advocate | ||
| 267 | advowson | ||
| 268 | adz | ||
| 269 | adze | ||
| 270 | aegis | ||
| 271 | aeon | ||
| 272 | aerate | ||
| 273 | aerial | ||
| 274 | aerie | ||
| 275 | aerobatics | ||
| 276 | aerodrome | ||
| 277 | aerodynamics | ||
| 278 | aeronaut | ||
| 279 | aeronautics | ||
| 280 | aeroplane | ||
| 281 | aerosol | ||
| 282 | aerospace | ||
| 283 | aertex | ||
| 284 | aery | ||
| 285 | aesthete | ||
| 286 | aesthetic | ||
| 287 | aether | ||
| 288 | aetiology | ||
| 289 | afar | ||
| 290 | affable | ||
| 291 | affair | ||
| 292 | affect | ||
| 293 | affectation | ||
| 294 | affection | ||
| 295 | affectionate | ||
| 296 | affiance | ||
| 297 | affidavit | ||
| 298 | affiliate | ||
| 299 | affiliation | ||
| 300 | affinity | ||
| 301 | affirm | ||
| 302 | affix | ||
| 303 | afflatus | ||
| 304 | afflict | ||
| 305 | affliction | ||
| 306 | affluence | ||
| 307 | affluent | ||
| 308 | afford | ||
| 309 | afforest | ||
| 310 | affranchise | ||
| 311 | affray | ||
| 312 | affront | ||
| 313 | afield | ||
| 314 | afire | ||
| 315 | aflame | ||
| 316 | afloat | ||
| 317 | afoot | ||
| 318 | afore | ||
| 319 | afoul | ||
| 320 | afraid | ||
| 321 | afresh | ||
| 322 | african | ||
| 323 | afrikaans | ||
| 324 | aft | ||
| 325 | after | ||
| 326 | afternoon | ||
| 327 | afters | ||
| 328 | afterwards | ||
| 329 | again | ||
| 330 | against | ||
| 331 | agape | ||
| 332 | agate | ||
| 333 | agave | ||
| 334 | age | ||
| 335 | agency | ||
| 336 | agenda | ||
| 337 | agent | ||
| 338 | agglomerate | ||
| 339 | agglutinate | ||
| 340 | aggrandize | ||
| 341 | aggravate | ||
| 342 | aggregate | ||
| 343 | aggression | ||
| 344 | aggressive | ||
| 345 | aggrieve | ||
| 346 | aggro | ||
| 347 | aghast | ||
| 348 | agile | ||
| 349 | agin | ||
| 350 | agitate | ||
| 351 | aglow | ||
| 352 | agnail | ||
| 353 | agnostic | ||
| 354 | ago | ||
| 355 | agog | ||
| 356 | agony | ||
| 357 | agora | ||
| 358 | agrarian | ||
| 359 | agree | ||
| 360 | agreeable | ||
| 361 | agreement | ||
| 362 | agriculture | ||
| 363 | aground | ||
| 364 | ague | ||
| 365 | ah | ||
| 366 | aha | ||
| 367 | ahead | ||
| 368 | ahem | ||
| 369 | ahoy | ||
| 370 | aid | ||
| 371 | aigret | ||
| 372 | aigrette | ||
| 373 | ail | ||
| 374 | aileron | ||
| 375 | ailment | ||
| 376 | aim | ||
| 377 | air | ||
| 378 | airedale | ||
| 379 | airless | ||
| 380 | airy | ||
| 381 | aisle | ||
| 382 | aitch | ||
| 383 | ajar | ||
| 384 | akimbo | ||
| 385 | akin | ||
| 386 | alabaster | ||
| 387 | alack | ||
| 388 | alacrity | ||
| 389 | alarm | ||
| 390 | alas | ||
| 391 | alb | ||
| 392 | albatross | ||
| 393 | albeit | ||
| 394 | albino | ||
| 395 | album | ||
| 396 | albumen | ||
| 397 | alchemist | ||
| 398 | alchemy | ||
| 399 | alcohol | ||
| 400 | alcove | ||
| 401 | alder | ||
| 402 | alderman | ||
| 403 | ale | ||
| 404 | alee | ||
| 405 | alert | ||
| 406 | alexandrine | ||
| 407 | alexia | ||
| 408 | alfalfa | ||
| 409 | alfresco | ||
| 410 | alga | ||
| 411 | algebra | ||
| 412 | alias | ||
| 413 | alibi | ||
| 414 | alien | ||
| 415 | alienate | ||
| 416 | alienist | ||
| 417 | alight | ||
| 418 | align | ||
| 419 | alike | ||
| 420 | alimentary | ||
| 421 | alimony | ||
| 422 | alive | ||
| 423 | alkali | ||
| 424 | all | ||
| 425 | allah | ||
| 426 | allay | ||
| 427 | allege | ||
| 428 | allegiance | ||
| 429 | allegory | ||
| 430 | allegretto | ||
| 431 | allegro | ||
| 432 | alleluia | ||
| 433 | allergy | ||
| 434 | alleviate | ||
| 435 | alley | ||
| 436 | alliance | ||
| 437 | allied | ||
| 438 | alligator | ||
| 439 | alliteration | ||
| 440 | allocate | ||
| 441 | allot | ||
| 442 | allow | ||
| 443 | allowance | ||
| 444 | alloy | ||
| 445 | allspice | ||
| 446 | allude | ||
| 447 | allure | ||
| 448 | allusion | ||
| 449 | alluvial | ||
| 450 | ally | ||
| 451 | almanac | ||
| 452 | almighty | ||
| 453 | almond | ||
| 454 | almoner | ||
| 455 | almost | ||
| 456 | alms | ||
| 457 | aloe | ||
| 458 | aloft | ||
| 459 | alone | ||
| 460 | along | ||
| 461 | aloof | ||
| 462 | aloud | ||
| 463 | alp | ||
| 464 | alpaca | ||
| 465 | alpenstock | ||
| 466 | alpha | ||
| 467 | alphabet | ||
| 468 | alpine | ||
| 469 | already | ||
| 470 | alright | ||
| 471 | alsatian | ||
| 472 | also | ||
| 473 | altar | ||
| 474 | alter | ||
| 475 | altercation | ||
| 476 | alternate | ||
| 477 | alternative | ||
| 478 | altho | ||
| 479 | although | ||
| 480 | altimeter | ||
| 481 | altitude | ||
| 482 | alto | ||
| 483 | altogether | ||
| 484 | altruism | ||
| 485 | alum | ||
| 486 | aluminium | ||
| 487 | alumna | ||
| 488 | alumnus | ||
| 489 | alveolar | ||
| 490 | always | ||
| 491 | am | ||
| 492 | amah | ||
| 493 | amain | ||
| 494 | amalgam | ||
| 495 | amalgamate | ||
| 496 | amanuensis | ||
| 497 | amaryllis | ||
| 498 | amass | ||
| 499 | amateur | ||
| 500 | amatory | ||
| 501 | amaze | ||
| 502 | amazon | ||
| 503 | ambassador | ||
| 504 | amber | ||
| 505 | ambergris | ||
| 506 | ambidextrous | ||
| 507 | ambience | ||
| 508 | ambient | ||
| 509 | ambiguity | ||
| 510 | ambiguous | ||
| 511 | ambit | ||
| 512 | ambition | ||
| 513 | ambitious | ||
| 514 | ambivalent | ||
| 515 | amble | ||
| 516 | ambrosia | ||
| 517 | ambulance | ||
| 518 | ambuscade | ||
| 519 | ambush | ||
| 520 | ameba | ||
| 521 | ameer | ||
| 522 | ameliorate | ||
| 523 | amen | ||
| 524 | amenable | ||
| 525 | amend | ||
| 526 | amends | ||
| 527 | amenity | ||
| 528 | america | ||
| 529 | american | ||
| 530 | amethyst | ||
| 531 | amiable | ||
| 532 | amicable | ||
| 533 | amid | ||
| 534 | amidships | ||
| 535 | amir | ||
| 536 | amiss | ||
| 537 | amity | ||
| 538 | ammeter | ||
| 539 | ammonia | ||
| 540 | ammonite | ||
| 541 | ammunition | ||
| 542 | amnesia | ||
| 543 | amnesty | ||
| 544 | amoeba | ||
| 545 | amok | ||
| 546 | among | ||
| 547 | amoral | ||
| 548 | amorous | ||
| 549 | amorphous | ||
| 550 | amortize | ||
| 551 | amount | ||
| 552 | amour | ||
| 553 | amp | ||
| 554 | ampere | ||
| 555 | amphetamine | ||
| 556 | amphibian | ||
| 557 | amphibious | ||
| 558 | amphitheatre | ||
| 559 | amphora | ||
| 560 | ample | ||
| 561 | amplify | ||
| 562 | amplitude | ||
| 563 | ampoule | ||
| 564 | amputate | ||
| 565 | amuck | ||
| 566 | amulet | ||
| 567 | amuse | ||
| 568 | an | ||
| 569 | anachronism | ||
| 570 | anaconda | ||
| 571 | anaemia | ||
| 572 | anaesthesia | ||
| 573 | anagram | ||
| 574 | anal | ||
| 575 | analects | ||
| 576 | analgesia | ||
| 577 | analogous | ||
| 578 | analogue | ||
| 579 | analogy | ||
| 580 | analyse | ||
| 581 | analysis | ||
| 582 | analyst | ||
| 583 | analyze | ||
| 584 | anapaest | ||
| 585 | anarchy | ||
| 586 | anathema | ||
| 587 | anatomy | ||
| 588 | ancestor | ||
| 589 | anchor | ||
| 590 | anchorite | ||
| 591 | anchovy | ||
| 592 | ancient | ||
| 593 | ancillary | ||
| 594 | and | ||
| 595 | andante | ||
| 596 | andiron | ||
| 597 | anecdote | ||
| 598 | anemia | ||
| 599 | anemic | ||
| 600 | anemometer | ||
| 601 | anemone | ||
| 602 | anent | ||
| 603 | aneroid | ||
| 604 | anew | ||
| 605 | angel | ||
| 606 | angelica | ||
| 607 | angelus | ||
| 608 | anger | ||
| 609 | angle | ||
| 610 | anglican | ||
| 611 | anglicize | ||
| 612 | anglomania | ||
| 613 | anglophile | ||
| 614 | anglophobe | ||
| 615 | anglophobia | ||
| 616 | angora | ||
| 617 | angostura | ||
| 618 | angry | ||
| 619 | angst | ||
| 620 | anguish | ||
| 621 | angular | ||
| 622 | aniline | ||
| 623 | animadvert | ||
| 624 | animal | ||
| 625 | animate | ||
| 626 | animism | ||
| 627 | animosity | ||
| 628 | animus | ||
| 629 | anise | ||
| 630 | ankle | ||
| 631 | anna | ||
| 632 | annals | ||
| 633 | anneal | ||
| 634 | annex | ||
| 635 | annihilate | ||
| 636 | anniversary | ||
| 637 | annotate | ||
| 638 | announce | ||
| 639 | annoy | ||
| 640 | annual | ||
| 641 | annuity | ||
| 642 | annul | ||
| 643 | annular | ||
| 644 | annunciate | ||
| 645 | annunciation | ||
| 646 | anode | ||
| 647 | anodyne | ||
| 648 | anoint | ||
| 649 | anomalous | ||
| 650 | anon | ||
| 651 | anonymity | ||
| 652 | anonymous | ||
| 653 | anopheles | ||
| 654 | anorak | ||
| 655 | another | ||
| 656 | answer | ||
| 657 | ant | ||
| 658 | antagonism | ||
| 659 | antagonist | ||
| 660 | antagonistic | ||
| 661 | antagonize | ||
| 662 | antarctic | ||
| 663 | ante | ||
| 664 | antecedent | ||
| 665 | antechamber | ||
| 666 | antedate | ||
| 667 | antediluvian | ||
| 668 | antelope | ||
| 669 | antenatal | ||
| 670 | antenna | ||
| 671 | antenuptial | ||
| 672 | antepenultimate | ||
| 673 | anterior | ||
| 674 | anteroom | ||
| 675 | anthem | ||
| 676 | anther | ||
| 677 | anthology | ||
| 678 | anthracite | ||
| 679 | anthrax | ||
| 680 | anthropoid | ||
| 681 | anthropology | ||
| 682 | antibiotic | ||
| 683 | antibody | ||
| 684 | antic | ||
| 685 | anticipate | ||
| 686 | anticipation | ||
| 687 | anticyclone | ||
| 688 | antidote | ||
| 689 | antifreeze | ||
| 690 | antiknock | ||
| 691 | antilogarithm | ||
| 692 | antimacassar | ||
| 693 | antimony | ||
| 694 | antipathy | ||
| 695 | antipodes | ||
| 696 | antiquarian | ||
| 697 | antiquary | ||
| 698 | antiquated | ||
| 699 | antique | ||
| 700 | antiquity | ||
| 701 | antirrhinum | ||
| 702 | antiseptic | ||
| 703 | antisocial | ||
| 704 | antitank | ||
| 705 | antithesis | ||
| 706 | antitoxin | ||
| 707 | antitrade | ||
| 708 | antler | ||
| 709 | antonym | ||
| 710 | anus | ||
| 711 | anvil | ||
| 712 | anxiety | ||
| 713 | anxious | ||
| 714 | any | ||
| 715 | anybody | ||
| 716 | anyhow | ||
| 717 | anyone | ||
| 718 | anyplace | ||
| 719 | anything | ||
| 720 | anyway | ||
| 721 | anywhere | ||
| 722 | aorta | ||
| 723 | apace | ||
| 724 | apache | ||
| 725 | apanage | ||
| 726 | apart | ||
| 727 | apartheid | ||
| 728 | apartment | ||
| 729 | apathy | ||
| 730 | ape | ||
| 731 | aperient | ||
| 732 | aperitif | ||
| 733 | aperture | ||
| 734 | apex | ||
| 735 | aphasia | ||
| 736 | aphid | ||
| 737 | aphis | ||
| 738 | aphorism | ||
| 739 | aphrodisiac | ||
| 740 | apiary | ||
| 741 | apiece | ||
| 742 | apish | ||
| 743 | aplomb | ||
| 744 | apocalypse | ||
| 745 | apocrypha | ||
| 746 | apogee | ||
| 747 | apologetic | ||
| 748 | apologize | ||
| 749 | apology | ||
| 750 | apophthegm | ||
| 751 | apoplexy | ||
| 752 | apostasy | ||
| 753 | apostle | ||
| 754 | apostrophe | ||
| 755 | apothecary | ||
| 756 | apothegm | ||
| 757 | apotheosis | ||
| 758 | appal | ||
| 759 | appanage | ||
| 760 | apparatus | ||
| 761 | apparel | ||
| 762 | apparent | ||
| 763 | apparition | ||
| 764 | appeal | ||
| 765 | appear | ||
| 766 | appearance | ||
| 767 | appease | ||
| 768 | appellant | ||
| 769 | appellation | ||
| 770 | append | ||
| 771 | appendage | ||
| 772 | appendix | ||
| 773 | appertain | ||
| 774 | appetite | ||
| 775 | applaud | ||
| 776 | applause | ||
| 777 | apple | ||
| 778 | appliance | ||
| 779 | applicable | ||
| 780 | applicant | ||
| 781 | application | ||
| 782 | applied | ||
| 783 | applique | ||
| 784 | apply | ||
| 785 | appoint | ||
| 786 | appointment | ||
| 787 | apportion | ||
| 788 | apposite | ||
| 789 | apposition | ||
| 790 | appraise | ||
| 791 | appreciable | ||
| 792 | appreciate | ||
| 793 | appreciation | ||
| 794 | apprehend | ||
| 795 | apprehension | ||
| 796 | apprehensive | ||
| 797 | apprentice | ||
| 798 | apprise | ||
| 799 | appro | ||
| 800 | approach | ||
| 801 | approbation | ||
| 802 | appropriate | ||
| 803 | approval | ||
| 804 | approve | ||
| 805 | approximate | ||
| 806 | appurtenance | ||
| 807 | apricot | ||
| 808 | april | ||
| 809 | apron | ||
| 810 | apropos | ||
| 811 | apse | ||
| 812 | apt | ||
| 813 | aptitude | ||
| 814 | aqualung | ||
| 815 | aquamarine | ||
| 816 | aquanaut | ||
| 817 | aquaplane | ||
| 818 | aquarium | ||
| 819 | aquarius | ||
| 820 | aquatic | ||
| 821 | aquatint | ||
| 822 | aquavit | ||
| 823 | aqueduct | ||
| 824 | aqueous | ||
| 825 | aquiline | ||
| 826 | arab | ||
| 827 | arabesque | ||
| 828 | arabian | ||
| 829 | arabic | ||
| 830 | arabist | ||
| 831 | arable | ||
| 832 | arachnid | ||
| 833 | arbiter | ||
| 834 | arbitrament | ||
| 835 | arbitrary | ||
| 836 | arbitrate | ||
| 837 | arbitration | ||
| 838 | arbitrator | ||
| 839 | arbor | ||
| 840 | arboreal | ||
| 841 | arbour | ||
| 842 | arc | ||
| 843 | arcade | ||
| 844 | arcadian | ||
| 845 | arcane | ||
| 846 | arch | ||
| 847 | archaeology | ||
| 848 | archaic | ||
| 849 | archangel | ||
| 850 | archbishop | ||
| 851 | archdeacon | ||
| 852 | archdiocese | ||
| 853 | archduke | ||
| 854 | archer | ||
| 855 | archetype | ||
| 856 | archimandrite | ||
| 857 | archipelago | ||
| 858 | architect | ||
| 859 | architecture | ||
| 860 | archives | ||
| 861 | archway | ||
| 862 | arctic | ||
| 863 | ardent | ||
| 864 | ardour | ||
| 865 | arduous | ||
| 866 | are | ||
| 867 | area | ||
| 868 | areca | ||
| 869 | arena | ||
| 870 | arete | ||
| 871 | argent | ||
| 872 | argon | ||
| 873 | argonaut | ||
| 874 | argosy | ||
| 875 | argot | ||
| 876 | argue | ||
| 877 | argument | ||
| 878 | argumentation | ||
| 879 | argus | ||
| 880 | aria | ||
| 881 | arid | ||
| 882 | aries | ||
| 883 | aright | ||
| 884 | arise | ||
| 885 | aristocracy | ||
| 886 | aristocrat | ||
| 887 | arithmetic | ||
| 888 | ark | ||
| 889 | arm | ||
| 890 | armada | ||
| 891 | armadillo | ||
| 892 | armageddon | ||
| 893 | armament | ||
| 894 | armature | ||
| 895 | armistice | ||
| 896 | armoire | ||
| 897 | armor | ||
| 898 | armorial | ||
| 899 | armour | ||
| 900 | arms | ||
| 901 | army | ||
| 902 | arnica | ||
| 903 | aroma | ||
| 904 | arose | ||
| 905 | around | ||
| 906 | arouse | ||
| 907 | arpeggio | ||
| 908 | arquebus | ||
| 909 | arrack | ||
| 910 | arraign | ||
| 911 | arrange | ||
| 912 | arrangement | ||
| 913 | arrant | ||
| 914 | arras | ||
| 915 | array | ||
| 916 | arrears | ||
| 917 | arrest | ||
| 918 | arrival | ||
| 919 | arrive | ||
| 920 | arrogant | ||
| 921 | arrogate | ||
| 922 | arrow | ||
| 923 | arrowroot | ||
| 924 | arse | ||
| 925 | arsenal | ||
| 926 | arsenic | ||
| 927 | arson | ||
| 928 | art | ||
| 929 | artefact | ||
| 930 | arterial | ||
| 931 | arteriosclerosis | ||
| 932 | artery | ||
| 933 | artesian | ||
| 934 | artful | ||
| 935 | arthritis | ||
| 936 | artichoke | ||
| 937 | article | ||
| 938 | articulate | ||
| 939 | articulation | ||
| 940 | artifact | ||
| 941 | artifice | ||
| 942 | artificer | ||
| 943 | artificial | ||
| 944 | artillery | ||
| 945 | artisan | ||
| 946 | artist | ||
| 947 | artiste | ||
| 948 | artistic | ||
| 949 | artistry | ||
| 950 | artless | ||
| 951 | arty | ||
| 952 | arum | ||
| 953 | aryan | ||
| 954 | as | ||
| 955 | asbestos | ||
| 956 | ascend | ||
| 957 | ascendancy | ||
| 958 | ascendant | ||
| 959 | ascension | ||
| 960 | ascent | ||
| 961 | ascertain | ||
| 962 | ascetic | ||
| 963 | ascorbic | ||
| 964 | ascribe | ||
| 965 | asdic | ||
| 966 | aseptic | ||
| 967 | asexual | ||
| 968 | ash | ||
| 969 | ashamed | ||
| 970 | ashen | ||
| 971 | ashore | ||
| 972 | ashy | ||
| 973 | asian | ||
| 974 | asiatic | ||
| 975 | aside | ||
| 976 | asinine | ||
| 977 | ask | ||
| 978 | askance | ||
| 979 | askew | ||
| 980 | asking | ||
| 981 | aslant | ||
| 982 | asleep | ||
| 983 | asp | ||
| 984 | asparagus | ||
| 985 | aspect | ||
| 986 | aspen | ||
| 987 | asperity | ||
| 988 | asperse | ||
| 989 | asphalt | ||
| 990 | asphodel | ||
| 991 | asphyxia | ||
| 992 | aspic | ||
| 993 | aspidistra | ||
| 994 | aspirant | ||
| 995 | aspirate | ||
| 996 | aspiration | ||
| 997 | aspire | ||
| 998 | aspirin | ||
| 999 | ass | ||
| 1000 | assagai | ||
| 1001 | assail | ||
| 1002 | assassin | ||
| 1003 | assault | ||
| 1004 | assay | ||
| 1005 | assegai | ||
| 1006 | assemblage | ||
| 1007 | assemble | ||
| 1008 | assembly | ||
| 1009 | assent | ||
| 1010 | assert | ||
| 1011 | assertion | ||
| 1012 | assertive | ||
| 1013 | assess | ||
| 1014 | asset | ||
| 1015 | asseverate | ||
| 1016 | assiduity | ||
| 1017 | assiduous | ||
| 1018 | assign | ||
| 1019 | assignation | ||
| 1020 | assimilate | ||
| 1021 | assist | ||
| 1022 | assize | ||
| 1023 | associate | ||
| 1024 | association | ||
| 1025 | assonance | ||
| 1026 | assorted | ||
| 1027 | assuage | ||
| 1028 | assume | ||
| 1029 | assumption | ||
| 1030 | assurance | ||
| 1031 | assure | ||
| 1032 | aster | ||
| 1033 | asterisk | ||
| 1034 | astern | ||
| 1035 | asteroid | ||
| 1036 | asthma | ||
| 1037 | astigmatism | ||
| 1038 | astir | ||
| 1039 | astonish | ||
| 1040 | astound | ||
| 1041 | astrakhan | ||
| 1042 | astral | ||
| 1043 | astray | ||
| 1044 | astride | ||
| 1045 | astringent | ||
| 1046 | astrodome | ||
| 1047 | astrolabe | ||
| 1048 | astrology | ||
| 1049 | astronaut | ||
| 1050 | astronomy | ||
| 1051 | astrophysics | ||
| 1052 | astute | ||
| 1053 | asunder | ||
| 1054 | asylum | ||
| 1055 | at | ||
| 1056 | atabrine | ||
| 1057 | atavism | ||
| 1058 | ate | ||
| 1059 | atelier | ||
| 1060 | atheism | ||
| 1061 | athirst | ||
| 1062 | athlete | ||
| 1063 | athletic | ||
| 1064 | athletics | ||
| 1065 | athwart | ||
| 1066 | atishoo | ||
| 1067 | atlas | ||
| 1068 | atmosphere | ||
| 1069 | atmospheric | ||
| 1070 | atoll | ||
| 1071 | atom | ||
| 1072 | atomic | ||
| 1073 | atomize | ||
| 1074 | atonal | ||
| 1075 | atone | ||
| 1076 | atop | ||
| 1077 | atrabilious | ||
| 1078 | atrocious | ||
| 1079 | atrocity | ||
| 1080 | atrophy | ||
| 1081 | attaboy | ||
| 1082 | attach | ||
| 1083 | attache | ||
| 1084 | attack | ||
| 1085 | attain | ||
| 1086 | attainder | ||
| 1087 | attar | ||
| 1088 | attempt | ||
| 1089 | attend | ||
| 1090 | attendance | ||
| 1091 | attendant | ||
| 1092 | attention | ||
| 1093 | attentive | ||
| 1094 | attenuate | ||
| 1095 | attest | ||
| 1096 | attic | ||
| 1097 | attire | ||
| 1098 | attitude | ||
| 1099 | attorney | ||
| 1100 | attract | ||
| 1101 | attraction | ||
| 1102 | attractive | ||
| 1103 | attribute | ||
| 1104 | attributive | ||
| 1105 | attrition | ||
| 1106 | attune | ||
| 1107 | aubergine | ||
| 1108 | aubrietia | ||
| 1109 | auburn | ||
| 1110 | auction | ||
| 1111 | audacious | ||
| 1112 | audible | ||
| 1113 | audience | ||
| 1114 | audit | ||
| 1115 | audition | ||
| 1116 | auditor | ||
| 1117 | auditorium | ||
| 1118 | auditory | ||
| 1119 | auger | ||
| 1120 | aught | ||
| 1121 | augment | ||
| 1122 | augur | ||
| 1123 | august | ||
| 1124 | augustan | ||
| 1125 | auk | ||
| 1126 | aunt | ||
| 1127 | aura | ||
| 1128 | aural | ||
| 1129 | aureole | ||
| 1130 | auricle | ||
| 1131 | auricular | ||
| 1132 | auriferous | ||
| 1133 | aurora | ||
| 1134 | auspices | ||
| 1135 | auspicious | ||
| 1136 | aussie | ||
| 1137 | austere | ||
| 1138 | autarchy | ||
| 1139 | autarky | ||
| 1140 | authentic | ||
| 1141 | authenticate | ||
| 1142 | author | ||
| 1143 | authoritarian | ||
| 1144 | authoritative | ||
| 1145 | authority | ||
| 1146 | authorize | ||
| 1147 | autism | ||
| 1148 | auto | ||
| 1149 | autobahn | ||
| 1150 | autobiography | ||
| 1151 | autocracy | ||
| 1152 | autocrat | ||
| 1153 | autogiro | ||
| 1154 | autograph | ||
| 1155 | automat | ||
| 1156 | automate | ||
| 1157 | automatic | ||
| 1158 | automation | ||
| 1159 | automaton | ||
| 1160 | automobile | ||
| 1161 | autonomous | ||
| 1162 | autopsy | ||
| 1163 | autostrada | ||
| 1164 | autumn | ||
| 1165 | auxiliary | ||
| 1166 | avail | ||
| 1167 | available | ||
| 1168 | avalanche | ||
| 1169 | avarice | ||
| 1170 | avast | ||
| 1171 | avatar | ||
| 1172 | avaunt | ||
| 1173 | avenge | ||
| 1174 | avenue | ||
| 1175 | aver | ||
| 1176 | average | ||
| 1177 | averse | ||
| 1178 | aversion | ||
| 1179 | avert | ||
| 1180 | aviary | ||
| 1181 | aviation | ||
| 1182 | avid | ||
| 1183 | avocado | ||
| 1184 | avocation | ||
| 1185 | avoid | ||
| 1186 | avoirdupois | ||
| 1187 | avouch | ||
| 1188 | avow | ||
| 1189 | avuncular | ||
| 1190 | await | ||
| 1191 | awake | ||
| 1192 | awaken | ||
| 1193 | award | ||
| 1194 | aware | ||
| 1195 | awash | ||
| 1196 | away | ||
| 1197 | awe | ||
| 1198 | aweigh | ||
| 1199 | awful | ||
| 1200 | awhile | ||
| 1201 | awkward | ||
| 1202 | awl | ||
| 1203 | awning | ||
| 1204 | awoke | ||
| 1205 | awry | ||
| 1206 | ax | ||
| 1207 | axe | ||
| 1208 | axiom | ||
| 1209 | axis | ||
| 1210 | axle | ||
| 1211 | ay | ||
| 1212 | ayah | ||
| 1213 | aye | ||
| 1214 | azalea | ||
| 1215 | azimuth | ||
| 1216 | azure | ||
| 1217 | b | ||
| 1218 | baa | ||
| 1219 | baas | ||
| 1220 | babble | ||
| 1221 | babe | ||
| 1222 | babel | ||
| 1223 | baboo | ||
| 1224 | baboon | ||
| 1225 | babu | ||
| 1226 | baby | ||
| 1227 | baccalaureate | ||
| 1228 | baccarat | ||
| 1229 | bacchanal | ||
| 1230 | baccy | ||
| 1231 | bachelor | ||
| 1232 | bacillus | ||
| 1233 | back | ||
| 1234 | backgammon | ||
| 1235 | backsheesh | ||
| 1236 | backward | ||
| 1237 | bacon | ||
| 1238 | bacterium | ||
| 1239 | bad | ||
| 1240 | bade | ||
| 1241 | badge | ||
| 1242 | badger | ||
| 1243 | badinage | ||
| 1244 | badminton | ||
| 1245 | baffle | ||
| 1246 | bag | ||
| 1247 | bagatelle | ||
| 1248 | baggage | ||
| 1249 | baggy | ||
| 1250 | bagnio | ||
| 1251 | bagpipe | ||
| 1252 | bags | ||
| 1253 | bah | ||
| 1254 | bail | ||
| 1255 | bailey | ||
| 1256 | bailiff | ||
| 1257 | bairn | ||
| 1258 | bait | ||
| 1259 | baize | ||
| 1260 | bake | ||
| 1261 | bakelite | ||
| 1262 | baksheesh | ||
| 1263 | balalaika | ||
| 1264 | balance | ||
| 1265 | balcony | ||
| 1266 | bald | ||
| 1267 | balderdash | ||
| 1268 | baldric | ||
| 1269 | bale | ||
| 1270 | balk | ||
| 1271 | ball | ||
| 1272 | ballad | ||
| 1273 | ballade | ||
| 1274 | ballast | ||
| 1275 | ballerina | ||
| 1276 | ballet | ||
| 1277 | ballistic | ||
| 1278 | ballocks | ||
| 1279 | balloon | ||
| 1280 | ballot | ||
| 1281 | bally | ||
| 1282 | ballyhoo | ||
| 1283 | balm | ||
| 1284 | baloney | ||
| 1285 | balsa | ||
| 1286 | balsam | ||
| 1287 | baluster | ||
| 1288 | balustrade | ||
| 1289 | bambino | ||
| 1290 | bamboo | ||
| 1291 | bamboozle | ||
| 1292 | ban | ||
| 1293 | banal | ||
| 1294 | banana | ||
| 1295 | band | ||
| 1296 | bandage | ||
| 1297 | bandanna | ||
| 1298 | bandbox | ||
| 1299 | bandeau | ||
| 1300 | bandit | ||
| 1301 | bandoleer | ||
| 1302 | bandy | ||
| 1303 | bane | ||
| 1304 | bang | ||
| 1305 | banger | ||
| 1306 | bangle | ||
| 1307 | banian | ||
| 1308 | banish | ||
| 1309 | banister | ||
| 1310 | banjo | ||
| 1311 | bank | ||
| 1312 | bankrupt | ||
| 1313 | banner | ||
| 1314 | bannock | ||
| 1315 | banns | ||
| 1316 | banquet | ||
| 1317 | banshee | ||
| 1318 | bant | ||
| 1319 | bantam | ||
| 1320 | banter | ||
| 1321 | bantu | ||
| 1322 | banyan | ||
| 1323 | baobab | ||
| 1324 | baptism | ||
| 1325 | baptist | ||
| 1326 | baptize | ||
| 1327 | bar | ||
| 1328 | barb | ||
| 1329 | barbarian | ||
| 1330 | barbaric | ||
| 1331 | barbarism | ||
| 1332 | barbarity | ||
| 1333 | barbarize | ||
| 1334 | barbarous | ||
| 1335 | barbecue | ||
| 1336 | barbel | ||
| 1337 | barber | ||
| 1338 | barbican | ||
| 1339 | barbitone | ||
| 1340 | barbiturate | ||
| 1341 | barcarole | ||
| 1342 | bard | ||
| 1343 | bare | ||
| 1344 | bargain | ||
| 1345 | barge | ||
| 1346 | bargee | ||
| 1347 | baritone | ||
| 1348 | barium | ||
| 1349 | bark | ||
| 1350 | barker | ||
| 1351 | barley | ||
| 1352 | barm | ||
| 1353 | barmy | ||
| 1354 | barn | ||
| 1355 | barnacle | ||
| 1356 | barometer | ||
| 1357 | baron | ||
| 1358 | baronet | ||
| 1359 | baroque | ||
| 1360 | barouche | ||
| 1361 | barque | ||
| 1362 | barrack | ||
| 1363 | barracuda | ||
| 1364 | barrage | ||
| 1365 | barred | ||
| 1366 | barrel | ||
| 1367 | barren | ||
| 1368 | barricade | ||
| 1369 | barrier | ||
| 1370 | barring | ||
| 1371 | barrister | ||
| 1372 | barrow | ||
| 1373 | barter | ||
| 1374 | basalt | ||
| 1375 | bascule | ||
| 1376 | base | ||
| 1377 | baseball | ||
| 1378 | basement | ||
| 1379 | bash | ||
| 1380 | bashful | ||
| 1381 | basic | ||
| 1382 | basil | ||
| 1383 | basilica | ||
| 1384 | basilisk | ||
| 1385 | basin | ||
| 1386 | basis | ||
| 1387 | bask | ||
| 1388 | basket | ||
| 1389 | bass | ||
| 1390 | bassinet | ||
| 1391 | bassoon | ||
| 1392 | bast | ||
| 1393 | bastard | ||
| 1394 | baste | ||
| 1395 | bastinado | ||
| 1396 | bastion | ||
| 1397 | bat | ||
| 1398 | batch | ||
| 1399 | bate | ||
| 1400 | bath | ||
| 1401 | bathe | ||
| 1402 | bathing | ||
| 1403 | bathos | ||
| 1404 | bathysphere | ||
| 1405 | batik | ||
| 1406 | batiste | ||
| 1407 | batman | ||
| 1408 | baton | ||
| 1409 | bats | ||
| 1410 | battalion | ||
| 1411 | batten | ||
| 1412 | batter | ||
| 1413 | battery | ||
| 1414 | batting | ||
| 1415 | battle | ||
| 1416 | battledore | ||
| 1417 | battlements | ||
| 1418 | battue | ||
| 1419 | batty | ||
| 1420 | bauble | ||
| 1421 | baulk | ||
| 1422 | bauxite | ||
| 1423 | bawbee | ||
| 1424 | bawd | ||
| 1425 | bawl | ||
| 1426 | bay | ||
| 1427 | bayonet | ||
| 1428 | bayou | ||
| 1429 | bazaar | ||
| 1430 | bazooka | ||
| 1431 | be | ||
| 1432 | beach | ||
| 1433 | beacon | ||
| 1434 | bead | ||
| 1435 | beadle | ||
| 1436 | beady | ||
| 1437 | beagle | ||
| 1438 | beak | ||
| 1439 | beaker | ||
| 1440 | beam | ||
| 1441 | bean | ||
| 1442 | bear | ||
| 1443 | bearable | ||
| 1444 | beard | ||
| 1445 | bearer | ||
| 1446 | bearing | ||
| 1447 | bearish | ||
| 1448 | beast | ||
| 1449 | beat | ||
| 1450 | beaten | ||
| 1451 | beater | ||
| 1452 | beatific | ||
| 1453 | beatify | ||
| 1454 | beatitude | ||
| 1455 | beatnik | ||
| 1456 | beau | ||
| 1457 | beaujolais | ||
| 1458 | beauteous | ||
| 1459 | beautician | ||
| 1460 | beautiful | ||
| 1461 | beauty | ||
| 1462 | beaver | ||
| 1463 | becalmed | ||
| 1464 | because | ||
| 1465 | beck | ||
| 1466 | beckon | ||
| 1467 | become | ||
| 1468 | bed | ||
| 1469 | bedaubed | ||
| 1470 | bedding | ||
| 1471 | bedecked | ||
| 1472 | bedevil | ||
| 1473 | bedewed | ||
| 1474 | bedimmed | ||
| 1475 | bedlam | ||
| 1476 | bedouin | ||
| 1477 | bedraggled | ||
| 1478 | beduin | ||
| 1479 | bee | ||
| 1480 | beech | ||
| 1481 | beef | ||
| 1482 | been | ||
| 1483 | beep | ||
| 1484 | beer | ||
| 1485 | beeswax | ||
| 1486 | beet | ||
| 1487 | beetle | ||
| 1488 | beeves | ||
| 1489 | befall | ||
| 1490 | befit | ||
| 1491 | befogged | ||
| 1492 | before | ||
| 1493 | beforehand | ||
| 1494 | befoul | ||
| 1495 | befriend | ||
| 1496 | beg | ||
| 1497 | begad | ||
| 1498 | began | ||
| 1499 | beget | ||
| 1500 | beggar | ||
| 1501 | begin | ||
| 1502 | begone | ||
| 1503 | begonia | ||
| 1504 | begorra | ||
| 1505 | begot | ||
| 1506 | begotten | ||
| 1507 | begrimed | ||
| 1508 | begrudge | ||
| 1509 | beguile | ||
| 1510 | begum | ||
| 1511 | begun | ||
| 1512 | behalf | ||
| 1513 | behave | ||
| 1514 | behaviour | ||
| 1515 | behead | ||
| 1516 | beheld | ||
| 1517 | behest | ||
| 1518 | behind | ||
| 1519 | behindhand | ||
| 1520 | behold | ||
| 1521 | beholden | ||
| 1522 | behove | ||
| 1523 | beige | ||
| 1524 | being | ||
| 1525 | bejewelled | ||
| 1526 | belabour | ||
| 1527 | belated | ||
| 1528 | belay | ||
| 1529 | belch | ||
| 1530 | beldam | ||
| 1531 | beldame | ||
| 1532 | beleaguer | ||
| 1533 | belfry | ||
| 1534 | belie | ||
| 1535 | belief | ||
| 1536 | believe | ||
| 1537 | belike | ||
| 1538 | belittle | ||
| 1539 | bell | ||
| 1540 | belladonna | ||
| 1541 | belle | ||
| 1542 | bellicose | ||
| 1543 | belligerency | ||
| 1544 | belligerent | ||
| 1545 | bellow | ||
| 1546 | bellows | ||
| 1547 | belly | ||
| 1548 | belong | ||
| 1549 | beloved | ||
| 1550 | below | ||
| 1551 | belt | ||
| 1552 | bemoan | ||
| 1553 | bemused | ||
| 1554 | ben | ||
| 1555 | bench | ||
| 1556 | bend | ||
| 1557 | beneath | ||
| 1558 | benedick | ||
| 1559 | benedictine | ||
| 1560 | benediction | ||
| 1561 | benefaction | ||
| 1562 | benefactor | ||
| 1563 | benefice | ||
| 1564 | beneficence | ||
| 1565 | beneficial | ||
| 1566 | beneficiary | ||
| 1567 | benefit | ||
| 1568 | benevolence | ||
| 1569 | benevolent | ||
| 1570 | benighted | ||
| 1571 | benign | ||
| 1572 | benignant | ||
| 1573 | benignity | ||
| 1574 | benison | ||
| 1575 | bent | ||
| 1576 | benumbed | ||
| 1577 | benzedrine | ||
| 1578 | benzene | ||
| 1579 | benzine | ||
| 1580 | benzol | ||
| 1581 | bequeath | ||
| 1582 | bequest | ||
| 1583 | berate | ||
| 1584 | bereave | ||
| 1585 | bereft | ||
| 1586 | beret | ||
| 1587 | berg | ||
| 1588 | berry | ||
| 1589 | berserk | ||
| 1590 | berth | ||
| 1591 | beryl | ||
| 1592 | beseech | ||
| 1593 | beseem | ||
| 1594 | beset | ||
| 1595 | beshrew | ||
| 1596 | beside | ||
| 1597 | besides | ||
| 1598 | besiege | ||
| 1599 | besmear | ||
| 1600 | besmirch | ||
| 1601 | besom | ||
| 1602 | besotted | ||
| 1603 | besought | ||
| 1604 | bespangled | ||
| 1605 | bespattered | ||
| 1606 | bespeak | ||
| 1607 | best | ||
| 1608 | bestial | ||
| 1609 | bestiary | ||
| 1610 | bestir | ||
| 1611 | bestow | ||
| 1612 | bestrew | ||
| 1613 | bestride | ||
| 1614 | bet | ||
| 1615 | beta | ||
| 1616 | betake | ||
| 1617 | betel | ||
| 1618 | bethel | ||
| 1619 | bethink | ||
| 1620 | betide | ||
| 1621 | betimes | ||
| 1622 | betoken | ||
| 1623 | betook | ||
| 1624 | betray | ||
| 1625 | betroth | ||
| 1626 | better | ||
| 1627 | bettor | ||
| 1628 | between | ||
| 1629 | betwixt | ||
| 1630 | bevel | ||
| 1631 | beverage | ||
| 1632 | bevy | ||
| 1633 | bewail | ||
| 1634 | beware | ||
| 1635 | bewilder | ||
| 1636 | bewitch | ||
| 1637 | bey | ||
| 1638 | beyond | ||
| 1639 | bezique | ||
| 1640 | bhang | ||
| 1641 | bias | ||
| 1642 | bib | ||
| 1643 | bible | ||
| 1644 | bibliography | ||
| 1645 | bibliophile | ||
| 1646 | bibulous | ||
| 1647 | bicameral | ||
| 1648 | bicarbonate | ||
| 1649 | bicentenary | ||
| 1650 | bicentennial | ||
| 1651 | biceps | ||
| 1652 | bicker | ||
| 1653 | bicycle | ||
| 1654 | bid | ||
| 1655 | bide | ||
| 1656 | bidet | ||
| 1657 | biennial | ||
| 1658 | bier | ||
| 1659 | biff | ||
| 1660 | bifocal | ||
| 1661 | bifurcate | ||
| 1662 | big | ||
| 1663 | bigamy | ||
| 1664 | bight | ||
| 1665 | bigot | ||
| 1666 | bijou | ||
| 1667 | bike | ||
| 1668 | bikini | ||
| 1669 | bilabial | ||
| 1670 | bilateral | ||
| 1671 | bilberry | ||
| 1672 | bile | ||
| 1673 | bilge | ||
| 1674 | bilharzia | ||
| 1675 | bilingual | ||
| 1676 | bilious | ||
| 1677 | bilk | ||
| 1678 | bill | ||
| 1679 | billet | ||
| 1680 | billhook | ||
| 1681 | billiards | ||
| 1682 | billingsgate | ||
| 1683 | billion | ||
| 1684 | billow | ||
| 1685 | billy | ||
| 1686 | biltong | ||
| 1687 | bimetallism | ||
| 1688 | bin | ||
| 1689 | binary | ||
| 1690 | bind | ||
| 1691 | bindweed | ||
| 1692 | bine | ||
| 1693 | binge | ||
| 1694 | bingo | ||
| 1695 | binnacle | ||
| 1696 | binoculars | ||
| 1697 | binomial | ||
| 1698 | biochemistry | ||
| 1699 | biodegradable | ||
| 1700 | biograph | ||
| 1701 | biography | ||
| 1702 | biology | ||
| 1703 | bioscope | ||
| 1704 | bipartisan | ||
| 1705 | biped | ||
| 1706 | biplane | ||
| 1707 | birch | ||
| 1708 | bird | ||
| 1709 | biretta | ||
| 1710 | biro | ||
| 1711 | birth | ||
| 1712 | biscuit | ||
| 1713 | bisect | ||
| 1714 | bisexual | ||
| 1715 | bishop | ||
| 1716 | bismuth | ||
| 1717 | bison | ||
| 1718 | bistro | ||
| 1719 | bit | ||
| 1720 | bitch | ||
| 1721 | bite | ||
| 1722 | bitten | ||
| 1723 | bitter | ||
| 1724 | bittern | ||
| 1725 | bitumen | ||
| 1726 | bivalve | ||
| 1727 | bivouac | ||
| 1728 | biz | ||
| 1729 | bizarre | ||
| 1730 | bizonal | ||
| 1731 | blab | ||
| 1732 | blabber | ||
| 1733 | black | ||
| 1734 | blackamoor | ||
| 1735 | blacken | ||
| 1736 | blacking | ||
| 1737 | bladder | ||
| 1738 | blade | ||
| 1739 | blaeberry | ||
| 1740 | blah | ||
| 1741 | blame | ||
| 1742 | blanch | ||
| 1743 | blancmange | ||
| 1744 | bland | ||
| 1745 | blandishment | ||
| 1746 | blank | ||
| 1747 | blanket | ||
| 1748 | blare | ||
| 1749 | blarney | ||
| 1750 | blase | ||
| 1751 | blaspheme | ||
| 1752 | blast | ||
| 1753 | blatant | ||
| 1754 | blather | ||
| 1755 | blaze | ||
| 1756 | blazer | ||
| 1757 | blazon | ||
| 1758 | bleach | ||
| 1759 | bleachers | ||
| 1760 | bleak | ||
| 1761 | bleary | ||
| 1762 | bleat | ||
| 1763 | bleed | ||
| 1764 | bleep | ||
| 1765 | blemish | ||
| 1766 | blench | ||
| 1767 | blend | ||
| 1768 | blent | ||
| 1769 | bless | ||
| 1770 | blether | ||
| 1771 | blew | ||
| 1772 | blight | ||
| 1773 | blighty | ||
| 1774 | blimey | ||
| 1775 | blimp | ||
| 1776 | blind | ||
| 1777 | blindfold | ||
| 1778 | blink | ||
| 1779 | blinkers | ||
| 1780 | blip | ||
| 1781 | bliss | ||
| 1782 | blister | ||
| 1783 | blithe | ||
| 1784 | blithering | ||
| 1785 | blithesome | ||
| 1786 | blitz | ||
| 1787 | blizzard | ||
| 1788 | bloated | ||
| 1789 | bloater | ||
| 1790 | blob | ||
| 1791 | bloc | ||
| 1792 | block | ||
| 1793 | blockade | ||
| 1794 | blockage | ||
| 1795 | blockhead | ||
| 1796 | blockhouse | ||
| 1797 | bloke | ||
| 1798 | blond | ||
| 1799 | blonde | ||
| 1800 | blood | ||
| 1801 | bloody | ||
| 1802 | bloom | ||
| 1803 | bloomer | ||
| 1804 | bloomers | ||
| 1805 | blossom | ||
| 1806 | blot | ||
| 1807 | blotch | ||
| 1808 | blotto | ||
| 1809 | blouse | ||
| 1810 | blow | ||
| 1811 | blower | ||
| 1812 | blown | ||
| 1813 | blowzy | ||
| 1814 | blubber | ||
| 1815 | bludgeon | ||
| 1816 | blue | ||
| 1817 | bluff | ||
| 1818 | blunder | ||
| 1819 | blunderbuss | ||
| 1820 | blunt | ||
| 1821 | blur | ||
| 1822 | blurb | ||
| 1823 | blurt | ||
| 1824 | blush | ||
| 1825 | bluster | ||
| 1826 | boa | ||
| 1827 | boar | ||
| 1828 | board | ||
| 1829 | boast | ||
| 1830 | boat | ||
| 1831 | boater | ||
| 1832 | boatswain | ||
| 1833 | bob | ||
| 1834 | bobbin | ||
| 1835 | bobby | ||
| 1836 | bobolink | ||
| 1837 | bobsled | ||
| 1838 | bobsleigh | ||
| 1839 | bobtail | ||
| 1840 | boche | ||
| 1841 | bode | ||
| 1842 | bodice | ||
| 1843 | bodily | ||
| 1844 | bodkin | ||
| 1845 | body | ||
| 1846 | boer | ||
| 1847 | boffin | ||
| 1848 | bog | ||
| 1849 | bogey | ||
| 1850 | boggle | ||
| 1851 | bogie | ||
| 1852 | bogus | ||
| 1853 | bogy | ||
| 1854 | bohemian | ||
| 1855 | boil | ||
| 1856 | boiler | ||
| 1857 | boisterous | ||
| 1858 | bold | ||
| 1859 | bole | ||
| 1860 | bolero | ||
| 1861 | boll | ||
| 1862 | bollard | ||
| 1863 | bollocks | ||
| 1864 | boloney | ||
| 1865 | bolshevik | ||
| 1866 | bolshy | ||
| 1867 | bolster | ||
| 1868 | bolt | ||
| 1869 | bomb | ||
| 1870 | bombard | ||
| 1871 | bombardier | ||
| 1872 | bombast | ||
| 1873 | bonanza | ||
| 1874 | bonbon | ||
| 1875 | bond | ||
| 1876 | bondage | ||
| 1877 | bone | ||
| 1878 | boner | ||
| 1879 | bonfire | ||
| 1880 | bongo | ||
| 1881 | bonhomie | ||
| 1882 | bonito | ||
| 1883 | bonkers | ||
| 1884 | bonnet | ||
| 1885 | bonny | ||
| 1886 | bonus | ||
| 1887 | bony | ||
| 1888 | boo | ||
| 1889 | boob | ||
| 1890 | booby | ||
| 1891 | boogie | ||
| 1892 | book | ||
| 1893 | bookie | ||
| 1894 | bookish | ||
| 1895 | booklet | ||
| 1896 | boom | ||
| 1897 | boomerang | ||
| 1898 | boon | ||
| 1899 | boor | ||
| 1900 | boost | ||
| 1901 | boot | ||
| 1902 | bootee | ||
| 1903 | booth | ||
| 1904 | bootleg | ||
| 1905 | bootless | ||
| 1906 | booty | ||
| 1907 | booze | ||
| 1908 | bopeep | ||
| 1909 | boracic | ||
| 1910 | borage | ||
| 1911 | borax | ||
| 1912 | bordeaux | ||
| 1913 | border | ||
| 1914 | bore | ||
| 1915 | boric | ||
| 1916 | born | ||
| 1917 | borne | ||
| 1918 | boron | ||
| 1919 | borough | ||
| 1920 | borrow | ||
| 1921 | borsch | ||
| 1922 | borstal | ||
| 1923 | bortsch | ||
| 1924 | borzoi | ||
| 1925 | bosh | ||
| 1926 | bosky | ||
| 1927 | bosom | ||
| 1928 | boss | ||
| 1929 | botany | ||
| 1930 | botch | ||
| 1931 | both | ||
| 1932 | bother | ||
| 1933 | bottle | ||
| 1934 | bottom | ||
| 1935 | botulism | ||
| 1936 | boudoir | ||
| 1937 | bougainvillea | ||
| 1938 | bough | ||
| 1939 | bought | ||
| 1940 | bouillon | ||
| 1941 | boulder | ||
| 1942 | boulevard | ||
| 1943 | bounce | ||
| 1944 | bound | ||
| 1945 | boundary | ||
| 1946 | bounden | ||
| 1947 | bounder | ||
| 1948 | boundless | ||
| 1949 | bounteous | ||
| 1950 | bountiful | ||
| 1951 | bounty | ||
| 1952 | bouquet | ||
| 1953 | bourbon | ||
| 1954 | bourgeois | ||
| 1955 | bourn | ||
| 1956 | bourse | ||
| 1957 | bout | ||
| 1958 | boutique | ||
| 1959 | bovine | ||
| 1960 | bovril | ||
| 1961 | bow | ||
| 1962 | bowdlerize | ||
| 1963 | bowel | ||
| 1964 | bower | ||
| 1965 | bowl | ||
| 1966 | bowler | ||
| 1967 | bowline | ||
| 1968 | bowls | ||
| 1969 | bowman | ||
| 1970 | bowsprit | ||
| 1971 | box | ||
| 1972 | boy | ||
| 1973 | boycott | ||
| 1974 | bra | ||
| 1975 | brace | ||
| 1976 | bracelet | ||
| 1977 | bracken | ||
| 1978 | bracket | ||
| 1979 | brackish | ||
| 1980 | bract | ||
| 1981 | brad | ||
| 1982 | bradawl | ||
| 1983 | brae | ||
| 1984 | brag | ||
| 1985 | brahmin | ||
| 1986 | braid | ||
| 1987 | braille | ||
| 1988 | brain | ||
| 1989 | braise | ||
| 1990 | brake | ||
| 1991 | bramble | ||
| 1992 | bran | ||
| 1993 | branch | ||
| 1994 | brand | ||
| 1995 | brandish | ||
| 1996 | brandy | ||
| 1997 | brash | ||
| 1998 | brass | ||
| 1999 | brassard | ||
| 2000 | brasserie | ||
| 2001 | brassiere | ||
| 2002 | brat | ||
| 2003 | bravado | ||
| 2004 | brave | ||
| 2005 | bravo | ||
| 2006 | brawl | ||
| 2007 | brawn | ||
| 2008 | bray | ||
| 2009 | braze | ||
| 2010 | brazen | ||
| 2011 | brazier | ||
| 2012 | breach | ||
| 2013 | bread | ||
| 2014 | breadth | ||
| 2015 | break | ||
| 2016 | breakable | ||
| 2017 | breakage | ||
| 2018 | breaker | ||
| 2019 | breakfast | ||
| 2020 | breakneck | ||
| 2021 | breakwater | ||
| 2022 | bream | ||
| 2023 | breast | ||
| 2024 | breath | ||
| 2025 | breathe | ||
| 2026 | breech | ||
| 2027 | breeches | ||
| 2028 | breed | ||
| 2029 | breeze | ||
| 2030 | bren | ||
| 2031 | brethren | ||
| 2032 | breve | ||
| 2033 | brevet | ||
| 2034 | breviary | ||
| 2035 | brevity | ||
| 2036 | brew | ||
| 2037 | briar | ||
| 2038 | bribe | ||
| 2039 | brick | ||
| 2040 | bridal | ||
| 2041 | bride | ||
| 2042 | bridegroom | ||
| 2043 | bridesmaid | ||
| 2044 | bridge | ||
| 2045 | bridle | ||
| 2046 | brief | ||
| 2047 | briefs | ||
| 2048 | brier | ||
| 2049 | brig | ||
| 2050 | brigade | ||
| 2051 | brigand | ||
| 2052 | brigantine | ||
| 2053 | bright | ||
| 2054 | brill | ||
| 2055 | brilliant | ||
| 2056 | brilliantine | ||
| 2057 | brim | ||
| 2058 | brimstone | ||
| 2059 | brindled | ||
| 2060 | brine | ||
| 2061 | bring | ||
| 2062 | brink | ||
| 2063 | briny | ||
| 2064 | brioche | ||
| 2065 | briquet | ||
| 2066 | briquette | ||
| 2067 | brisk | ||
| 2068 | brisket | ||
| 2069 | bristle | ||
| 2070 | britain | ||
| 2071 | british | ||
| 2072 | briton | ||
| 2073 | brittle | ||
| 2074 | broach | ||
| 2075 | broad | ||
| 2076 | broadcast | ||
| 2077 | broadcloth | ||
| 2078 | broadsheet | ||
| 2079 | broadside | ||
| 2080 | broadways | ||
| 2081 | broadwise | ||
| 2082 | brocade | ||
| 2083 | broccoli | ||
| 2084 | brochure | ||
| 2085 | brogue | ||
| 2086 | broil | ||
| 2087 | broke | ||
| 2088 | broken | ||
| 2089 | broker | ||
| 2090 | brolly | ||
| 2091 | bromide | ||
| 2092 | bromine | ||
| 2093 | bronchi | ||
| 2094 | bronco | ||
| 2095 | bronze | ||
| 2096 | brooch | ||
| 2097 | brood | ||
| 2098 | brook | ||
| 2099 | broom | ||
| 2100 | bros | ||
| 2101 | broth | ||
| 2102 | brothel | ||
| 2103 | brother | ||
| 2104 | brougham | ||
| 2105 | brouhaha | ||
| 2106 | brow | ||
| 2107 | browbeat | ||
| 2108 | brown | ||
| 2109 | brownie | ||
| 2110 | browse | ||
| 2111 | bruin | ||
| 2112 | bruise | ||
| 2113 | bruit | ||
| 2114 | brunch | ||
| 2115 | brunette | ||
| 2116 | brunt | ||
| 2117 | brush | ||
| 2118 | brusque | ||
| 2119 | brussels | ||
| 2120 | brutal | ||
| 2121 | brute | ||
| 2122 | bubble | ||
| 2123 | bubonic | ||
| 2124 | buccaneer | ||
| 2125 | buck | ||
| 2126 | bucket | ||
| 2127 | buckle | ||
| 2128 | buckler | ||
| 2129 | buckram | ||
| 2130 | buckshot | ||
| 2131 | buckwheat | ||
| 2132 | bucolic | ||
| 2133 | bud | ||
| 2134 | buddhism | ||
| 2135 | buddy | ||
| 2136 | budge | ||
| 2137 | budgerigar | ||
| 2138 | budget | ||
| 2139 | budgie | ||
| 2140 | buff | ||
| 2141 | buffalo | ||
| 2142 | buffer | ||
| 2143 | buffet | ||
| 2144 | buffoon | ||
| 2145 | bug | ||
| 2146 | bugaboo | ||
| 2147 | bugbear | ||
| 2148 | bugger | ||
| 2149 | buggy | ||
| 2150 | bugle | ||
| 2151 | buhl | ||
| 2152 | build | ||
| 2153 | building | ||
| 2154 | bulb | ||
| 2155 | bulbul | ||
| 2156 | bulge | ||
| 2157 | bulk | ||
| 2158 | bulkhead | ||
| 2159 | bull | ||
| 2160 | bullet | ||
| 2161 | bulletin | ||
| 2162 | bullion | ||
| 2163 | bullock | ||
| 2164 | bully | ||
| 2165 | bulrush | ||
| 2166 | bulwark | ||
| 2167 | bum | ||
| 2168 | bumboat | ||
| 2169 | bump | ||
| 2170 | bumper | ||
| 2171 | bumpkin | ||
| 2172 | bumptious | ||
| 2173 | bun | ||
| 2174 | buna | ||
| 2175 | bunch | ||
| 2176 | bundle | ||
| 2177 | bung | ||
| 2178 | bungalow | ||
| 2179 | bungle | ||
| 2180 | bunion | ||
| 2181 | bunk | ||
| 2182 | bunker | ||
| 2183 | bunkum | ||
| 2184 | bunny | ||
| 2185 | bunsen | ||
| 2186 | bunting | ||
| 2187 | buoy | ||
| 2188 | buoyancy | ||
| 2189 | buoyant | ||
| 2190 | bur | ||
| 2191 | burberry | ||
| 2192 | burble | ||
| 2193 | burden | ||
| 2194 | burdock | ||
| 2195 | bureau | ||
| 2196 | bureaucracy | ||
| 2197 | bureaucrat | ||
| 2198 | burette | ||
| 2199 | burg | ||
| 2200 | burgeon | ||
| 2201 | burgess | ||
| 2202 | burgh | ||
| 2203 | burgher | ||
| 2204 | burglar | ||
| 2205 | burgomaster | ||
| 2206 | burgundy | ||
| 2207 | burial | ||
| 2208 | burke | ||
| 2209 | burlap | ||
| 2210 | burlesque | ||
| 2211 | burly | ||
| 2212 | burn | ||
| 2213 | burner | ||
| 2214 | burning | ||
| 2215 | burnish | ||
| 2216 | burnouse | ||
| 2217 | burp | ||
| 2218 | burr | ||
| 2219 | burrow | ||
| 2220 | bursar | ||
| 2221 | burst | ||
| 2222 | burthen | ||
| 2223 | burton | ||
| 2224 | bury | ||
| 2225 | bus | ||
| 2226 | busby | ||
| 2227 | bush | ||
| 2228 | bushel | ||
| 2229 | busier | ||
| 2230 | busiest | ||
| 2231 | business | ||
| 2232 | busker | ||
| 2233 | bust | ||
| 2234 | bustard | ||
| 2235 | buster | ||
| 2236 | bustle | ||
| 2237 | busy | ||
| 2238 | but | ||
| 2239 | butane | ||
| 2240 | butch | ||
| 2241 | butcher | ||
| 2242 | butler | ||
| 2243 | butt | ||
| 2244 | butter | ||
| 2245 | butterfly | ||
| 2246 | buttery | ||
| 2247 | buttock | ||
| 2248 | button | ||
| 2249 | buttress | ||
| 2250 | buxom | ||
| 2251 | buy | ||
| 2252 | buzz | ||
| 2253 | buzzard | ||
| 2254 | by | ||
| 2255 | bye | ||
| 2256 | bygone | ||
| 2257 | bypath | ||
| 2258 | byplay | ||
| 2259 | bystander | ||
| 2260 | byword | ||
| 2261 | c | ||
| 2262 | cab | ||
| 2263 | cabal | ||
| 2264 | cabaret | ||
| 2265 | cabbage | ||
| 2266 | cabby | ||
| 2267 | caber | ||
| 2268 | cabin | ||
| 2269 | cabinet | ||
| 2270 | cable | ||
| 2271 | caboodle | ||
| 2272 | caboose | ||
| 2273 | cacao | ||
| 2274 | cache | ||
| 2275 | cachet | ||
| 2276 | cachou | ||
| 2277 | cackle | ||
| 2278 | cacophony | ||
| 2279 | cactus | ||
| 2280 | cad | ||
| 2281 | cadaver | ||
| 2282 | caddie | ||
| 2283 | caddy | ||
| 2284 | cadence | ||
| 2285 | cadenza | ||
| 2286 | cadet | ||
| 2287 | cadge | ||
| 2288 | cadmium | ||
| 2289 | cadre | ||
| 2290 | caesar | ||
| 2291 | caesura | ||
| 2292 | cafe | ||
| 2293 | cafeteria | ||
| 2294 | caff | ||
| 2295 | caffeine | ||
| 2296 | caftan | ||
| 2297 | cage | ||
| 2298 | cagey | ||
| 2299 | cagoule | ||
| 2300 | cahoots | ||
| 2301 | caiman | ||
| 2302 | cairn | ||
| 2303 | caisson | ||
| 2304 | caitiff | ||
| 2305 | cajole | ||
| 2306 | cake | ||
| 2307 | calabash | ||
| 2308 | calamity | ||
| 2309 | calcify | ||
| 2310 | calcine | ||
| 2311 | calcium | ||
| 2312 | calculable | ||
| 2313 | calculate | ||
| 2314 | calculus | ||
| 2315 | caldron | ||
| 2316 | calendar | ||
| 2317 | calender | ||
| 2318 | calends | ||
| 2319 | calf | ||
| 2320 | calibrate | ||
| 2321 | calico | ||
| 2322 | calif | ||
| 2323 | calipers | ||
| 2324 | caliph | ||
| 2325 | calisthenics | ||
| 2326 | calk | ||
| 2327 | call | ||
| 2328 | calligraphy | ||
| 2329 | calliope | ||
| 2330 | callipers | ||
| 2331 | callisthenics | ||
| 2332 | callosity | ||
| 2333 | callous | ||
| 2334 | callow | ||
| 2335 | callus | ||
| 2336 | calm | ||
| 2337 | calomel | ||
| 2338 | calorie | ||
| 2339 | calumny | ||
| 2340 | calvary | ||
| 2341 | calve | ||
| 2342 | calvinism | ||
| 2343 | calypso | ||
| 2344 | calyx | ||
| 2345 | cam | ||
| 2346 | camaraderie | ||
| 2347 | camber | ||
| 2348 | cambric | ||
| 2349 | camel | ||
| 2350 | camellia | ||
| 2351 | camembert | ||
| 2352 | cameo | ||
| 2353 | camera | ||
| 2354 | camion | ||
| 2355 | camomile | ||
| 2356 | camouflage | ||
| 2357 | camp | ||
| 2358 | campaign | ||
| 2359 | campanile | ||
| 2360 | campanula | ||
| 2361 | camphor | ||
| 2362 | campion | ||
| 2363 | campus | ||
| 2364 | can | ||
| 2365 | canadian | ||
| 2366 | canal | ||
| 2367 | canape | ||
| 2368 | canard | ||
| 2369 | canary | ||
| 2370 | canasta | ||
| 2371 | cancan | ||
| 2372 | cancel | ||
| 2373 | cancer | ||
| 2374 | candelabrum | ||
| 2375 | candid | ||
| 2376 | candidate | ||
| 2377 | candied | ||
| 2378 | candle | ||
| 2379 | candour | ||
| 2380 | candy | ||
| 2381 | candytuft | ||
| 2382 | cane | ||
| 2383 | canine | ||
| 2384 | canister | ||
| 2385 | canker | ||
| 2386 | canna | ||
| 2387 | cannabis | ||
| 2388 | canned | ||
| 2389 | cannery | ||
| 2390 | cannibal | ||
| 2391 | cannon | ||
| 2392 | cannot | ||
| 2393 | canny | ||
| 2394 | canoe | ||
| 2395 | canon | ||
| 2396 | canonize | ||
| 2397 | canopy | ||
| 2398 | cant | ||
| 2399 | cantab | ||
| 2400 | cantaloup | ||
| 2401 | cantankerous | ||
| 2402 | cantata | ||
| 2403 | canteen | ||
| 2404 | canter | ||
| 2405 | canticle | ||
| 2406 | cantilever | ||
| 2407 | canto | ||
| 2408 | canton | ||
| 2409 | cantonment | ||
| 2410 | cantor | ||
| 2411 | canuck | ||
| 2412 | canvas | ||
| 2413 | canvass | ||
| 2414 | canyon | ||
| 2415 | cap | ||
| 2416 | capability | ||
| 2417 | capable | ||
| 2418 | capacious | ||
| 2419 | capacity | ||
| 2420 | caparison | ||
| 2421 | cape | ||
| 2422 | caper | ||
| 2423 | capillary | ||
| 2424 | capital | ||
| 2425 | capitalism | ||
| 2426 | capitalize | ||
| 2427 | capitation | ||
| 2428 | capitol | ||
| 2429 | capitulate | ||
| 2430 | capon | ||
| 2431 | caprice | ||
| 2432 | capricious | ||
| 2433 | capricorn | ||
| 2434 | capsicum | ||
| 2435 | capsize | ||
| 2436 | capstan | ||
| 2437 | capsule | ||
| 2438 | captain | ||
| 2439 | caption | ||
| 2440 | captious | ||
| 2441 | captivate | ||
| 2442 | captive | ||
| 2443 | captor | ||
| 2444 | capture | ||
| 2445 | car | ||
| 2446 | carafe | ||
| 2447 | caramel | ||
| 2448 | carapace | ||
| 2449 | carat | ||
| 2450 | caravan | ||
| 2451 | caraway | ||
| 2452 | carbide | ||
| 2453 | carbine | ||
| 2454 | carbohydrate | ||
| 2455 | carbon | ||
| 2456 | carborundum | ||
| 2457 | carboy | ||
| 2458 | carbuncle | ||
| 2459 | carburettor | ||
| 2460 | carcase | ||
| 2461 | carcass | ||
| 2462 | card | ||
| 2463 | cardamom | ||
| 2464 | cardboard | ||
| 2465 | cardiac | ||
| 2466 | cardigan | ||
| 2467 | cardinal | ||
| 2468 | care | ||
| 2469 | careen | ||
| 2470 | career | ||
| 2471 | careful | ||
| 2472 | careless | ||
| 2473 | caress | ||
| 2474 | caret | ||
| 2475 | cargo | ||
| 2476 | caribou | ||
| 2477 | caricature | ||
| 2478 | caries | ||
| 2479 | carillon | ||
| 2480 | carmelite | ||
| 2481 | carmine | ||
| 2482 | carnage | ||
| 2483 | carnal | ||
| 2484 | carnation | ||
| 2485 | carnival | ||
| 2486 | carnivore | ||
| 2487 | carol | ||
| 2488 | carouse | ||
| 2489 | carp | ||
| 2490 | carpal | ||
| 2491 | carpenter | ||
| 2492 | carpet | ||
| 2493 | carriage | ||
| 2494 | carrier | ||
| 2495 | carrion | ||
| 2496 | carrot | ||
| 2497 | carry | ||
| 2498 | cart | ||
| 2499 | cartel | ||
| 2500 | cartilage | ||
| 2501 | cartographer | ||
| 2502 | carton | ||
| 2503 | cartoon | ||
| 2504 | cartridge | ||
| 2505 | carve | ||
| 2506 | caryatid | ||
| 2507 | cascade | ||
| 2508 | case | ||
| 2509 | casein | ||
| 2510 | casement | ||
| 2511 | cash | ||
| 2512 | cashew | ||
| 2513 | cashier | ||
| 2514 | cashmere | ||
| 2515 | casing | ||
| 2516 | casino | ||
| 2517 | cask | ||
| 2518 | casket | ||
| 2519 | cassava | ||
| 2520 | casserole | ||
| 2521 | cassette | ||
| 2522 | cassock | ||
| 2523 | cassowary | ||
| 2524 | cast | ||
| 2525 | castanets | ||
| 2526 | castaway | ||
| 2527 | caste | ||
| 2528 | castellated | ||
| 2529 | caster | ||
| 2530 | castigate | ||
| 2531 | castle | ||
| 2532 | castor | ||
| 2533 | castrate | ||
| 2534 | casual | ||
| 2535 | casualty | ||
| 2536 | casuist | ||
| 2537 | cat | ||
| 2538 | cataclysm | ||
| 2539 | catacombs | ||
| 2540 | catafalque | ||
| 2541 | catalepsy | ||
| 2542 | catalogue | ||
| 2543 | catalpa | ||
| 2544 | catalysis | ||
| 2545 | catamaran | ||
| 2546 | catapult | ||
| 2547 | cataract | ||
| 2548 | catarrh | ||
| 2549 | catastrophe | ||
| 2550 | catch | ||
| 2551 | catchment | ||
| 2552 | catchup | ||
| 2553 | catechism | ||
| 2554 | catechize | ||
| 2555 | categorical | ||
| 2556 | category | ||
| 2557 | cater | ||
| 2558 | caterpillar | ||
| 2559 | caterwaul | ||
| 2560 | catgut | ||
| 2561 | catharsis | ||
| 2562 | cathedral | ||
| 2563 | cathode | ||
| 2564 | catholic | ||
| 2565 | catkin | ||
| 2566 | catsup | ||
| 2567 | cattish | ||
| 2568 | cattle | ||
| 2569 | catty | ||
| 2570 | caucasian | ||
| 2571 | caucus | ||
| 2572 | caught | ||
| 2573 | caul | ||
| 2574 | cauldron | ||
| 2575 | cauliflower | ||
| 2576 | caulk | ||
| 2577 | causal | ||
| 2578 | cause | ||
| 2579 | causerie | ||
| 2580 | causeway | ||
| 2581 | caustic | ||
| 2582 | cauterize | ||
| 2583 | caution | ||
| 2584 | cautious | ||
| 2585 | cavalcade | ||
| 2586 | cavalier | ||
| 2587 | cavalry | ||
| 2588 | cave | ||
| 2589 | caveat | ||
| 2590 | cavern | ||
| 2591 | caviar | ||
| 2592 | caviare | ||
| 2593 | cavil | ||
| 2594 | cavity | ||
| 2595 | cavort | ||
| 2596 | caw | ||
| 2597 | cayenne | ||
| 2598 | cayman | ||
| 2599 | caymen | ||
| 2600 | cease | ||
| 2601 | cedar | ||
| 2602 | cede | ||
| 2603 | cedilla | ||
| 2604 | ceiling | ||
| 2605 | celandine | ||
| 2606 | celebrant | ||
| 2607 | celebrate | ||
| 2608 | celerity | ||
| 2609 | celery | ||
| 2610 | celestial | ||
| 2611 | celibacy | ||
| 2612 | cell | ||
| 2613 | cellar | ||
| 2614 | cello | ||
| 2615 | cellophane | ||
| 2616 | cellular | ||
| 2617 | celluloid | ||
| 2618 | cellulose | ||
| 2619 | celsius | ||
| 2620 | celt | ||
| 2621 | cement | ||
| 2622 | cemetery | ||
| 2623 | cenotaph | ||
| 2624 | censer | ||
| 2625 | censor | ||
| 2626 | censorious | ||
| 2627 | censure | ||
| 2628 | census | ||
| 2629 | cent | ||
| 2630 | centaur | ||
| 2631 | centenarian | ||
| 2632 | centenary | ||
| 2633 | centennial | ||
| 2634 | center | ||
| 2635 | centigrade | ||
| 2636 | centime | ||
| 2637 | centipede | ||
| 2638 | central | ||
| 2639 | centralize | ||
| 2640 | centre | ||
| 2641 | centrifugal | ||
| 2642 | centripetal | ||
| 2643 | centurion | ||
| 2644 | century | ||
| 2645 | ceramic | ||
| 2646 | cereal | ||
| 2647 | cerebral | ||
| 2648 | cerebration | ||
| 2649 | ceremonial | ||
| 2650 | ceremonious | ||
| 2651 | ceremony | ||
| 2652 | cerise | ||
| 2653 | cert | ||
| 2654 | certain | ||
| 2655 | certifiable | ||
| 2656 | certificate | ||
| 2657 | certify | ||
| 2658 | certitude | ||
| 2659 | cerulean | ||
| 2660 | cervix | ||
| 2661 | cessation | ||
| 2662 | cession | ||
| 2663 | cesspit | ||
| 2664 | chafe | ||
| 2665 | chaff | ||
| 2666 | chaffinch | ||
| 2667 | chagrin | ||
| 2668 | chain | ||
| 2669 | chair | ||
| 2670 | chaise | ||
| 2671 | chalet | ||
| 2672 | chalice | ||
| 2673 | chalk | ||
| 2674 | challenge | ||
| 2675 | chamber | ||
| 2676 | chamberlain | ||
| 2677 | chameleon | ||
| 2678 | chamois | ||
| 2679 | chamomile | ||
| 2680 | champ | ||
| 2681 | champagne | ||
| 2682 | champion | ||
| 2683 | chance | ||
| 2684 | chancel | ||
| 2685 | chancellery | ||
| 2686 | chancellor | ||
| 2687 | chancery | ||
| 2688 | chancy | ||
| 2689 | chandelier | ||
| 2690 | chandler | ||
| 2691 | change | ||
| 2692 | changeling | ||
| 2693 | channel | ||
| 2694 | chant | ||
| 2695 | chantey | ||
| 2696 | chanty | ||
| 2697 | chaos | ||
| 2698 | chap | ||
| 2699 | chapel | ||
| 2700 | chaperon | ||
| 2701 | chapfallen | ||
| 2702 | chaplain | ||
| 2703 | chaplet | ||
| 2704 | chapman | ||
| 2705 | chapter | ||
| 2706 | char | ||
| 2707 | character | ||
| 2708 | charade | ||
| 2709 | charcoal | ||
| 2710 | chard | ||
| 2711 | charge | ||
| 2712 | chargeable | ||
| 2713 | charger | ||
| 2714 | chariot | ||
| 2715 | charisma | ||
| 2716 | charitable | ||
| 2717 | charity | ||
| 2718 | charivari | ||
| 2719 | charlady | ||
| 2720 | charlatan | ||
| 2721 | charleston | ||
| 2722 | charlock | ||
| 2723 | charm | ||
| 2724 | chart | ||
| 2725 | charter | ||
| 2726 | chartism | ||
| 2727 | chartreuse | ||
| 2728 | charwoman | ||
| 2729 | chary | ||
| 2730 | charybdis | ||
| 2731 | chase | ||
| 2732 | chasm | ||
| 2733 | chassis | ||
| 2734 | chaste | ||
| 2735 | chasten | ||
| 2736 | chastise | ||
| 2737 | chastity | ||
| 2738 | chasuble | ||
| 2739 | chat | ||
| 2740 | chateau | ||
| 2741 | chatelaine | ||
| 2742 | chattel | ||
| 2743 | chatter | ||
| 2744 | chauffeur | ||
| 2745 | chauvinism | ||
| 2746 | chaw | ||
| 2747 | cheap | ||
| 2748 | cheapen | ||
| 2749 | cheat | ||
| 2750 | check | ||
| 2751 | checker | ||
| 2752 | checkers | ||
| 2753 | checkmate | ||
| 2754 | cheddar | ||
| 2755 | cheek | ||
| 2756 | cheep | ||
| 2757 | cheer | ||
| 2758 | cheerful | ||
| 2759 | cheerio | ||
| 2760 | cheerless | ||
| 2761 | cheery | ||
| 2762 | cheese | ||
| 2763 | cheetah | ||
| 2764 | chef | ||
| 2765 | chemical | ||
| 2766 | chemise | ||
| 2767 | chemist | ||
| 2768 | chemistry | ||
| 2769 | chemotherapy | ||
| 2770 | chenille | ||
| 2771 | cheque | ||
| 2772 | chequer | ||
| 2773 | cherish | ||
| 2774 | cheroot | ||
| 2775 | cherry | ||
| 2776 | cherub | ||
| 2777 | chervil | ||
| 2778 | chess | ||
| 2779 | chest | ||
| 2780 | chesterfield | ||
| 2781 | chestnut | ||
| 2782 | chevron | ||
| 2783 | chew | ||
| 2784 | chianti | ||
| 2785 | chiaroscuro | ||
| 2786 | chic | ||
| 2787 | chicanery | ||
| 2788 | chichi | ||
| 2789 | chick | ||
| 2790 | chicken | ||
| 2791 | chicle | ||
| 2792 | chicory | ||
| 2793 | chide | ||
| 2794 | chief | ||
| 2795 | chieftain | ||
| 2796 | chiffon | ||
| 2797 | chiffonier | ||
| 2798 | chignon | ||
| 2799 | chilblain | ||
| 2800 | child | ||
| 2801 | chile | ||
| 2802 | chili | ||
| 2803 | chill | ||
| 2804 | chilli | ||
| 2805 | chilly | ||
| 2806 | chimaera | ||
| 2807 | chime | ||
| 2808 | chimera | ||
| 2809 | chimney | ||
| 2810 | chimp | ||
| 2811 | chimpanzee | ||
| 2812 | chin | ||
| 2813 | china | ||
| 2814 | chinchilla | ||
| 2815 | chine | ||
| 2816 | chink | ||
| 2817 | chintz | ||
| 2818 | chip | ||
| 2819 | chipmunk | ||
| 2820 | chippendale | ||
| 2821 | chiropodist | ||
| 2822 | chiropractor | ||
| 2823 | chirp | ||
| 2824 | chirpy | ||
| 2825 | chirrup | ||
| 2826 | chisel | ||
| 2827 | chit | ||
| 2828 | chivalry | ||
| 2829 | chive | ||
| 2830 | chivvy | ||
| 2831 | chivy | ||
| 2832 | chloride | ||
| 2833 | chlorine | ||
| 2834 | chloroform | ||
| 2835 | chlorophyll | ||
| 2836 | chock | ||
| 2837 | chocolate | ||
| 2838 | choice | ||
| 2839 | choir | ||
| 2840 | choke | ||
| 2841 | choker | ||
| 2842 | chokey | ||
| 2843 | choky | ||
| 2844 | choler | ||
| 2845 | cholera | ||
| 2846 | choose | ||
| 2847 | choosey | ||
| 2848 | choosy | ||
| 2849 | chop | ||
| 2850 | chopper | ||
| 2851 | choppy | ||
| 2852 | chopsticks | ||
| 2853 | choral | ||
| 2854 | chorale | ||
| 2855 | chord | ||
| 2856 | chore | ||
| 2857 | choreography | ||
| 2858 | chorister | ||
| 2859 | chortle | ||
| 2860 | chorus | ||
| 2861 | chose | ||
| 2862 | chosen | ||
| 2863 | chow | ||
| 2864 | chowder | ||
| 2865 | christ | ||
| 2866 | christen | ||
| 2867 | christendom | ||
| 2868 | christian | ||
| 2869 | christmas | ||
| 2870 | chromatic | ||
| 2871 | chrome | ||
| 2872 | chromium | ||
| 2873 | chromosome | ||
| 2874 | chronic | ||
| 2875 | chronicle | ||
| 2876 | chronological | ||
| 2877 | chronology | ||
| 2878 | chronometer | ||
| 2879 | chrysalis | ||
| 2880 | chrysanthemum | ||
| 2881 | chubby | ||
| 2882 | chuck | ||
| 2883 | chuckle | ||
| 2884 | chug | ||
| 2885 | chukker | ||
| 2886 | chum | ||
| 2887 | chump | ||
| 2888 | chunk | ||
| 2889 | church | ||
| 2890 | churl | ||
| 2891 | churn | ||
| 2892 | chute | ||
| 2893 | chutney | ||
| 2894 | cicada | ||
| 2895 | cicala | ||
| 2896 | cicatrice | ||
| 2897 | cicerone | ||
| 2898 | cider | ||
| 2899 | cigar | ||
| 2900 | cigarette | ||
| 2901 | cinch | ||
| 2902 | cinchona | ||
| 2903 | cincture | ||
| 2904 | cinder | ||
| 2905 | cinderella | ||
| 2906 | cinema | ||
| 2907 | cinnamon | ||
| 2908 | cinquefoil | ||
| 2909 | cipher | ||
| 2910 | circa | ||
| 2911 | circle | ||
| 2912 | circlet | ||
| 2913 | circuit | ||
| 2914 | circuitous | ||
| 2915 | circular | ||
| 2916 | circulate | ||
| 2917 | circulation | ||
| 2918 | circumcise | ||
| 2919 | circumference | ||
| 2920 | circumflex | ||
| 2921 | circumlocution | ||
| 2922 | circumnavigate | ||
| 2923 | circumscribe | ||
| 2924 | circumspect | ||
| 2925 | circumstance | ||
| 2926 | circumstantial | ||
| 2927 | circumvent | ||
| 2928 | circus | ||
| 2929 | cirrhosis | ||
| 2930 | cirrus | ||
| 2931 | cissy | ||
| 2932 | cistern | ||
| 2933 | citadel | ||
| 2934 | cite | ||
| 2935 | citizen | ||
| 2936 | citric | ||
| 2937 | citron | ||
| 2938 | citrous | ||
| 2939 | citrus | ||
| 2940 | city | ||
| 2941 | civet | ||
| 2942 | civic | ||
| 2943 | civies | ||
| 2944 | civil | ||
| 2945 | civilian | ||
| 2946 | civilization | ||
| 2947 | civilize | ||
| 2948 | civvies | ||
| 2949 | clack | ||
| 2950 | clad | ||
| 2951 | claim | ||
| 2952 | clairvoyance | ||
| 2953 | clam | ||
| 2954 | clamber | ||
| 2955 | clammy | ||
| 2956 | clamour | ||
| 2957 | clamp | ||
| 2958 | clan | ||
| 2959 | clandestine | ||
| 2960 | clang | ||
| 2961 | clangour | ||
| 2962 | clank | ||
| 2963 | clannish | ||
| 2964 | clansman | ||
| 2965 | clap | ||
| 2966 | clapboard | ||
| 2967 | clapper | ||
| 2968 | claptrap | ||
| 2969 | claque | ||
| 2970 | claret | ||
| 2971 | clarify | ||
| 2972 | clarinet | ||
| 2973 | clarion | ||
| 2974 | clarity | ||
| 2975 | clash | ||
| 2976 | clasp | ||
| 2977 | class | ||
| 2978 | classic | ||
| 2979 | classical | ||
| 2980 | classicist | ||
| 2981 | classification | ||
| 2982 | classify | ||
| 2983 | classy | ||
| 2984 | clatter | ||
| 2985 | clause | ||
| 2986 | claustrophobia | ||
| 2987 | clavichord | ||
| 2988 | clavicle | ||
| 2989 | claw | ||
| 2990 | clay | ||
| 2991 | clean | ||
| 2992 | cleanly | ||
| 2993 | cleanse | ||
| 2994 | clear | ||
| 2995 | clearance | ||
| 2996 | clearing | ||
| 2997 | clearly | ||
| 2998 | cleat | ||
| 2999 | cleavage | ||
| 3000 | cleave | ||
| 3001 | cleaver | ||
| 3002 | clef | ||
| 3003 | cleft | ||
| 3004 | clematis | ||
| 3005 | clemency | ||
| 3006 | clement | ||
| 3007 | clench | ||
| 3008 | clerestory | ||
| 3009 | clergy | ||
| 3010 | cleric | ||
| 3011 | clerical | ||
| 3012 | clerihew | ||
| 3013 | clerk | ||
| 3014 | clever | ||
| 3015 | clew | ||
| 3016 | cliche | ||
| 3017 | click | ||
| 3018 | client | ||
| 3019 | cliff | ||
| 3020 | climacteric | ||
| 3021 | climactic | ||
| 3022 | climate | ||
| 3023 | climax | ||
| 3024 | climb | ||
| 3025 | clime | ||
| 3026 | clinch | ||
| 3027 | cling | ||
| 3028 | clinic | ||
| 3029 | clinical | ||
| 3030 | clink | ||
| 3031 | clinker | ||
| 3032 | clip | ||
| 3033 | clipper | ||
| 3034 | clique | ||
| 3035 | clitoris | ||
| 3036 | cloak | ||
| 3037 | clobber | ||
| 3038 | cloche | ||
| 3039 | clock | ||
| 3040 | clod | ||
| 3041 | clog | ||
| 3042 | cloisonne | ||
| 3043 | cloister | ||
| 3044 | clone | ||
| 3045 | close | ||
| 3046 | closet | ||
| 3047 | closure | ||
| 3048 | clot | ||
| 3049 | cloth | ||
| 3050 | clothe | ||
| 3051 | clothes | ||
| 3052 | clothier | ||
| 3053 | clothing | ||
| 3054 | cloture | ||
| 3055 | cloud | ||
| 3056 | clout | ||
| 3057 | clove | ||
| 3058 | cloven | ||
| 3059 | clover | ||
| 3060 | clown | ||
| 3061 | cloy | ||
| 3062 | club | ||
| 3063 | cluck | ||
| 3064 | clue | ||
| 3065 | clump | ||
| 3066 | clumsy | ||
| 3067 | clung | ||
| 3068 | clunk | ||
| 3069 | cluster | ||
| 3070 | clutch | ||
| 3071 | clutter | ||
| 3072 | coach | ||
| 3073 | coagulate | ||
| 3074 | coal | ||
| 3075 | coalesce | ||
| 3076 | coalition | ||
| 3077 | coaming | ||
| 3078 | coarse | ||
| 3079 | coast | ||
| 3080 | coat | ||
| 3081 | coatee | ||
| 3082 | coax | ||
| 3083 | cob | ||
| 3084 | cobalt | ||
| 3085 | cobber | ||
| 3086 | cobble | ||
| 3087 | cobbler | ||
| 3088 | cobra | ||
| 3089 | cobweb | ||
| 3090 | cocaine | ||
| 3091 | cochineal | ||
| 3092 | cochlea | ||
| 3093 | cock | ||
| 3094 | cockade | ||
| 3095 | cockatoo | ||
| 3096 | cockchafer | ||
| 3097 | cocker | ||
| 3098 | cockerel | ||
| 3099 | cockhorse | ||
| 3100 | cockle | ||
| 3101 | cockney | ||
| 3102 | cockpit | ||
| 3103 | cockroach | ||
| 3104 | cockscomb | ||
| 3105 | cocksure | ||
| 3106 | cocktail | ||
| 3107 | cocky | ||
| 3108 | coco | ||
| 3109 | cocoa | ||
| 3110 | cocoon | ||
| 3111 | cocotte | ||
| 3112 | cod | ||
| 3113 | coda | ||
| 3114 | coddle | ||
| 3115 | code | ||
| 3116 | codeine | ||
| 3117 | codex | ||
| 3118 | codger | ||
| 3119 | codices | ||
| 3120 | codicil | ||
| 3121 | codify | ||
| 3122 | codling | ||
| 3123 | codpiece | ||
| 3124 | coerce | ||
| 3125 | coeval | ||
| 3126 | coexist | ||
| 3127 | coffee | ||
| 3128 | coffer | ||
| 3129 | coffin | ||
| 3130 | cog | ||
| 3131 | cogent | ||
| 3132 | cogitate | ||
| 3133 | cognac | ||
| 3134 | cognate | ||
| 3135 | cognition | ||
| 3136 | cognizance | ||
| 3137 | cognomen | ||
| 3138 | cohabit | ||
| 3139 | cohere | ||
| 3140 | cohesion | ||
| 3141 | cohort | ||
| 3142 | coif | ||
| 3143 | coiffeur | ||
| 3144 | coiffure | ||
| 3145 | coign | ||
| 3146 | coil | ||
| 3147 | coin | ||
| 3148 | coincide | ||
| 3149 | coincidence | ||
| 3150 | coir | ||
| 3151 | coition | ||
| 3152 | coitus | ||
| 3153 | coke | ||
| 3154 | cokernut | ||
| 3155 | col | ||
| 3156 | cola | ||
| 3157 | colander | ||
| 3158 | cold | ||
| 3159 | coleslaw | ||
| 3160 | colic | ||
| 3161 | colitis | ||
| 3162 | collaborate | ||
| 3163 | collage | ||
| 3164 | collapse | ||
| 3165 | collar | ||
| 3166 | collate | ||
| 3167 | collateral | ||
| 3168 | collation | ||
| 3169 | colleague | ||
| 3170 | collect | ||
| 3171 | collection | ||
| 3172 | collective | ||
| 3173 | collector | ||
| 3174 | colleen | ||
| 3175 | college | ||
| 3176 | collide | ||
| 3177 | collie | ||
| 3178 | collier | ||
| 3179 | colliery | ||
| 3180 | collision | ||
| 3181 | collocate | ||
| 3182 | colloquial | ||
| 3183 | colloquy | ||
| 3184 | collusion | ||
| 3185 | collywobbles | ||
| 3186 | colon | ||
| 3187 | colonel | ||
| 3188 | colonial | ||
| 3189 | colonist | ||
| 3190 | colonize | ||
| 3191 | colonnade | ||
| 3192 | colony | ||
| 3193 | color | ||
| 3194 | coloratura | ||
| 3195 | colossal | ||
| 3196 | colossus | ||
| 3197 | colour | ||
| 3198 | colt | ||
| 3199 | colter | ||
| 3200 | columbine | ||
| 3201 | column | ||
| 3202 | coma | ||
| 3203 | comb | ||
| 3204 | combat | ||
| 3205 | combination | ||
| 3206 | combine | ||
| 3207 | combustible | ||
| 3208 | combustion | ||
| 3209 | come | ||
| 3210 | comedian | ||
| 3211 | comedy | ||
| 3212 | comely | ||
| 3213 | comer | ||
| 3214 | comestible | ||
| 3215 | comet | ||
| 3216 | comfit | ||
| 3217 | comfort | ||
| 3218 | comfortable | ||
| 3219 | comfrey | ||
| 3220 | comfy | ||
| 3221 | comic | ||
| 3222 | comical | ||
| 3223 | coming | ||
| 3224 | comity | ||
| 3225 | comma | ||
| 3226 | command | ||
| 3227 | commandant | ||
| 3228 | commandeer | ||
| 3229 | commander | ||
| 3230 | commandment | ||
| 3231 | commando | ||
| 3232 | commemorate | ||
| 3233 | commemoration | ||
| 3234 | commence | ||
| 3235 | commend | ||
| 3236 | commensurable | ||
| 3237 | commensurate | ||
| 3238 | comment | ||
| 3239 | commentary | ||
| 3240 | commerce | ||
| 3241 | commercial | ||
| 3242 | commination | ||
| 3243 | commingle | ||
| 3244 | commiserate | ||
| 3245 | commissar | ||
| 3246 | commissariat | ||
| 3247 | commissary | ||
| 3248 | commission | ||
| 3249 | commissionaire | ||
| 3250 | commissioner | ||
| 3251 | commit | ||
| 3252 | committee | ||
| 3253 | commode | ||
| 3254 | commodious | ||
| 3255 | commodity | ||
| 3256 | commodore | ||
| 3257 | common | ||
| 3258 | commonalty | ||
| 3259 | commoner | ||
| 3260 | commonplace | ||
| 3261 | commons | ||
| 3262 | commonwealth | ||
| 3263 | commotion | ||
| 3264 | communal | ||
| 3265 | commune | ||
| 3266 | communicable | ||
| 3267 | communicant | ||
| 3268 | communicate | ||
| 3269 | communication | ||
| 3270 | communicative | ||
| 3271 | communion | ||
| 3272 | communique | ||
| 3273 | communism | ||
| 3274 | community | ||
| 3275 | commutable | ||
| 3276 | commutation | ||
| 3277 | commutator | ||
| 3278 | commute | ||
| 3279 | compact | ||
| 3280 | companion | ||
| 3281 | company | ||
| 3282 | comparable | ||
| 3283 | comparative | ||
| 3284 | compare | ||
| 3285 | comparison | ||
| 3286 | compartment | ||
| 3287 | compass | ||
| 3288 | compassion | ||
| 3289 | compatible | ||
| 3290 | compatriot | ||
| 3291 | compeer | ||
| 3292 | compel | ||
| 3293 | compendious | ||
| 3294 | compendium | ||
| 3295 | compensate | ||
| 3296 | compensation | ||
| 3297 | compere | ||
| 3298 | compete | ||
| 3299 | competence | ||
| 3300 | competent | ||
| 3301 | competition | ||
| 3302 | competitive | ||
| 3303 | competitor | ||
| 3304 | compile | ||
| 3305 | complacence | ||
| 3306 | complacent | ||
| 3307 | complain | ||
| 3308 | complainant | ||
| 3309 | complaint | ||
| 3310 | complaisance | ||
| 3311 | complement | ||
| 3312 | complete | ||
| 3313 | completion | ||
| 3314 | complex | ||
| 3315 | complexion | ||
| 3316 | compliance | ||
| 3317 | compliant | ||
| 3318 | complicate | ||
| 3319 | complication | ||
| 3320 | complicity | ||
| 3321 | compliment | ||
| 3322 | complimentary | ||
| 3323 | complin | ||
| 3324 | compline | ||
| 3325 | comply | ||
| 3326 | component | ||
| 3327 | comport | ||
| 3328 | compose | ||
| 3329 | composer | ||
| 3330 | composite | ||
| 3331 | composition | ||
| 3332 | compositor | ||
| 3333 | compost | ||
| 3334 | composure | ||
| 3335 | compote | ||
| 3336 | compound | ||
| 3337 | comprehend | ||
| 3338 | comprehensible | ||
| 3339 | comprehension | ||
| 3340 | comprehensive | ||
| 3341 | compress | ||
| 3342 | compression | ||
| 3343 | comprise | ||
| 3344 | compromise | ||
| 3345 | comptroller | ||
| 3346 | compulsion | ||
| 3347 | compulsive | ||
| 3348 | compulsory | ||
| 3349 | compunction | ||
| 3350 | computation | ||
| 3351 | compute | ||
| 3352 | computer | ||
| 3353 | comrade | ||
| 3354 | con | ||
| 3355 | concatenation | ||
| 3356 | concave | ||
| 3357 | conceal | ||
| 3358 | concede | ||
| 3359 | conceit | ||
| 3360 | conceive | ||
| 3361 | concentrate | ||
| 3362 | concentration | ||
| 3363 | concentric | ||
| 3364 | concept | ||
| 3365 | conception | ||
| 3366 | concern | ||
| 3367 | concert | ||
| 3368 | concertina | ||
| 3369 | concerto | ||
| 3370 | concession | ||
| 3371 | conch | ||
| 3372 | concierge | ||
| 3373 | conciliate | ||
| 3374 | conciliation | ||
| 3375 | concise | ||
| 3376 | conclave | ||
| 3377 | conclude | ||
| 3378 | conclusion | ||
| 3379 | conclusive | ||
| 3380 | concoct | ||
| 3381 | concomitant | ||
| 3382 | concord | ||
| 3383 | concordance | ||
| 3384 | concordant | ||
| 3385 | concordat | ||
| 3386 | concourse | ||
| 3387 | concrete | ||
| 3388 | concubine | ||
| 3389 | concupiscence | ||
| 3390 | concur | ||
| 3391 | concurrent | ||
| 3392 | concuss | ||
| 3393 | concussion | ||
| 3394 | condemn | ||
| 3395 | condensation | ||
| 3396 | condense | ||
| 3397 | condenser | ||
| 3398 | condescend | ||
| 3399 | condign | ||
| 3400 | condiment | ||
| 3401 | condition | ||
| 3402 | conditional | ||
| 3403 | condole | ||
| 3404 | condominium | ||
| 3405 | condone | ||
| 3406 | condor | ||
| 3407 | conduce | ||
| 3408 | conduct | ||
| 3409 | conductor | ||
| 3410 | conduit | ||
| 3411 | cone | ||
| 3412 | coney | ||
| 3413 | confab | ||
| 3414 | confabulate | ||
| 3415 | confection | ||
| 3416 | confederacy | ||
| 3417 | confederate | ||
| 3418 | confer | ||
| 3419 | conference | ||
| 3420 | confess | ||
| 3421 | confession | ||
| 3422 | confessional | ||
| 3423 | confessor | ||
| 3424 | confetti | ||
| 3425 | confidant | ||
| 3426 | confide | ||
| 3427 | confidence | ||
| 3428 | confident | ||
| 3429 | confidential | ||
| 3430 | configuration | ||
| 3431 | confine | ||
| 3432 | confines | ||
| 3433 | confirm | ||
| 3434 | confirmation | ||
| 3435 | confiscate | ||
| 3436 | conflagration | ||
| 3437 | conflict | ||
| 3438 | confluence | ||
| 3439 | conform | ||
| 3440 | conformation | ||
| 3441 | conformist | ||
| 3442 | conformity | ||
| 3443 | confound | ||
| 3444 | confrere | ||
| 3445 | confront | ||
| 3446 | confrontation | ||
| 3447 | confucian | ||
| 3448 | confuse | ||
| 3449 | confusion | ||
| 3450 | confute | ||
| 3451 | conge | ||
| 3452 | congeal | ||
| 3453 | congenial | ||
| 3454 | congenital | ||
| 3455 | conger | ||
| 3456 | congested | ||
| 3457 | congestion | ||
| 3458 | conglomerate | ||
| 3459 | conglomeration | ||
| 3460 | congratulate | ||
| 3461 | congratulation | ||
| 3462 | congregate | ||
| 3463 | congregation | ||
| 3464 | congress | ||
| 3465 | congruent | ||
| 3466 | congruous | ||
| 3467 | conic | ||
| 3468 | conifer | ||
| 3469 | conjecture | ||
| 3470 | conjoin | ||
| 3471 | conjugal | ||
| 3472 | conjugate | ||
| 3473 | conjunction | ||
| 3474 | conjunctive | ||
| 3475 | conjuncture | ||
| 3476 | conjuration | ||
| 3477 | conjure | ||
| 3478 | conk | ||
| 3479 | conker | ||
| 3480 | connect | ||
| 3481 | connection | ||
| 3482 | connective | ||
| 3483 | connexion | ||
| 3484 | connive | ||
| 3485 | connoisseur | ||
| 3486 | connote | ||
| 3487 | connubial | ||
| 3488 | conquer | ||
| 3489 | conquest | ||
| 3490 | conquistador | ||
| 3491 | consanguinity | ||
| 3492 | conscience | ||
| 3493 | conscientious | ||
| 3494 | conscious | ||
| 3495 | consciousness | ||
| 3496 | conscript | ||
| 3497 | consecrate | ||
| 3498 | consecration | ||
| 3499 | consecutive | ||
| 3500 | consensus | ||
| 3501 | consent | ||
| 3502 | consequence | ||
| 3503 | consequent | ||
| 3504 | consequential | ||
| 3505 | conservancy | ||
| 3506 | conservation | ||
| 3507 | conservatism | ||
| 3508 | conservative | ||
| 3509 | conservatoire | ||
| 3510 | conservatory | ||
| 3511 | conserve | ||
| 3512 | consider | ||
| 3513 | considerable | ||
| 3514 | considerate | ||
| 3515 | consideration | ||
| 3516 | considering | ||
| 3517 | consign | ||
| 3518 | consist | ||
| 3519 | consistence | ||
| 3520 | consistency | ||
| 3521 | consistent | ||
| 3522 | consistory | ||
| 3523 | consolation | ||
| 3524 | consolatory | ||
| 3525 | console | ||
| 3526 | consolidate | ||
| 3527 | consolidation | ||
| 3528 | consols | ||
| 3529 | consomme | ||
| 3530 | consonance | ||
| 3531 | consonant | ||
| 3532 | consort | ||
| 3533 | consortium | ||
| 3534 | conspectus | ||
| 3535 | conspicuous | ||
| 3536 | conspiracy | ||
| 3537 | conspire | ||
| 3538 | constable | ||
| 3539 | constancy | ||
| 3540 | constant | ||
| 3541 | constellation | ||
| 3542 | consternation | ||
| 3543 | constipate | ||
| 3544 | constipated | ||
| 3545 | constipation | ||
| 3546 | constituency | ||
| 3547 | constituent | ||
| 3548 | constitute | ||
| 3549 | constitution | ||
| 3550 | constitutional | ||
| 3551 | constitutive | ||
| 3552 | constrain | ||
| 3553 | constraint | ||
| 3554 | constrict | ||
| 3555 | construct | ||
| 3556 | construction | ||
| 3557 | constructive | ||
| 3558 | construe | ||
| 3559 | consubstantiation | ||
| 3560 | consul | ||
| 3561 | consular | ||
| 3562 | consulate | ||
| 3563 | consult | ||
| 3564 | consultant | ||
| 3565 | consultation | ||
| 3566 | consultative | ||
| 3567 | consume | ||
| 3568 | consumer | ||
| 3569 | consummate | ||
| 3570 | consummation | ||
| 3571 | consumption | ||
| 3572 | consumptive | ||
| 3573 | contact | ||
| 3574 | contagion | ||
| 3575 | contagious | ||
| 3576 | contain | ||
| 3577 | contaminate | ||
| 3578 | contamination | ||
| 3579 | contemn | ||
| 3580 | contemplate | ||
| 3581 | contemplation | ||
| 3582 | contemplative | ||
| 3583 | contemporaneous | ||
| 3584 | contemporary | ||
| 3585 | contempt | ||
| 3586 | contemptible | ||
| 3587 | contemptuous | ||
| 3588 | contend | ||
| 3589 | content | ||
| 3590 | contention | ||
| 3591 | contentious | ||
| 3592 | conterminous | ||
| 3593 | contest | ||
| 3594 | context | ||
| 3595 | contiguity | ||
| 3596 | contiguous | ||
| 3597 | continence | ||
| 3598 | continent | ||
| 3599 | contingency | ||
| 3600 | contingent | ||
| 3601 | continual | ||
| 3602 | continuance | ||
| 3603 | continuation | ||
| 3604 | continue | ||
| 3605 | continuity | ||
| 3606 | continuous | ||
| 3607 | contort | ||
| 3608 | contortion | ||
| 3609 | contour | ||
| 3610 | contraband | ||
| 3611 | contrabass | ||
| 3612 | contraception | ||
| 3613 | contract | ||
| 3614 | contraction | ||
| 3615 | contradict | ||
| 3616 | contradistinction | ||
| 3617 | contradistinguish | ||
| 3618 | contralto | ||
| 3619 | contraption | ||
| 3620 | contrapuntal | ||
| 3621 | contrariety | ||
| 3622 | contrariwise | ||
| 3623 | contrary | ||
| 3624 | contrast | ||
| 3625 | contravene | ||
| 3626 | contravention | ||
| 3627 | contretemps | ||
| 3628 | contribute | ||
| 3629 | contribution | ||
| 3630 | contributory | ||
| 3631 | contrite | ||
| 3632 | contrition | ||
| 3633 | contrivance | ||
| 3634 | contrive | ||
| 3635 | control | ||
| 3636 | controller | ||
| 3637 | controversial | ||
| 3638 | controversy | ||
| 3639 | controvert | ||
| 3640 | contumacious | ||
| 3641 | contumacy | ||
| 3642 | contumelious | ||
| 3643 | contumely | ||
| 3644 | contuse | ||
| 3645 | conundrum | ||
| 3646 | conurbation | ||
| 3647 | convalesce | ||
| 3648 | convection | ||
| 3649 | convector | ||
| 3650 | convene | ||
| 3651 | convenience | ||
| 3652 | convenient | ||
| 3653 | convent | ||
| 3654 | conventicle | ||
| 3655 | convention | ||
| 3656 | conventional | ||
| 3657 | conventionality | ||
| 3658 | converge | ||
| 3659 | conversant | ||
| 3660 | conversation | ||
| 3661 | converse | ||
| 3662 | conversion | ||
| 3663 | convert | ||
| 3664 | convertible | ||
| 3665 | convex | ||
| 3666 | convey | ||
| 3667 | conveyance | ||
| 3668 | convict | ||
| 3669 | conviction | ||
| 3670 | convince | ||
| 3671 | convivial | ||
| 3672 | convocation | ||
| 3673 | convoke | ||
| 3674 | convoluted | ||
| 3675 | convolution | ||
| 3676 | convolvulus | ||
| 3677 | convoy | ||
| 3678 | convulse | ||
| 3679 | convulsion | ||
| 3680 | convulsive | ||
| 3681 | cony | ||
| 3682 | coo | ||
| 3683 | cook | ||
| 3684 | cooker | ||
| 3685 | cookery | ||
| 3686 | cookie | ||
| 3687 | cooky | ||
| 3688 | cool | ||
| 3689 | coolant | ||
| 3690 | cooler | ||
| 3691 | coolie | ||
| 3692 | coon | ||
| 3693 | coop | ||
| 3694 | cooper | ||
| 3695 | coot | ||
| 3696 | cop | ||
| 3697 | cope | ||
| 3698 | copeck | ||
| 3699 | copernican | ||
| 3700 | coping | ||
| 3701 | copious | ||
| 3702 | copper | ||
| 3703 | coppice | ||
| 3704 | copra | ||
| 3705 | copse | ||
| 3706 | copt | ||
| 3707 | copula | ||
| 3708 | copulate | ||
| 3709 | copy | ||
| 3710 | copyhold | ||
| 3711 | copyright | ||
| 3712 | coquetry | ||
| 3713 | coquette | ||
| 3714 | coracle | ||
| 3715 | coral | ||
| 3716 | corbel | ||
| 3717 | cord | ||
| 3718 | cordage | ||
| 3719 | cordial | ||
| 3720 | cordite | ||
| 3721 | cordon | ||
| 3722 | cords | ||
| 3723 | corduroy | ||
| 3724 | core | ||
| 3725 | corgi | ||
| 3726 | corinthian | ||
| 3727 | cork | ||
| 3728 | corkage | ||
| 3729 | corker | ||
| 3730 | corm | ||
| 3731 | cormorant | ||
| 3732 | corn | ||
| 3733 | cornea | ||
| 3734 | cornelian | ||
| 3735 | corner | ||
| 3736 | cornet | ||
| 3737 | cornice | ||
| 3738 | cornucopia | ||
| 3739 | corny | ||
| 3740 | corolla | ||
| 3741 | corollary | ||
| 3742 | corona | ||
| 3743 | coronary | ||
| 3744 | coronation | ||
| 3745 | coroner | ||
| 3746 | coronet | ||
| 3747 | corporal | ||
| 3748 | corporate | ||
| 3749 | corporation | ||
| 3750 | corporeal | ||
| 3751 | corps | ||
| 3752 | corpse | ||
| 3753 | corpulent | ||
| 3754 | corpus | ||
| 3755 | corpuscle | ||
| 3756 | corral | ||
| 3757 | correct | ||
| 3758 | correction | ||
| 3759 | correctitude | ||
| 3760 | corrective | ||
| 3761 | correlate | ||
| 3762 | correlation | ||
| 3763 | correlative | ||
| 3764 | correspond | ||
| 3765 | correspondence | ||
| 3766 | correspondent | ||
| 3767 | corridor | ||
| 3768 | corrie | ||
| 3769 | corrigendum | ||
| 3770 | corrigible | ||
| 3771 | corroborate | ||
| 3772 | corroboration | ||
| 3773 | corrode | ||
| 3774 | corrosive | ||
| 3775 | corrugate | ||
| 3776 | corrupt | ||
| 3777 | corruption | ||
| 3778 | corsage | ||
| 3779 | corsair | ||
| 3780 | corse | ||
| 3781 | corselet | ||
| 3782 | corset | ||
| 3783 | corslet | ||
| 3784 | cortege | ||
| 3785 | cortex | ||
| 3786 | cortisone | ||
| 3787 | corundum | ||
| 3788 | coruscate | ||
| 3789 | corvee | ||
| 3790 | corvette | ||
| 3791 | cos | ||
| 3792 | cosh | ||
| 3793 | cosher | ||
| 3794 | cosine | ||
| 3795 | cosmetic | ||
| 3796 | cosmic | ||
| 3797 | cosmogony | ||
| 3798 | cosmonaut | ||
| 3799 | cosmopolitan | ||
| 3800 | cosmos | ||
| 3801 | cosset | ||
| 3802 | cost | ||
| 3803 | costermonger | ||
| 3804 | costive | ||
| 3805 | costly | ||
| 3806 | costume | ||
| 3807 | cosy | ||
| 3808 | cot | ||
| 3809 | cote | ||
| 3810 | coterie | ||
| 3811 | coterminous | ||
| 3812 | cotilion | ||
| 3813 | cotillion | ||
| 3814 | cottage | ||
| 3815 | cottar | ||
| 3816 | cotter | ||
| 3817 | cotton | ||
| 3818 | cotyledon | ||
| 3819 | couch | ||
| 3820 | couchant | ||
| 3821 | couchette | ||
| 3822 | cougar | ||
| 3823 | cough | ||
| 3824 | could | ||
| 3825 | couldst | ||
| 3826 | coulter | ||
| 3827 | council | ||
| 3828 | councillor | ||
| 3829 | counsel | ||
| 3830 | counsellor | ||
| 3831 | count | ||
| 3832 | countenance | ||
| 3833 | counter | ||
| 3834 | counteract | ||
| 3835 | counterbalance | ||
| 3836 | counterblast | ||
| 3837 | counterclaim | ||
| 3838 | counterfeit | ||
| 3839 | counterfoil | ||
| 3840 | countermand | ||
| 3841 | countermine | ||
| 3842 | counteroffer | ||
| 3843 | counterpane | ||
| 3844 | counterpart | ||
| 3845 | counterplot | ||
| 3846 | counterpoint | ||
| 3847 | counterpoise | ||
| 3848 | countersign | ||
| 3849 | countersink | ||
| 3850 | countertenor | ||
| 3851 | countervail | ||
| 3852 | countess | ||
| 3853 | countless | ||
| 3854 | countrified | ||
| 3855 | country | ||
| 3856 | countryman | ||
| 3857 | countryside | ||
| 3858 | county | ||
| 3859 | coup | ||
| 3860 | coupe | ||
| 3861 | couple | ||
| 3862 | couplet | ||
| 3863 | coupling | ||
| 3864 | coupon | ||
| 3865 | courage | ||
| 3866 | courageous | ||
| 3867 | courgette | ||
| 3868 | courier | ||
| 3869 | course | ||
| 3870 | courser | ||
| 3871 | court | ||
| 3872 | courteous | ||
| 3873 | courtesan | ||
| 3874 | courtesy | ||
| 3875 | courtier | ||
| 3876 | courtly | ||
| 3877 | courtship | ||
| 3878 | courtyard | ||
| 3879 | cousin | ||
| 3880 | cove | ||
| 3881 | coven | ||
| 3882 | covenant | ||
| 3883 | coventry | ||
| 3884 | cover | ||
| 3885 | coverage | ||
| 3886 | coverlet | ||
| 3887 | covert | ||
| 3888 | covet | ||
| 3889 | covetous | ||
| 3890 | covey | ||
| 3891 | cow | ||
| 3892 | coward | ||
| 3893 | cowardice | ||
| 3894 | cower | ||
| 3895 | cowl | ||
| 3896 | cowpox | ||
| 3897 | cowrie | ||
| 3898 | cowslip | ||
| 3899 | cox | ||
| 3900 | coxcomb | ||
| 3901 | coxswain | ||
| 3902 | coy | ||
| 3903 | coyote | ||
| 3904 | coypu | ||
| 3905 | cozen | ||
| 3906 | cozy | ||
| 3907 | crab | ||
| 3908 | crabbed | ||
| 3909 | crack | ||
| 3910 | cracker | ||
| 3911 | crackers | ||
| 3912 | crackle | ||
| 3913 | crackling | ||
| 3914 | crackpot | ||
| 3915 | cracksman | ||
| 3916 | cradle | ||
| 3917 | craft | ||
| 3918 | craftsman | ||
| 3919 | crag | ||
| 3920 | crake | ||
| 3921 | cram | ||
| 3922 | cramp | ||
| 3923 | crampon | ||
| 3924 | cranberry | ||
| 3925 | crane | ||
| 3926 | cranial | ||
| 3927 | cranium | ||
| 3928 | crank | ||
| 3929 | cranny | ||
| 3930 | crap | ||
| 3931 | crape | ||
| 3932 | craps | ||
| 3933 | crash | ||
| 3934 | crass | ||
| 3935 | crate | ||
| 3936 | crater | ||
| 3937 | cravat | ||
| 3938 | crave | ||
| 3939 | craven | ||
| 3940 | crawfish | ||
| 3941 | crawl | ||
| 3942 | crayfish | ||
| 3943 | crayon | ||
| 3944 | craze | ||
| 3945 | crazed | ||
| 3946 | crazy | ||
| 3947 | creak | ||
| 3948 | cream | ||
| 3949 | crease | ||
| 3950 | create | ||
| 3951 | creation | ||
| 3952 | creative | ||
| 3953 | creator | ||
| 3954 | creature | ||
| 3955 | creche | ||
| 3956 | credence | ||
| 3957 | credentials | ||
| 3958 | credible | ||
| 3959 | credit | ||
| 3960 | creditable | ||
| 3961 | creditor | ||
| 3962 | credo | ||
| 3963 | credulity | ||
| 3964 | credulous | ||
| 3965 | creed | ||
| 3966 | creek | ||
| 3967 | creel | ||
| 3968 | creep | ||
| 3969 | creeper | ||
| 3970 | creepy | ||
| 3971 | cremate | ||
| 3972 | crenellated | ||
| 3973 | creole | ||
| 3974 | creosote | ||
| 3975 | crepe | ||
| 3976 | crepitate | ||
| 3977 | crept | ||
| 3978 | crepuscular | ||
| 3979 | crescendo | ||
| 3980 | crescent | ||
| 3981 | cress | ||
| 3982 | crest | ||
| 3983 | cretacious | ||
| 3984 | cretin | ||
| 3985 | cretonne | ||
| 3986 | crevasse | ||
| 3987 | crevice | ||
| 3988 | crew | ||
| 3989 | crib | ||
| 3990 | cribbage | ||
| 3991 | crick | ||
| 3992 | cricket | ||
| 3993 | cried | ||
| 3994 | crier | ||
| 3995 | cries | ||
| 3996 | crikey | ||
| 3997 | crime | ||
| 3998 | criminal | ||
| 3999 | criminology | ||
| 4000 | crimp | ||
| 4001 | crimson | ||
| 4002 | cringe | ||
| 4003 | crinkle | ||
| 4004 | crinoline | ||
| 4005 | cripes | ||
| 4006 | cripple | ||
| 4007 | crisis | ||
| 4008 | crisp | ||
| 4009 | crisscross | ||
| 4010 | criterion | ||
| 4011 | critic | ||
| 4012 | critical | ||
| 4013 | criticism | ||
| 4014 | criticize | ||
| 4015 | critique | ||
| 4016 | croak | ||
| 4017 | crochet | ||
| 4018 | crock | ||
| 4019 | crockery | ||
| 4020 | crocodile | ||
| 4021 | crocus | ||
| 4022 | croesus | ||
| 4023 | croft | ||
| 4024 | cromlech | ||
| 4025 | crone | ||
| 4026 | crony | ||
| 4027 | crook | ||
| 4028 | crooked | ||
| 4029 | croon | ||
| 4030 | crop | ||
| 4031 | cropper | ||
| 4032 | croquet | ||
| 4033 | croquette | ||
| 4034 | crore | ||
| 4035 | crosier | ||
| 4036 | cross | ||
| 4037 | crossbar | ||
| 4038 | crossbeam | ||
| 4039 | crossbenches | ||
| 4040 | crossbones | ||
| 4041 | crossbow | ||
| 4042 | crossbred | ||
| 4043 | crossbreed | ||
| 4044 | crosscountry | ||
| 4045 | crosscut | ||
| 4046 | crosse | ||
| 4047 | crosseyed | ||
| 4048 | crossfire | ||
| 4049 | crossing | ||
| 4050 | crosskeys | ||
| 4051 | crosspatch | ||
| 4052 | crossroad | ||
| 4053 | crosstrees | ||
| 4054 | crosswalk | ||
| 4055 | crosswind | ||
| 4056 | crossword | ||
| 4057 | crotch | ||
| 4058 | crotchet | ||
| 4059 | crouch | ||
| 4060 | croup | ||
| 4061 | croupier | ||
| 4062 | crow | ||
| 4063 | crowbar | ||
| 4064 | crowd | ||
| 4065 | crown | ||
| 4066 | crozier | ||
| 4067 | crucial | ||
| 4068 | crucible | ||
| 4069 | crucifix | ||
| 4070 | crucifixion | ||
| 4071 | cruciform | ||
| 4072 | crucify | ||
| 4073 | crude | ||
| 4074 | crudity | ||
| 4075 | cruel | ||
| 4076 | cruelty | ||
| 4077 | cruet | ||
| 4078 | cruise | ||
| 4079 | crumb | ||
| 4080 | crumble | ||
| 4081 | crumbly | ||
| 4082 | crumpet | ||
| 4083 | crumple | ||
| 4084 | crunch | ||
| 4085 | crupper | ||
| 4086 | crusade | ||
| 4087 | cruse | ||
| 4088 | crush | ||
| 4089 | crust | ||
| 4090 | crustacean | ||
| 4091 | crusted | ||
| 4092 | crusty | ||
| 4093 | crutch | ||
| 4094 | crux | ||
| 4095 | cry | ||
| 4096 | crying | ||
| 4097 | crypt | ||
| 4098 | cryptic | ||
| 4099 | cryptogram | ||
| 4100 | crystal | ||
| 4101 | crystalline | ||
| 4102 | crystallize | ||
| 4103 | cub | ||
| 4104 | cube | ||
| 4105 | cubic | ||
| 4106 | cubical | ||
| 4107 | cubicle | ||
| 4108 | cubism | ||
| 4109 | cubit | ||
| 4110 | cuckold | ||
| 4111 | cuckoo | ||
| 4112 | cucumber | ||
| 4113 | cud | ||
| 4114 | cuddle | ||
| 4115 | cudgel | ||
| 4116 | cue | ||
| 4117 | cuff | ||
| 4118 | cuirass | ||
| 4119 | cuisine | ||
| 4120 | culinary | ||
| 4121 | cull | ||
| 4122 | cullender | ||
| 4123 | culminate | ||
| 4124 | culpable | ||
| 4125 | culprit | ||
| 4126 | cult | ||
| 4127 | cultivable | ||
| 4128 | cultivate | ||
| 4129 | cultivation | ||
| 4130 | cultivator | ||
| 4131 | cultural | ||
| 4132 | culture | ||
| 4133 | culvert | ||
| 4134 | cumber | ||
| 4135 | cumbersome | ||
| 4136 | cumbrous | ||
| 4137 | cummerbund | ||
| 4138 | cumulative | ||
| 4139 | cumulus | ||
| 4140 | cuneiform | ||
| 4141 | cunning | ||
| 4142 | cunt | ||
| 4143 | cup | ||
| 4144 | cupboard | ||
| 4145 | cupid | ||
| 4146 | cupidity | ||
| 4147 | cupola | ||
| 4148 | cuppa | ||
| 4149 | cupping | ||
| 4150 | cupric | ||
| 4151 | cur | ||
| 4152 | curable | ||
| 4153 | curacao | ||
| 4154 | curacy | ||
| 4155 | curate | ||
| 4156 | curative | ||
| 4157 | curator | ||
| 4158 | curb | ||
| 4159 | curd | ||
| 4160 | curdle | ||
| 4161 | cure | ||
| 4162 | curfew | ||
| 4163 | curio | ||
| 4164 | curiosity | ||
| 4165 | curious | ||
| 4166 | curl | ||
| 4167 | curlew | ||
| 4168 | curling | ||
| 4169 | curly | ||
| 4170 | curmudgeon | ||
| 4171 | currant | ||
| 4172 | currency | ||
| 4173 | current | ||
| 4174 | curriculum | ||
| 4175 | currish | ||
| 4176 | curry | ||
| 4177 | curse | ||
| 4178 | cursed | ||
| 4179 | cursive | ||
| 4180 | cursory | ||
| 4181 | curst | ||
| 4182 | curt | ||
| 4183 | curtail | ||
| 4184 | curtain | ||
| 4185 | curtsey | ||
| 4186 | curtsy | ||
| 4187 | curvature | ||
| 4188 | curve | ||
| 4189 | cushion | ||
| 4190 | cushy | ||
| 4191 | cusp | ||
| 4192 | cuspidor | ||
| 4193 | cuss | ||
| 4194 | cussed | ||
| 4195 | custard | ||
| 4196 | custodian | ||
| 4197 | custody | ||
| 4198 | custom | ||
| 4199 | customary | ||
| 4200 | customer | ||
| 4201 | cut | ||
| 4202 | cute | ||
| 4203 | cuticle | ||
| 4204 | cutlass | ||
| 4205 | cutler | ||
| 4206 | cutlet | ||
| 4207 | cutpurse | ||
| 4208 | cutter | ||
| 4209 | cutting | ||
| 4210 | cuttlefish | ||
| 4211 | cutworm | ||
| 4212 | cyanide | ||
| 4213 | cybernetics | ||
| 4214 | cyclamen | ||
| 4215 | cycle | ||
| 4216 | cyclic | ||
| 4217 | cyclical | ||
| 4218 | cyclist | ||
| 4219 | cyclone | ||
| 4220 | cyclopaedia | ||
| 4221 | cyclopean | ||
| 4222 | cyclostyle | ||
| 4223 | cyclotron | ||
| 4224 | cyder | ||
| 4225 | cygnet | ||
| 4226 | cylinder | ||
| 4227 | cymbal | ||
| 4228 | cynic | ||
| 4229 | cynical | ||
| 4230 | cynosure | ||
| 4231 | cypher | ||
| 4232 | cypress | ||
| 4233 | cyrillic | ||
| 4234 | cyst | ||
| 4235 | czar | ||
| 4236 | czech | ||
| 4237 | d | ||
| 4238 | dab | ||
| 4239 | dabble | ||
| 4240 | dace | ||
| 4241 | dacha | ||
| 4242 | dachshund | ||
| 4243 | dacoit | ||
| 4244 | dactyl | ||
| 4245 | dad | ||
| 4246 | daddy | ||
| 4247 | dado | ||
| 4248 | daemon | ||
| 4249 | daffodil | ||
| 4250 | daft | ||
| 4251 | dagger | ||
| 4252 | dago | ||
| 4253 | daguerreotype | ||
| 4254 | dahlia | ||
| 4255 | daily | ||
| 4256 | dainty | ||
| 4257 | dairy | ||
| 4258 | dais | ||
| 4259 | daisy | ||
| 4260 | dale | ||
| 4261 | dalliance | ||
| 4262 | dally | ||
| 4263 | dalmation | ||
| 4264 | dam | ||
| 4265 | damage | ||
| 4266 | damascene | ||
| 4267 | damask | ||
| 4268 | dame | ||
| 4269 | damn | ||
| 4270 | damnable | ||
| 4271 | damnation | ||
| 4272 | damned | ||
| 4273 | damocles | ||
| 4274 | damp | ||
| 4275 | dampen | ||
| 4276 | damper | ||
| 4277 | damsel | ||
| 4278 | damson | ||
| 4279 | dance | ||
| 4280 | dandelion | ||
| 4281 | dander | ||
| 4282 | dandle | ||
| 4283 | dandruff | ||
| 4284 | dandy | ||
| 4285 | dane | ||
| 4286 | danger | ||
| 4287 | dangerous | ||
| 4288 | dangle | ||
| 4289 | daniel | ||
| 4290 | danish | ||
| 4291 | dank | ||
| 4292 | daphne | ||
| 4293 | dapper | ||
| 4294 | dapple | ||
| 4295 | dare | ||
| 4296 | daring | ||
| 4297 | dark | ||
| 4298 | darken | ||
| 4299 | darkey | ||
| 4300 | darkie | ||
| 4301 | darky | ||
| 4302 | darling | ||
| 4303 | darn | ||
| 4304 | dart | ||
| 4305 | dash | ||
| 4306 | dastard | ||
| 4307 | data | ||
| 4308 | date | ||
| 4309 | dative | ||
| 4310 | datum | ||
| 4311 | daub | ||
| 4312 | daughter | ||
| 4313 | daunt | ||
| 4314 | dauntless | ||
| 4315 | dauphin | ||
| 4316 | davenport | ||
| 4317 | davit | ||
| 4318 | daw | ||
| 4319 | dawdle | ||
| 4320 | dawn | ||
| 4321 | day | ||
| 4322 | daylight | ||
| 4323 | daze | ||
| 4324 | dazzle | ||
| 4325 | deacon | ||
| 4326 | dead | ||
| 4327 | deaden | ||
| 4328 | deadlock | ||
| 4329 | deadly | ||
| 4330 | deaf | ||
| 4331 | deafen | ||
| 4332 | deal | ||
| 4333 | dealer | ||
| 4334 | dealing | ||
| 4335 | dealt | ||
| 4336 | dean | ||
| 4337 | dear | ||
| 4338 | dearie | ||
| 4339 | dearth | ||
| 4340 | deary | ||
| 4341 | death | ||
| 4342 | deathless | ||
| 4343 | deathlike | ||
| 4344 | deathly | ||
| 4345 | deb | ||
| 4346 | debacle | ||
| 4347 | debag | ||
| 4348 | debar | ||
| 4349 | debark | ||
| 4350 | debase | ||
| 4351 | debatable | ||
| 4352 | debate | ||
| 4353 | debauch | ||
| 4354 | debenture | ||
| 4355 | debilitate | ||
| 4356 | debility | ||
| 4357 | debit | ||
| 4358 | debonair | ||
| 4359 | debouch | ||
| 4360 | debrief | ||
| 4361 | debris | ||
| 4362 | debt | ||
| 4363 | debug | ||
| 4364 | debunk | ||
| 4365 | debut | ||
| 4366 | debutante | ||
| 4367 | decade | ||
| 4368 | decadence | ||
| 4369 | decadent | ||
| 4370 | decalogue | ||
| 4371 | decamp | ||
| 4372 | decant | ||
| 4373 | decapitate | ||
| 4374 | decarbonize | ||
| 4375 | decasyllable | ||
| 4376 | decay | ||
| 4377 | decease | ||
| 4378 | deceit | ||
| 4379 | deceitful | ||
| 4380 | deceive | ||
| 4381 | decelerate | ||
| 4382 | december | ||
| 4383 | decency | ||
| 4384 | decent | ||
| 4385 | decentralize | ||
| 4386 | deception | ||
| 4387 | deceptive | ||
| 4388 | decibel | ||
| 4389 | decide | ||
| 4390 | deciduous | ||
| 4391 | decimal | ||
| 4392 | decimate | ||
| 4393 | decipher | ||
| 4394 | decision | ||
| 4395 | decisive | ||
| 4396 | deck | ||
| 4397 | declaim | ||
| 4398 | declamation | ||
| 4399 | declaration | ||
| 4400 | declare | ||
| 4401 | declassify | ||
| 4402 | declension | ||
| 4403 | declination | ||
| 4404 | decline | ||
| 4405 | declivity | ||
| 4406 | declutch | ||
| 4407 | decode | ||
| 4408 | decoke | ||
| 4409 | decollete | ||
| 4410 | decolonize | ||
| 4411 | decompose | ||
| 4412 | decompress | ||
| 4413 | decontaminate | ||
| 4414 | decontrol | ||
| 4415 | decor | ||
| 4416 | decorate | ||
| 4417 | decoration | ||
| 4418 | decorative | ||
| 4419 | decorous | ||
| 4420 | decorum | ||
| 4421 | decoy | ||
| 4422 | decrease | ||
| 4423 | decree | ||
| 4424 | decrepit | ||
| 4425 | decry | ||
| 4426 | dedicate | ||
| 4427 | deduce | ||
| 4428 | deduct | ||
| 4429 | deduction | ||
| 4430 | deed | ||
| 4431 | deem | ||
| 4432 | deep | ||
| 4433 | deer | ||
| 4434 | deface | ||
| 4435 | defalcation | ||
| 4436 | defame | ||
| 4437 | default | ||
| 4438 | defeat | ||
| 4439 | defecate | ||
| 4440 | defect | ||
| 4441 | defection | ||
| 4442 | defective | ||
| 4443 | defence | ||
| 4444 | defend | ||
| 4445 | defendant | ||
| 4446 | defense | ||
| 4447 | defensible | ||
| 4448 | defensive | ||
| 4449 | defer | ||
| 4450 | deference | ||
| 4451 | defiance | ||
| 4452 | defiant | ||
| 4453 | deficiency | ||
| 4454 | deficient | ||
| 4455 | deficit | ||
| 4456 | defile | ||
| 4457 | define | ||
| 4458 | definite | ||
| 4459 | definition | ||
| 4460 | definitive | ||
| 4461 | deflate | ||
| 4462 | deflect | ||
| 4463 | deflower | ||
| 4464 | defoliate | ||
| 4465 | deforest | ||
| 4466 | deform | ||
| 4467 | deformity | ||
| 4468 | defraud | ||
| 4469 | defray | ||
| 4470 | defrock | ||
| 4471 | defrost | ||
| 4472 | deft | ||
| 4473 | defunct | ||
| 4474 | defuse | ||
| 4475 | defy | ||
| 4476 | degauss | ||
| 4477 | degenerate | ||
| 4478 | degrade | ||
| 4479 | degree | ||
| 4480 | dehumanize | ||
| 4481 | dehydrate | ||
| 4482 | deify | ||
| 4483 | deign | ||
| 4484 | deism | ||
| 4485 | deity | ||
| 4486 | deject | ||
| 4487 | dekko | ||
| 4488 | delay | ||
| 4489 | delectable | ||
| 4490 | delectation | ||
| 4491 | delegacy | ||
| 4492 | delegate | ||
| 4493 | delegation | ||
| 4494 | delete | ||
| 4495 | deleterious | ||
| 4496 | delft | ||
| 4497 | deliberate | ||
| 4498 | deliberation | ||
| 4499 | delicacy | ||
| 4500 | delicate | ||
| 4501 | delicatessen | ||
| 4502 | delicious | ||
| 4503 | delight | ||
| 4504 | delimit | ||
| 4505 | delineate | ||
| 4506 | delinquency | ||
| 4507 | delinquent | ||
| 4508 | deliquescent | ||
| 4509 | delirious | ||
| 4510 | delirium | ||
| 4511 | deliver | ||
| 4512 | deliverance | ||
| 4513 | delivery | ||
| 4514 | dell | ||
| 4515 | delouse | ||
| 4516 | delphic | ||
| 4517 | delphinium | ||
| 4518 | delta | ||
| 4519 | delude | ||
| 4520 | deluge | ||
| 4521 | delusion | ||
| 4522 | delusive | ||
| 4523 | delve | ||
| 4524 | demagnetize | ||
| 4525 | demagogue | ||
| 4526 | demand | ||
| 4527 | demarcate | ||
| 4528 | demarcation | ||
| 4529 | demarche | ||
| 4530 | demean | ||
| 4531 | demeanour | ||
| 4532 | demented | ||
| 4533 | demerara | ||
| 4534 | demerit | ||
| 4535 | demesne | ||
| 4536 | demigod | ||
| 4537 | demijohn | ||
| 4538 | demilitarize | ||
| 4539 | demimonde | ||
| 4540 | demise | ||
| 4541 | demist | ||
| 4542 | demo | ||
| 4543 | demob | ||
| 4544 | demobilize | ||
| 4545 | democracy | ||
| 4546 | democrat | ||
| 4547 | democratic | ||
| 4548 | democratize | ||
| 4549 | demode | ||
| 4550 | demography | ||
| 4551 | demolish | ||
| 4552 | demon | ||
| 4553 | demonetize | ||
| 4554 | demoniac | ||
| 4555 | demonstrable | ||
| 4556 | demonstrate | ||
| 4557 | demonstration | ||
| 4558 | demonstrative | ||
| 4559 | demonstrator | ||
| 4560 | demoralize | ||
| 4561 | demote | ||
| 4562 | demotic | ||
| 4563 | demur | ||
| 4564 | demure | ||
| 4565 | den | ||
| 4566 | denary | ||
| 4567 | denationalize | ||
| 4568 | denatured | ||
| 4569 | deniable | ||
| 4570 | denial | ||
| 4571 | denier | ||
| 4572 | denigrate | ||
| 4573 | denim | ||
| 4574 | denizen | ||
| 4575 | denominate | ||
| 4576 | denomination | ||
| 4577 | denominator | ||
| 4578 | denote | ||
| 4579 | denouement | ||
| 4580 | denounce | ||
| 4581 | dense | ||
| 4582 | density | ||
| 4583 | dent | ||
| 4584 | dental | ||
| 4585 | dentifrice | ||
| 4586 | dentist | ||
| 4587 | denture | ||
| 4588 | denude | ||
| 4589 | denunciation | ||
| 4590 | deny | ||
| 4591 | deodar | ||
| 4592 | deodorant | ||
| 4593 | deodorize | ||
| 4594 | depart | ||
| 4595 | department | ||
| 4596 | departure | ||
| 4597 | depend | ||
| 4598 | dependant | ||
| 4599 | dependence | ||
| 4600 | dependency | ||
| 4601 | dependent | ||
| 4602 | depict | ||
| 4603 | depilatory | ||
| 4604 | deplane | ||
| 4605 | deplete | ||
| 4606 | deplore | ||
| 4607 | deploy | ||
| 4608 | deponent | ||
| 4609 | depopulate | ||
| 4610 | deport | ||
| 4611 | depose | ||
| 4612 | deposit | ||
| 4613 | deposition | ||
| 4614 | depositor | ||
| 4615 | depository | ||
| 4616 | depot | ||
| 4617 | deprave | ||
| 4618 | depravity | ||
| 4619 | deprecate | ||
| 4620 | depreciate | ||
| 4621 | depredation | ||
| 4622 | depress | ||
| 4623 | depression | ||
| 4624 | depressive | ||
| 4625 | deprive | ||
| 4626 | depth | ||
| 4627 | deputation | ||
| 4628 | depute | ||
| 4629 | deputize | ||
| 4630 | deputy | ||
| 4631 | derail | ||
| 4632 | derange | ||
| 4633 | derate | ||
| 4634 | derby | ||
| 4635 | derelict | ||
| 4636 | derequisition | ||
| 4637 | derestrict | ||
| 4638 | deride | ||
| 4639 | derision | ||
| 4640 | derisive | ||
| 4641 | derisory | ||
| 4642 | derivation | ||
| 4643 | derivative | ||
| 4644 | derive | ||
| 4645 | dermatology | ||
| 4646 | derogate | ||
| 4647 | derogatory | ||
| 4648 | derrick | ||
| 4649 | derv | ||
| 4650 | dervish | ||
| 4651 | desalinate | ||
| 4652 | desalinize | ||
| 4653 | desalt | ||
| 4654 | descale | ||
| 4655 | descant | ||
| 4656 | descend | ||
| 4657 | descent | ||
| 4658 | describe | ||
| 4659 | description | ||
| 4660 | descriptive | ||
| 4661 | descry | ||
| 4662 | desecrate | ||
| 4663 | desegregate | ||
| 4664 | desensitize | ||
| 4665 | desert | ||
| 4666 | deserts | ||
| 4667 | deserve | ||
| 4668 | deserving | ||
| 4669 | deshabille | ||
| 4670 | desiccant | ||
| 4671 | desiccate | ||
| 4672 | desideratum | ||
| 4673 | design | ||
| 4674 | designate | ||
| 4675 | designation | ||
| 4676 | designer | ||
| 4677 | designing | ||
| 4678 | desirable | ||
| 4679 | desire | ||
| 4680 | desirous | ||
| 4681 | desist | ||
| 4682 | desk | ||
| 4683 | desolate | ||
| 4684 | despair | ||
| 4685 | despatch | ||
| 4686 | desperado | ||
| 4687 | desperate | ||
| 4688 | despicable | ||
| 4689 | despise | ||
| 4690 | despite | ||
| 4691 | despoil | ||
| 4692 | despondency | ||
| 4693 | despot | ||
| 4694 | dessert | ||
| 4695 | destination | ||
| 4696 | destine | ||
| 4697 | destiny | ||
| 4698 | destitute | ||
| 4699 | destroy | ||
| 4700 | destructible | ||
| 4701 | destruction | ||
| 4702 | destructive | ||
| 4703 | desuetude | ||
| 4704 | desultory | ||
| 4705 | detach | ||
| 4706 | detachment | ||
| 4707 | detail | ||
| 4708 | detain | ||
| 4709 | detect | ||
| 4710 | detection | ||
| 4711 | detective | ||
| 4712 | detente | ||
| 4713 | detention | ||
| 4714 | deter | ||
| 4715 | detergent | ||
| 4716 | deteriorate | ||
| 4717 | determinant | ||
| 4718 | determinate | ||
| 4719 | determination | ||
| 4720 | determinative | ||
| 4721 | determine | ||
| 4722 | determiner | ||
| 4723 | deterrent | ||
| 4724 | detest | ||
| 4725 | dethrone | ||
| 4726 | detonate | ||
| 4727 | detour | ||
| 4728 | detract | ||
| 4729 | detrain | ||
| 4730 | detribalize | ||
| 4731 | detriment | ||
| 4732 | detritus | ||
| 4733 | deuce | ||
| 4734 | devalue | ||
| 4735 | devastate | ||
| 4736 | develop | ||
| 4737 | development | ||
| 4738 | deviant | ||
| 4739 | deviate | ||
| 4740 | deviation | ||
| 4741 | device | ||
| 4742 | devil | ||
| 4743 | devilish | ||
| 4744 | devilment | ||
| 4745 | devious | ||
| 4746 | devise | ||
| 4747 | devitalize | ||
| 4748 | devoid | ||
| 4749 | devolution | ||
| 4750 | devolve | ||
| 4751 | devote | ||
| 4752 | devotee | ||
| 4753 | devotion | ||
| 4754 | devour | ||
| 4755 | devout | ||
| 4756 | dew | ||
| 4757 | dewlap | ||
| 4758 | dexterity | ||
| 4759 | dexterous | ||
| 4760 | dextrose | ||
| 4761 | dextrous | ||
| 4762 | dhoti | ||
| 4763 | dhow | ||
| 4764 | diabetes | ||
| 4765 | diabetic | ||
| 4766 | diabolic | ||
| 4767 | diacritic | ||
| 4768 | diadem | ||
| 4769 | diaeresis | ||
| 4770 | diagnose | ||
| 4771 | diagnosis | ||
| 4772 | diagnostic | ||
| 4773 | diagonal | ||
| 4774 | diagram | ||
| 4775 | dial | ||
| 4776 | dialect | ||
| 4777 | dialectic | ||
| 4778 | dialogue | ||
| 4779 | diameter | ||
| 4780 | diametrically | ||
| 4781 | diamond | ||
| 4782 | diaper | ||
| 4783 | diaphanous | ||
| 4784 | diaphragm | ||
| 4785 | diarchy | ||
| 4786 | diarrhoea | ||
| 4787 | diary | ||
| 4788 | diaspora | ||
| 4789 | diatonic | ||
| 4790 | diatribe | ||
| 4791 | dibble | ||
| 4792 | dice | ||
| 4793 | dicey | ||
| 4794 | dichotomy | ||
| 4795 | dickens | ||
| 4796 | dicker | ||
| 4797 | dickey | ||
| 4798 | dicky | ||
| 4799 | dictaphone | ||
| 4800 | dictate | ||
| 4801 | dictation | ||
| 4802 | dictator | ||
| 4803 | diction | ||
| 4804 | dictionary | ||
| 4805 | dictum | ||
| 4806 | did | ||
| 4807 | didactic | ||
| 4808 | diddle | ||
| 4809 | die | ||
| 4810 | dieresis | ||
| 4811 | diesel | ||
| 4812 | diet | ||
| 4813 | differ | ||
| 4814 | difference | ||
| 4815 | different | ||
| 4816 | differential | ||
| 4817 | differentiate | ||
| 4818 | difficult | ||
| 4819 | difficulty | ||
| 4820 | diffident | ||
| 4821 | diffract | ||
| 4822 | diffuse | ||
| 4823 | dig | ||
| 4824 | digest | ||
| 4825 | digestion | ||
| 4826 | digestive | ||
| 4827 | digger | ||
| 4828 | digging | ||
| 4829 | digit | ||
| 4830 | dignify | ||
| 4831 | dignitary | ||
| 4832 | dignity | ||
| 4833 | digraph | ||
| 4834 | digress | ||
| 4835 | digs | ||
| 4836 | dike | ||
| 4837 | dilapidated | ||
| 4838 | dilate | ||
| 4839 | dilatory | ||
| 4840 | dilemma | ||
| 4841 | dilettante | ||
| 4842 | diligence | ||
| 4843 | diligent | ||
| 4844 | dill | ||
| 4845 | dilute | ||
| 4846 | dim | ||
| 4847 | dime | ||
| 4848 | dimension | ||
| 4849 | diminish | ||
| 4850 | diminuendo | ||
| 4851 | diminution | ||
| 4852 | diminutive | ||
| 4853 | dimity | ||
| 4854 | dimple | ||
| 4855 | din | ||
| 4856 | dine | ||
| 4857 | diner | ||
| 4858 | dinghy | ||
| 4859 | dingle | ||
| 4860 | dingy | ||
| 4861 | dining | ||
| 4862 | dinky | ||
| 4863 | dinner | ||
| 4864 | dinosaur | ||
| 4865 | dint | ||
| 4866 | diocese | ||
| 4867 | dioxide | ||
| 4868 | dip | ||
| 4869 | diphtheria | ||
| 4870 | diphthong | ||
| 4871 | diploma | ||
| 4872 | diplomacy | ||
| 4873 | diplomat | ||
| 4874 | diplomatic | ||
| 4875 | diplomatist | ||
| 4876 | dipper | ||
| 4877 | dipsomania | ||
| 4878 | diptych | ||
| 4879 | dire | ||
| 4880 | direct | ||
| 4881 | direction | ||
| 4882 | directive | ||
| 4883 | directly | ||
| 4884 | director | ||
| 4885 | directorate | ||
| 4886 | directory | ||
| 4887 | direful | ||
| 4888 | dirge | ||
| 4889 | dirigible | ||
| 4890 | dirk | ||
| 4891 | dirndl | ||
| 4892 | dirt | ||
| 4893 | dirty | ||
| 4894 | disability | ||
| 4895 | disable | ||
| 4896 | disabuse | ||
| 4897 | disadvantage | ||
| 4898 | disaffected | ||
| 4899 | disafforest | ||
| 4900 | disagree | ||
| 4901 | disagreement | ||
| 4902 | disallow | ||
| 4903 | disappear | ||
| 4904 | disappoint | ||
| 4905 | disappointment | ||
| 4906 | disapprobation | ||
| 4907 | disapprove | ||
| 4908 | disarm | ||
| 4909 | disarrange | ||
| 4910 | disarray | ||
| 4911 | disassociate | ||
| 4912 | disaster | ||
| 4913 | disavow | ||
| 4914 | disband | ||
| 4915 | disbelieve | ||
| 4916 | disbud | ||
| 4917 | disburden | ||
| 4918 | disburse | ||
| 4919 | disc | ||
| 4920 | discard | ||
| 4921 | discern | ||
| 4922 | discharge | ||
| 4923 | disciple | ||
| 4924 | disciplinarian | ||
| 4925 | discipline | ||
| 4926 | disclaim | ||
| 4927 | disclose | ||
| 4928 | disco | ||
| 4929 | discolour | ||
| 4930 | discomfit | ||
| 4931 | discomfort | ||
| 4932 | discommode | ||
| 4933 | discompose | ||
| 4934 | disconcert | ||
| 4935 | disconnect | ||
| 4936 | disconsolate | ||
| 4937 | discontent | ||
| 4938 | discontinue | ||
| 4939 | discontinuous | ||
| 4940 | discord | ||
| 4941 | discotheque | ||
| 4942 | discount | ||
| 4943 | discountenance | ||
| 4944 | discourage | ||
| 4945 | discourse | ||
| 4946 | discourteous | ||
| 4947 | discover | ||
| 4948 | discovery | ||
| 4949 | discredit | ||
| 4950 | discreet | ||
| 4951 | discrepancy | ||
| 4952 | discrete | ||
| 4953 | discretion | ||
| 4954 | discriminate | ||
| 4955 | discrimination | ||
| 4956 | discursive | ||
| 4957 | discus | ||
| 4958 | discuss | ||
| 4959 | discussion | ||
| 4960 | disdain | ||
| 4961 | disease | ||
| 4962 | disembark | ||
| 4963 | disembarrass | ||
| 4964 | disembody | ||
| 4965 | disembowel | ||
| 4966 | disenchant | ||
| 4967 | disencumber | ||
| 4968 | disenfranchise | ||
| 4969 | disengage | ||
| 4970 | disentangle | ||
| 4971 | disequilibrium | ||
| 4972 | disestablish | ||
| 4973 | disfavour | ||
| 4974 | disfigure | ||
| 4975 | disforest | ||
| 4976 | disfranchise | ||
| 4977 | disgorge | ||
| 4978 | disgrace | ||
| 4979 | disgruntled | ||
| 4980 | disguise | ||
| 4981 | disgust | ||
| 4982 | dish | ||
| 4983 | dishabille | ||
| 4984 | disharmony | ||
| 4985 | dishearten | ||
| 4986 | dishevelled | ||
| 4987 | dishonest | ||
| 4988 | dishonour | ||
| 4989 | disillusion | ||
| 4990 | disincentive | ||
| 4991 | disinclination | ||
| 4992 | disincline | ||
| 4993 | disinfect | ||
| 4994 | disinfest | ||
| 4995 | disinflation | ||
| 4996 | disingenuous | ||
| 4997 | disinherit | ||
| 4998 | disintegrate | ||
| 4999 | disinter | ||
13767 more lines aren’t shown here.
| @@ -1,5235 +0,0 @@ | |||
| 1 | login: | ||
| 2 | case '\7': *((char *)(384*1024L+062)) = 2; /* beep */ | ||
| 3 | Welcome to VAX/VMS Version 1.60 | ||
| 4 | ON ENDFILE(SYSIN) GO TO ADATHIBA; /* FILE-VEGE VIZSGALATA */ | ||
| 5 | Tape dump of all filesystems taken this afternoon. | ||
| 6 | "Analysis" is "design" spelled backwards. | ||
| 7 | "RULE 7: Option arguments cannot be optional." Sys V Interface p 343. | ||
| 8 | "Sound advice" is usually mostly sound with not much advice. | ||
| 9 | "The Dresser," first a play, then a movie, then AT&T headquarters. | ||
| 10 | "The more you drive ... the less intelligent you are." -- Miller, in Repo Man | ||
| 11 | "x.c", line 1: cannot recover from earlier errors: goodbye! | ||
| 12 | #(cat probably won't work on 8 bit files, you will have to use a simpler filter) | ||
| 13 | $! nulled, predecessor circle | ||
| 14 | $3,000,000 | ||
| 15 | %-W-NORML Normal Successful Completion | ||
| 16 | 'Tis a gross error, held in schools, That Fortune always favours fools. - John Gay. | ||
| 17 | 'Tis better playing with a lion's whelp,/Than with an old one dying. | ||
| 18 | 'Tis nobler in the mind to Look Things Up than to Pull Them Out Of The Air. | ||
| 19 | (^|[ (,;])(([Jj]ul[^ ]* *|(07|7)/)0*5)([^0123456789]|$) | ||
| 20 | * UNIX is a Trademark of Bell Laboratories. | ||
| 21 | *** LGP ERROR ***: Initialize -- Cannot initialize graphics hardware device. | ||
| 22 | *** REPLACE THIS LINE WITH YOUR MESSAGE *** | ||
| 23 | -1: No code table for op: ++post | ||
| 24 | ...and on the seventh day, He exited from append mode. | ||
| 25 | /usr/games/fortune: not found | ||
| 26 | /usr/news/gotcha | ||
| 27 | 1 bulls, 3 cows | ||
| 28 | 127 now in the unregulated subsidiary; see /usr/news/btl-split | ||
| 29 | 2 is always smaller than 3, even for large values of 2. | ||
| 30 | 2 lacks generality in a way that 1 doesn't. | ||
| 31 | 23. ... r-q1 | ||
| 32 | 355/113 -- not the famous irrational number PI, but an incredible simulation. | ||
| 33 | 4.2BSD is like a nightmare about Tenex. - Geoff Collyer | ||
| 34 | 4.2BSD may not be a complete disaster, but it does a good job of emulating one. | ||
| 35 | 55mph -- It's not a good idea, it's just the law. | ||
| 36 | : is not an identifier | ||
| 37 | A 10.0-szer 0.1 sohasem 1.0! | ||
| 38 | A 6-char limit is like a 6-inch trout: throw it back. | ||
| 39 | A 6-char limit is like night. | ||
| 40 | A Cray is the best machine for simulating the performance of a Cray. | ||
| 41 | A Point is a pair of shorts. | ||
| 42 | A Smith and Wesson beats four aces. | ||
| 43 | A bad workman quarrels with his tools. | ||
| 44 | A big book is a big nuisance. - Callimachus, librarian of Alexandria | ||
| 45 | A billion here, a billion there; soon you're talking real money. -E. Dirksen | ||
| 46 | A bird in hand is safer than one overhead. | ||
| 47 | A bird in the hand is worth what it will bring. | ||
| 48 | A block grant is a nice terminal, but it will keep you awake until noon. | ||
| 49 | A block grant is a solid mass of money surrounded on all sides by governors. | ||
| 50 | A chicken is just an egg's way of making more eggs. | ||
| 51 | A closed mouth gathers no foot. | ||
| 52 | A conservative is one who is too cowardly to fight and too fat to run. | ||
| 53 | A consistent indentation style is the hobgoblin of little minds. | ||
| 54 | A couch is as good as a chair. | ||
| 55 | A coward is one who in a perilous emergency thinks with his legs. | ||
| 56 | A critic is a legless man who teaches running. | ||
| 57 | A day for firm decisions!!!!! Or is it? | ||
| 58 | A day without sunshine is like night. | ||
| 59 | A duck with three wings and a loaf of bread is brother to the sun god. | ||
| 60 | A duck with three wings and a loaf of bread is brother to the turkey. | ||
| 61 | A fly by night leaves no shadow beyond a doubt. | ||
| 62 | A fool and his money stabilize the economy. | ||
| 63 | A foolish consistency is the hobgoblin of little minds. | ||
| 64 | A furore Normanorum libera nos, O Domine! | ||
| 65 | A game, a teaching aid, a sport, and a piece of art. -Erno Rubik | ||
| 66 | A gentleman is one who is never rude unintentionally. -Noel Coward | ||
| 67 | A good memory does not equal pale ink. | ||
| 68 | A good plan today is better than a perfect plan tomorrow. | ||
| 69 | A goodly apple rotten at the heart:/Oh, what a goodly outside falsehood hath! | ||
| 70 | A hacker does for love what others would not do for money. | ||
| 71 | A homeowner's reach should exceed his grasp, or what's a weekend for? | ||
| 72 | A hydrogen bomb doesn't care how brave you are. | ||
| 73 | A hypothesis is an opinion that you are trying to prove true. | ||
| 74 | A journey of a thousand miles begins with a cash advance from Sam. | ||
| 75 | A king's castle is his home. | ||
| 76 | A liberal is one too open-minded to take his own side in an argument. | ||
| 77 | A lone dime always gets the number nearly right. | ||
| 78 | A man does not attain the status of Galileo merely because he is persecuted; he must also be right. -Stephen Jay Gould | ||
| 79 | A man must destroy himself before others can destroy him. -Mong Tse | ||
| 80 | A man who fishes for marlin in ponds will put his money in Etruscan bonds. | ||
| 81 | A man who turns green has eschewed protein. | ||
| 82 | A man with 3 wings and a dictionary is cousin to the turkey. | ||
| 83 | A man without a faith is like a fish without a bicycle. | ||
| 84 | A megabyte here, a megabyte there, and pretty soon you're talking real power. | ||
| 85 | A megaflop is a failure of gigantic proportions. | ||
| 86 | A mighty maze! but not without a plan. -Pope | ||
| 87 | A more wretched hive of scum and villainy: not found. | ||
| 88 | A movie studio is the best toy a boy ever had. -Orson Welles | ||
| 89 | A penny saved is a political breakthrough. | ||
| 90 | A penny saved is ridiculous. | ||
| 91 | A penny saved kills your career in the Pentagon. | ||
| 92 | A philosopher does not need a torch to gather glow-worms by at mid-day. -- Earnest Bramah | ||
| 93 | A plague o' both your houses! They have made worms' meat of me. | ||
| 94 | A plucked goose doesn't lay golden eggs. | ||
| 95 | A poet who reads his verse in public may have other nasty habits. | ||
| 96 | A professor is one who talks in someone else's sleep. | ||
| 97 | A radical is a person with both feet firmly planted in the air. | ||
| 98 | A real Initiation never ends. -Aleister Crowley | ||
| 99 | A really busy person never knows how much he weighs. -Edgar Watson Howe | ||
| 100 | A recently completed trial proved TOAD Generic 1 to be reliable, user-friendly, and convenient. | ||
| 101 | A resort area will be part of your next holiday plans | ||
| 102 | A rolling stone gathers momentum. | ||
| 103 | A rose by any other name would still have thorns. | ||
| 104 | A sharp tongue is the only edge tool that grows keener with constant use. -W. Irving | ||
| 105 | A song in time is worth a dime. | ||
| 106 | A stitch in time keeps your tu-tu from becoming a four-four. | ||
| 107 | A system programmer is someone who debugs his programs with an oscilloscope. | ||
| 108 | A theory is better than an explanation. | ||
| 109 | A thousand throats may be slit in one night by a running man. | ||
| 110 | A tree is best measured when it is down. | ||
| 111 | A truly wise man never plays leapfrog with a Unicorn. | ||
| 112 | A twisting road will take you to Warsaw, but you won't be bored. | ||
| 113 | A u.f.o. closely encountered is no longer a u.f.o. | ||
| 114 | A victory is the greatest tragedy in the world - except a defeat. -Wellington | ||
| 115 | A watched terminal never prints. | ||
| 116 | A wise man never tries to warm himself in front of a painting of a fire. | ||
| 117 | A witty saying means nothing. -Voltaire | ||
| 118 | A woman is only a woman, but a good cigar is a smoke. -Rudyard Kipling | ||
| 119 | A578 Your FLP overflows into your KBUF. | ||
| 120 | AAAOO OOZOR AZZAZ ZAIEO AZAEI IIOZA KHOEO OOYTH OEAZA EAOOZ AKHOZ AKHEY THXAA LETHX KH | ||
| 121 | Ablata at alba. | ||
| 122 | Abortion and suicide are hereditary only if you prevent them. | ||
| 123 | About all some parents accomplish in life is either illegal, immoral or fattening. | ||
| 124 | About all some parents accomplish in life is to send a child to Harvard. | ||
| 125 | About the only thing on a farm that has an easy time is the dog. | ||
| 126 | Absence is better than a cure. | ||
| 127 | Absinthe makes the heart grow fonder. | ||
| 128 | According to the latest official figures, 43% of all statistics are worthless. | ||
| 129 | Accounting software is structured as a set of tools that can be used to build accounting systems. | ||
| 130 | Ad pulchritudinem tria requiruntur; integritas, consonantia, claritas. -Aquinas | ||
| 131 | Admiration is our polite recognition of another's resemblance to ourselves. | ||
| 132 | After 24 hours, corpses and guests smell bad. | ||
| 133 | After all, a murderer is only an extroverted suicide. | ||
| 134 | Afternoon very favorable for romance. Try a single person for a change. | ||
| 135 | Again, and strongly, undress the sheep. It is getting to visitors. | ||
| 136 | All articles that coruscate with resplendence are not truly aurifers. | ||
| 137 | All dare to write, who can or cannot read. -Horace, `Epistles', Book II | ||
| 138 | All my men wear badges, or they wear nothing at all. | ||
| 139 | All of the bridges between our today and our yesteryear have been burnt. | ||
| 140 | All of these futures having been sold, this fortune appears as a matter of record only. | ||
| 141 | All syllogisms have three parts; therefore this is not a syllogism. | ||
| 142 | All that does not glitter is not not-gold. | ||
| 143 | All the ethics in Hollywood can be rolled up and fit into a gnat's navel. | ||
| 144 | All the good ones are taken. | ||
| 145 | All the great men are dead and I'm not feeling too well myself. | ||
| 146 | All things considered, life is 9-to-5 against. | ||
| 147 | All things that are, are lights. | ||
| 148 | All you need to know is in the manual. | ||
| 149 | Almost all good computer programs contain at least one random-number generator. | ||
| 150 | Always keep a record of data. It indicates you've been working. | ||
| 151 | Always make water when you can. -Wellington | ||
| 152 | America's best buy for a dime is a telephone call to the right person. | ||
| 153 | An Austrian army, awfully arrayed, Boldly by battery besieged Belgrade. | ||
| 154 | An airplane is in your future. | ||
| 155 | An artist is never ahead of his time, but most people are far behind theirs. - Varese | ||
| 156 | An asylum for the sane would be empty in America. | ||
| 157 | An atheist is a man with no invisible means of support. | ||
| 158 | An elephant is a mouse built to government specifications. | ||
| 159 | An elephant is a mouse with an operating system. | ||
| 160 | An idle mind is worth two in the bush. | ||
| 161 | An oscilloscope is what cavemen used to debug fire. -Jim Veres | ||
| 162 | An ounce of application is worth a ton of abstraction. | ||
| 163 | And I alone am returned to wag the tail. | ||
| 164 | And malt does more than Milton can/to justify God's ways to man -A.E. Housman | ||
| 165 | And so to bed. | ||
| 166 | Androgyny recapitulates philately. | ||
| 167 | Another good night not to sleep in a eucalyptus tree. | ||
| 168 | Any change or reform you make is going to have consequences you don't like. | ||
| 169 | Any clod can have the facts, but having opinions is an *art*. -Chas. McCabe | ||
| 170 | Any country with "democratic" in the title isn't. | ||
| 171 | Any fool can paint a picture, but it takes a wise person to be able to sell it. | ||
| 172 | Any man's speeding ticket on the Interstate diminishes me, for I am involved in mankind. | ||
| 173 | Any small object that is accidentally dropped will hide under a larger object. | ||
| 174 | Any sufficiently advanced technology is indistinguishable from a rigged demo. | ||
| 175 | Any sufficiently advanced technology is indistinguishable from magic. -Clarke | ||
| 176 | Anyone can win, unless there happens to be a second entry. | ||
| 177 | Anyone who buys Wisconsin cheese is a traitor to mankind! -J. Pournelle | ||
| 178 | Anyone who understands my music will never be unhappy again. -L. Van Beethoven | ||
| 179 | Anyone's life is incomplete unless they are, in some smaller or larger way, saving the world. | ||
| 180 | Anything good in life is either illegal, immoral or fattening. | ||
| 181 | Arabic is a language, Persian is a sweetmeat, and Turkish is an art. | ||
| 182 | Arabic is a mystery -- love is just a crock. | ||
| 183 | Are we not men? | ||
| 184 | Are you kidding? | ||
| 185 | Are you sure you want a two dimensional array? | ||
| 186 | Aren't you glad his name wasn't Alexander Graham Klaxon? | ||
| 187 | Aries -- this is your lucky day! | ||
| 188 | Art is merely cheese made visible. | ||
| 189 | Artistic ventures highlighted. Rob a museum. | ||
| 190 | As above, so below. | ||
| 191 | As goatherd learns his trade by goat, so writer learns his trade by wrote. | ||
| 192 | As of Tuesday, C will be flushed in favor of COBOL. Please update all programs. | ||
| 193 | Assassination is the extreme form of censorship. | ||
| 194 | At the feast of souls failure is always the guest of honor. | ||
| 195 | Atomic compare and exchange. These sequences are not actually atomic [⋯]. However, they are very close to atomic, [⋯] LinuxThreads has been using these sequences for many years. | ||
| 196 | Attend winter sheep meetings. Learning never ends! | ||
| 197 | Auribus teneo lupum. | ||
| 198 | Automating a mess yields an automated mess. -Michael Hammer | ||
| 199 | Ave discordia. | ||
| 200 | Avoid a hasty decision. | ||
| 201 | Avoid reality at all costs. | ||
| 202 | Away put your weapon! I mean you no harm. | ||
| 203 | BLISS is ignorance. | ||
| 204 | Bad taste is timeless. | ||
| 205 | Ban the bomb. Save the world for conventional warfare. | ||
| 206 | Bank error in your favor. Collect $200. | ||
| 207 | Basic is like doing arithmetic with Roman numerals. - MD McIlroy | ||
| 208 | Be sure to evaluate the bird-hand/bush ratio. | ||
| 209 | Be the sea, and see me be. | ||
| 210 | Beauty is only sin deep. H H Munro | ||
| 211 | Beauty is only skin deep, but ugly goes clean to the bone. | ||
| 212 | Beauty times brains equals a constant. | ||
| 213 | Becoming an overnight success usually takes years. | ||
| 214 | Been Transferred Lately? | ||
| 215 | Better be right or your big venture goes wrong. -Resistor color code mnemonic | ||
| 216 | Better to have failed your Wasserman than never to have loved at all. | ||
| 217 | Between the idea and the reality, between the motion and the act falls the shadow. | ||
| 218 | Beware -- local customs vary. Check with a native before going into the jungle. | ||
| 219 | Beware of a dark-haired man with a loud tie. | ||
| 220 | Beware of low-flying butterflies. | ||
| 221 | Beware the foot of Nessus! | ||
| 222 | Beware: the light at the end of the tunnel may be New Jersey. | ||
| 223 | Beyond a certain point, the whole universe becomes a continuous Initiation. | ||
| 224 | Bigamy is having one spouse too many. Monogamy is the same. | ||
| 225 | Biggus Diggus wants YOU. | ||
| 226 | Bignose from Winnetka. | ||
| 227 | Blessed St. Leibowitz, let them keep on dreamin' down there... | ||
| 228 | Blessed are the meek for they shall inhibit the earth. | ||
| 229 | Blessed are they who Go Around in Circles, for they Shall be Known as Wheels. | ||
| 230 | Bosses never realize that a bottle neck is always at the top. | ||
| 231 | Bourne again. | ||
| 232 | Brain fried -- core dumped | ||
| 233 | Brashith Alhim | ||
| 234 | Bring your wife or husband and pink slip for the best trade-in deal in town. | ||
| 235 | Bubble bubble, toil and trouble; cast that float into a double. | ||
| 236 | Buick offers inbred american quality. -TV ad | ||
| 237 | Build a better mousetrap, and nature will build a better mouse. | ||
| 238 | Build it so that even a fool can use it, and only a fool will want to use it. | ||
| 239 | Bus error -- core dumped | ||
| 240 | But he who kisses the joy as it flies/Lives in Eternity's sunrise. -Wm. Blake | ||
| 241 | But many are not capable of a firm persuasion of anything. -Wm. Blake | ||
| 242 | But you'll never become a rhinoceros...you haven't got the vocation! | ||
| 243 | But, Siriusly... | ||
| 244 | By failing to prepare, you are preparing to fail. | ||
| 245 | By omnibus I traveled to Brooklyn. | ||
| 246 | By the pricking of my thumbs,/Something wicked this way comes. | ||
| 247 | C'est CHouette. Swiss bumper sticker | ||
| 248 | C'est dommage, mais c'est vrai. | ||
| 249 | C'est magnifique, mais ce n'est pas Unix. -Henry Spencer | ||
| 250 | CB is a great place to work. There are so many good going away parties. | ||
| 251 | CB is a many gendered thing. | ||
| 252 | California is a fine place to live if you happen to be an orange. - Fred Allen | ||
| 253 | Campus Crusade for Cthulhu -- It found me. | ||
| 254 | Can all this just be an accident? Or could there be some alien intelligence behind it? | ||
| 255 | Can tomorrow be more than just the end of today? | ||
| 256 | Cannot fork -- try again. | ||
| 257 | Capitalism is indeed obsessed with money, but Marxism is obsessed with Marxism. | ||
| 258 | Captain Clark welcomes you aboard. | ||
| 259 | Caught in --More-- loop. | ||
| 260 | Caution -- be sure brain is engaged before putting mouth in gear. | ||
| 261 | Caution: Do not view laser light with remaining eye. | ||
| 262 | Caution: breathing may be hazardous to your health. | ||
| 263 | Celebrate Hannibal Day this year. Take an elephant to lunch. | ||
| 264 | Celibacy is not hereditary. | ||
| 265 | Center 1127 -- It's not just a job, it's an adventure! | ||
| 266 | Center meeting at 4pm in 2C-543 | ||
| 267 | Centran manuals are available in 2B-515. | ||
| 268 | Charlie don't surf. | ||
| 269 | Children are hereditary: if your parents didn't have any, neither will you. | ||
| 270 | Clothes make the man. Naked people have little or no influence on society. | ||
| 271 | Club sandwiches, not baby seals. | ||
| 272 | Cocaine is nature's way of saying you make too much money. | ||
| 273 | Cogito Ergo Spud. | ||
| 274 | Cogito cogito ergo cogito sum. | ||
| 275 | Colorless green ideas sleep furiously. | ||
| 276 | Communication is only possible between equals. | ||
| 277 | Computers are not intelligent. They only think they are. | ||
| 278 | Consistency is always easier to defend than correctness. | ||
| 279 | Constants aren't. Variables don't. LISP does. Functions won't. Bytes do. | ||
| 280 | Contains no kung fu, car chases or decapitations. | ||
| 281 | Continental Life. Why do you ask? | ||
| 282 | Convictions cause convicts -- what you believe imprisons you. | ||
| 283 | Core Error - Bus Dumped | ||
| 284 | Could not open 2147478952 framebuffers. | ||
| 285 | Courage is something you can never totally own or totally lose. | ||
| 286 | Cowards die many times before their deaths;/The valiant never taste of death but once. | ||
| 287 | Crazee Edeee, his prices are INSANE!!! | ||
| 288 | Creativity is no substitute for knowing what you are doing. | ||
| 289 | Creditors have much better memories than debtors. | ||
| 290 | Critics are like eunuchs in a harem: they know how it's done, they've seen it done every day, but they're unable to do it themselves. -Brendan Behan | ||
| 291 | Cthulhu Saves! ... in case He's hungry later. | ||
| 292 | Dames is like streetcars -- The oceans is full of 'em. -Archie Bunker | ||
| 293 | Dames lie about anything - just for practice. -Raymond Chandler | ||
| 294 | Damn it, i gotta get outta here! | ||
| 295 | Dangerous knowledge is a little thing. | ||
| 296 | Data potato, du wop du wop. | ||
| 297 | Day of inquiry. You will be subpoenaed. | ||
| 298 | De minimis non curat lex. | ||
| 299 | Death is nature's way of telling you to slow down. | ||
| 300 | Death to all fanatics! | ||
| 301 | Deep down, we all need that escape velocity. -Steven Spielberg. | ||
| 302 | Democracy is also a form of worship. It is the worship of Jackals by Jackasses. | ||
| 303 | Department meeting in 3 minutes. | ||
| 304 | Deprive a mirror of its silver and even the Czar won't see his face. | ||
| 305 | Der Herrgott wurfelt nicht. -A. Einstein | ||
| 306 | Did you know ... that no-one ever reads these things? | ||
| 307 | Did you know that clones never use mirrors? | ||
| 308 | Die ich rief, die Geister, / Werd ich nun nicht los. | ||
| 309 | Die: to stop sinning suddenly. | ||
| 310 | Dieux! Un monstre hideux. En hurlant. Nous poursuit. | ||
| 311 | Diplomacy is the art of saying "nice doggy" until you can find a rock. | ||
| 312 | Disco delenda est. | ||
| 313 | Disk crisis, please clean up! | ||
| 314 | Disobedience was Man's Original Virtue. -Oscar Wilde. | ||
| 315 | Distrust yourself, and sleep before you fight. 'Tis not too late tomorrow to be brave. - J. Armstrong. | ||
| 316 | Ditat Deus. | ||
| 317 | Do not believe in miracles -- rely on them. | ||
| 318 | Do not clog intellect's sluices with bits of knowledge of questionable uses. | ||
| 319 | Do not confuse boredom with security. | ||
| 320 | Do not confuse effort with work. | ||
| 321 | Do not drink coffee in early A.M. It will keep you awake until noon. | ||
| 322 | Do not go gentle into that good night/Rage, rage against the dying of the light | ||
| 323 | Do not meddle in the affairs of troff; it is subtle and quick to anger. | ||
| 324 | Do not meddle in the affairs of wizards: it makes them soggy and hard to light. | ||
| 325 | Do not meddle in the affairs of wizards: they are subtle and quick to anger. | ||
| 326 | Do not meddle in the mouth. | ||
| 327 | Do not sleep in a eucalyptus tree tonight. | ||
| 328 | Do not take life too seriously; you will never get out if it alive. | ||
| 329 | Do not throw butts in the urinal: it makes them soggy and hard to light. | ||
| 330 | Do not throw butts in the urinal: they are subtle and quick to anger. | ||
| 331 | Do not underestimate the power of the Force. | ||
| 332 | Do not use the blue keys on this terminal. | ||
| 333 | Do something unusual today. Pay a bill. | ||
| 334 | Do what comes naturally now. Seethe and fume and throw a tantrum. | ||
| 335 | Do what thou wilt shall be the whole of the law. | ||
| 336 | Does George know what he's got here? -Steven Spielberg. | ||
| 337 | Does a firm persuasion that a thing is so make it so? -Wm. Blake | ||
| 338 | Does the early bird enjoy the worm as much as the late bird enjoys the sleep? | ||
| 339 | Don't be overly suspicious where it's not warranted. | ||
| 340 | Don't believe everything you hear or anything you say. | ||
| 341 | Don't call me a mindless philosopher, you overweight glob of grease. | ||
| 342 | Don't commute, communicate. | ||
| 343 | Don't conscience-stricken before they're hatched. | ||
| 344 | Don't eat yellow snow. | ||
| 345 | Don't feed the bats tonight. | ||
| 346 | Don't force it, use a bigger hammer. | ||
| 347 | Don't forget to run "make depend" | ||
| 348 | Don't get mad, make book. | ||
| 349 | Don't go surfing in South Dakota for a while. | ||
| 350 | Don't hate yourself in the morning -- sleep till noon. | ||
| 351 | Don't kiss an elephant on the lips today. | ||
| 352 | Don't let your thoughts get in a rut. The knife which spreads may also cut. | ||
| 353 | Don't lie if you don't have to. -Leo Szilard | ||
| 354 | Don't look back -- something may be gaining on you. -Satchel Paige. | ||
| 355 | Don't play games with me. You weren't on any mercy mission this time. | ||
| 356 | Don't put a loaded rifle on the stage unless someone intends to fire it. | ||
| 357 | Don't rely on your nose -- TEST ATMOSPHERE! | ||
| 358 | Don't speak about Time, until you have spoken to him. | ||
| 359 | Don't tell any big lies today. Small ones can be just as effective. | ||
| 360 | Don't try to have the last word. You might get it. | ||
| 361 | Don't try to out-weird me, I get stranger things than you free with my breakfast cereal. | ||
| 362 | Don't type so hard. | ||
| 363 | Don't vote -- it only encourages them. | ||
| 364 | Don't worry -- dat mine, it can't hurt us -- it's one of ours. -Eccles | ||
| 365 | Don't worry if it doesn't work right; if everything did, you'd be out of a job. | ||
| 366 | Don't worry, it's not loaded. | ||
| 367 | Don't worry, they couldn't hit an elephant at this dist | ||
| 368 | Don't you feel more like you do now than you did when you came in? | ||
| 369 | Don't you have anything better to do with your time? | ||
| 370 | Down with categorical imperative! | ||
| 371 | Dreams are free, but there's a small charge for alterations. | ||
| 372 | Dreams are free, but you get soaked on the connect time. | ||
| 373 | Drive defensively, buy a tank. | ||
| 374 | Ducking for apples. Change one letter and it's the story of my life. _ Dorothy Parker | ||
| 375 | Dump time is unreasonable | ||
| 376 | During 1986, UNIX will dominate the low end. J. Scanlon | ||
| 377 | Dyslexics of the world, untie! | ||
| 378 | E Pluribus Unix. | ||
| 379 | E Unibus Plurum. | ||
| 380 | E pur si muove. | ||
| 381 | ERROR CREEPOUT HAS BEGUN | ||
| 382 | EVACUATION ROUTE ----> | ||
| 383 | Each man's death diminishes me for I am involved in Humanity. -John Donne | ||
| 384 | Easy for you to type, I have to do all the work. | ||
| 385 | Eat snart foobs. -Unknown Jerome | ||
| 386 | Economic analysts say that while the economy may be slowing, it is not fizzling out. | ||
| 387 | Edinburgh is the Reykjavik of the South. | ||
| 388 | Ego sum ens omnipotens. | ||
| 389 | Eileen L. Behr has translated her skill in public speaking into a successful career selling capacitors. | ||
| 390 | Either I'm dead or my watch has stopped. -Groucho Marx' last words | ||
| 391 | Either we are alone or we are not. Either way is mind-boggling. | ||
| 392 | Eleemosynary deeds have their incipience intramurally. | ||
| 393 | English is a stretch language; one size fits all. -W. Safire | ||
| 394 | Eschew the implement of correction and vitiate the scion. | ||
| 395 | Espanol tiene demasiada mucha grammatica. | ||
| 396 | Even a cabbage may look at a king. | ||
| 397 | Even a hawk is an eagle among crows. | ||
| 398 | Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley | ||
| 399 | Even paranoia can sometimes be taken to extremes. | ||
| 400 | Even the boldest zebra fears the hungry lion. | ||
| 401 | Even the simplest solution is bound to have something wrong with it. | ||
| 402 | Even the smallest candle burns brighter in the dark. | ||
| 403 | Even the thousand-zloty note can't tapdance. | ||
| 404 | Even these days, it's not as easy to go crazy as you think. | ||
| 405 | Ever see what ratfor does on a syntax error in a for loop? | ||
| 406 | Ever wake up feeling like a null pointer? -Allan Pratt | ||
| 407 | Every absurdity has a champion to defend it. | ||
| 408 | Every cloud has a silver lining; you should have sold it, and bought titanium. | ||
| 409 | Every day, thousands of housewives pick up speed. | ||
| 410 | Every excess becomes a vice. | ||
| 411 | Every good subversive does it for fun. -Rich Rosen | ||
| 412 | Every law creates a whole new criminal class overnight. | ||
| 413 | Every little picofarad has a nanohenry all its own. | ||
| 414 | Every purchase has its price. | ||
| 415 | Every solution breeds new problems. | ||
| 416 | Every time you make something foolproof, along comes a better class of fool. | ||
| 417 | Everybody should believe in something -- I believe I'll have another drink. | ||
| 418 | Everything breaks down. | ||
| 419 | Everything east of the San Andreas Fault will eventually plunge into the ocean. | ||
| 420 | Everything is funny so long as it is happening to someone else. -Will Rogers | ||
| 421 | Everything should be as simple as possible, but no simpler. - A. Einstein | ||
| 422 | Everything takes longer than you think. | ||
| 423 | Everything you know is wrong. | ||
| 424 | Everything's been said before, but nobody's listening, so keep repeating. | ||
| 425 | Ewige Blumenkraft. | ||
| 426 | Excellent day for drinking heavily. Spike the office water cooler. | ||
| 427 | Excellent day to have a rotten day. | ||
| 428 | Excellent time to become a missing person. | ||
| 429 | Executive ability is in your make-up. | ||
| 430 | Exercise is the Yuppie version of bulemia. | ||
| 431 | Exhibition will continue to decline and ultimately lead to other sources of entertainment. | ||
| 432 | Expansion means complexity; and complexity decay. | ||
| 433 | Expected arrival date is presently unknown. -Dave Kristol | ||
| 434 | Experience varies directly with the equipment ruined. | ||
| 435 | Explicit liber viri elephantini. | ||
| 436 | External Security: | ||
| 437 | FORTRAN 8X combines the simplicity of PL/I and the parsimony of ADA. -S Feldman | ||
| 438 | Fact without theory is trivia, theory without fact is bullshit. | ||
| 439 | Facta, non verba -- et verbum caro factus est. | ||
| 440 | Facta, non verba. | ||
| 441 | Fairness? Decency? How can you expect fairness and decency on a planet of sleeping people? | ||
| 442 | Far duller than a serpent's tooth it is to spend a quiet youth. | ||
| 443 | Far too noisy, my dear Mozart. Far too many notes. -Emperor Ferdinand. | ||
| 444 | Favor negative lobes. | ||
| 445 | Fear is failure and the forerunner of failure. | ||
| 446 | Fear not, the end of the world isn't until next week. | ||
| 447 | Few things are harder to put up with than the annoyance of a good example. | ||
| 448 | Fiat lux. | ||
| 449 | Fiat voluntas tua. | ||
| 450 | Fill what's empty; empty what's full; scratch where it itches. -Alice Roosevelt Longworth | ||
| 451 | Find the enemy and shoot him down; everything else is rubbish. -M. von Richthofen | ||
| 452 | Fine day to throw a party. Throw him as far as you can. | ||
| 453 | Fine day to work off excess energy. Steal something heavy. | ||
| 454 | First there is a mountain, then there is no mountain, then there is. | ||
| 455 | First things first. Why not send for the Nazis right now. | ||
| 456 | Fleas can be taught nearly anything that a congressperson can. | ||
| 457 | Flee at once, all is discovered. | ||
| 458 | Flight 23 is down in the Bermuda Triangle. | ||
| 459 | Florida is the "flea and tick capital of America." | ||
| 460 | Fnord. | ||
| 461 | For a good time, call 8367-3100. | ||
| 462 | For every action there is an equal and opposite government program. | ||
| 463 | For me, UNIX is a way of being. -Armando P. Stettner | ||
| 464 | For people who like that kind of book, that is the kind of book they will like. | ||
| 465 | Forget it, Jake...it's Chinatown. | ||
| 466 | Forsan et haec olim meminisse juvabit. | ||
| 467 | Fortis fortuna adiuvat. - Terence | ||
| 468 | Fortran est; non potest legi. | ||
| 469 | Fortunate are they who can laugh at themselves; they will never want for amusement. | ||
| 470 | Fortune, good night, smile once more, turn thy wheel! - King Lear II.ii.180 | ||
| 471 | Fortunes ... come tumbling into some men's laps. - Francis Bacon. | ||
| 472 | Frankly, I'd rather be in Philadelphia. | ||
| 473 | Freedom is the right to be our own potty little selves. -G. K. Chesterton | ||
| 474 | Freedom of incrustations of grime is contiguous with rectitude. | ||
| 475 | Friends come and go, but enemies accumulate. | ||
| 476 | Fritter and waste the hours in an offhand way. | ||
| 477 | From EXPLMY: Serious internal error, check the error code in the documentation of VRFYMY. | ||
| 478 | Future looks spotty. You will spill soup in late evening. | ||
| 479 | Gaffer's tape, like The Force, has a light and a dark side and binds the universe together. | ||
| 480 | Gallium Arsenide is the material of the future and it always will be. | ||
| 481 | Generalizations are useful. The work contained in them can be reckoned as labor and therefore can create value. -G.W. Hegel | ||
| 482 | Generosity and perfection are your everlasting goals. | ||
| 483 | Genius is the talent of a person who is dead. | ||
| 484 | Gentlemen, you can't fight here. This is the war room. | ||
| 485 | Get your boots on, 'cause we're gunna go in DEEP! | ||
| 486 | Give me a rock, paper and scissors and I will move the world. CCFestoon | ||
| 487 | Give me a sleeping pill and tell me your troubles. | ||
| 488 | Give your child mental blocks for Christmas. | ||
| 489 | Given enough inside information and unlimited credit, you've got to go broke. | ||
| 490 | Go directly to jail. Do not pass Go, do not collect $200. | ||
| 491 | Go out and see what the real world has to offer -Gerry Todd | ||
| 492 | Go suck on an infinite tube. | ||
| 493 | God does not play dice. | ||
| 494 | God gives us relatives; thank goodness we can choose our friends. | ||
| 495 | God is in the rock too -- in the rock! | ||
| 496 | God isn't dead, he just couldn't find a parking place. | ||
| 497 | God made the integers; all else is the work of Man. | ||
| 498 | God not only plays dice with the universe, He loads the dice too. | ||
| 499 | Gods! A hideous beast, baying is pursuing us! | ||
| 500 | Golden lads and girls all must,/Like chimney sweepers, come to dust. | ||
| 501 | Good Americans, when they die, go to Paris. - Thomas Appleton. | ||
| 502 | Good Rule: Don't put anything in your mouth labeled "HARMFUL IF SWALLOWED" | ||
| 503 | Good day for a change of scene. Repaper the bedroom wall. | ||
| 504 | Good day for flaming at floyd!trb. | ||
| 505 | Good day for overcoming obstacles. Try a steeplechase. | ||
| 506 | Good day to avoid cops. Crawl to work. | ||
| 507 | Good day to do the unexpected: write some documentation. | ||
| 508 | Good day to let down old friends who need help. | ||
| 509 | Good day to write a purchase requisition for a 747. | ||
| 510 | Good fish get dull but sex is always fun. -- Mehinaku proverb | ||
| 511 | Good health is just the slowest, most lingering way of dying. | ||
| 512 | Good intentions don't mean anything unless they can deliver. | ||
| 513 | Good manners and bad breath get you nowhere | ||
| 514 | Good news. Ten weeks from Friday will be a pretty good day. | ||
| 515 | Gort! Klaatu barada...uh...uh... | ||
| 516 | Government expands to absorb all available revenue and then some. | ||
| 517 | Government is just Anarchy's way of making more anarchy. | ||
| 518 | Graecum est; non potest legi. | ||
| 519 | Great shot, kid. That was one in a million. | ||
| 520 | Great warrior? Heh-heh-heh. Wars do not make one great. | ||
| 521 | Green light in A.M. for new projects. Red light in P.M. for traffic tickets. | ||
| 522 | Growth itself becomes the only moral end. -John Dewey | ||
| 523 | Guns don't kill detectives -- love does. | ||
| 524 | Ha! You killed my husband, Sam. Be kind to me. | ||
| 525 | Had Cleopatra's nose been shorter, the whole history of the world would have been different. - Pascal | ||
| 526 | Hail to the sun god/He sure is a fun god/Ra! Ra! Ra! | ||
| 527 | Half Moon tonight. (At least it's better than no Moon at all.) | ||
| 528 | Hang by your pseudopod, write if you find a warm rich planet ripe for conquest. | ||
| 529 | Hang in there, hammock-nose. | ||
| 530 | Hangover is the wrath of the grapes. | ||
| 531 | Have a nice diurnal anomaly. | ||
| 532 | Have you done your Christmas chopping yet? -anon. White House Advisor 12/24/81 | ||
| 533 | Have you hugged my T-shirt today? | ||
| 534 | He can't think without his hat. | ||
| 535 | He cried at all his own weddings, and with reason. | ||
| 536 | He gave her a look that you could have poured on a waffle. | ||
| 537 | He is no lawyer who cannot take two sides. | ||
| 538 | He is truly wise who gains wisdom from another's mishap. | ||
| 539 | He is winding the watch of his wit; by and by it will strike. | ||
| 540 | He looked at me as if I was a side dish he hadn't ordered. | ||
| 541 | He missed an invaluable opportunity to hold his tongue. | ||
| 542 | He serves the state best who opposes it most. -Thoreau | ||
| 543 | He that laugheth in the face of death haveth the last laugh. | ||
| 544 | He thinks by infection, catching an opinion like a cold. | ||
| 545 | He was al coltissh, ful of ragerye,/And ful of jargon as a flekke pye. -Chaucer | ||
| 546 | He was so narrow-minded he could see through a keyhole with two eyes. | ||
| 547 | He who binds himself to a joy/Does the winged life destroy. -Wm. Blake | ||
| 548 | He who has a shady past knows that nice guys finish last. | ||
| 549 | He who has imagination without learning has wings but no feet. | ||
| 550 | He who has science and art has religion. -Goethe | ||
| 551 | He who hesitates is last. | ||
| 552 | He who hesitates is scrap metal. | ||
| 553 | He who hesitates is sometimes saved. | ||
| 554 | He who invents adages for others to peruse takes along rowboat when going on cruise. | ||
| 555 | He who keeps his nose to the grindstone, has a flat face. | ||
| 556 | He who laughs last is a little slow on the uptake. | ||
| 557 | He who laughs, lasts. | ||
| 558 | He who listens last is the last one listening. | ||
| 559 | He who makes a beast of himself gets rid of the pain of being a man. -H.S. Thompson | ||
| 560 | He who spends a storm beneath a tree, takes life with a grain of TNT. | ||
| 561 | He who trains his tongue to quote from learned sages will be known far and wide as a smartass. | ||
| 562 | He who wears belt and suspenders needs tighter belt. | ||
| 563 | Help a swallow land at Capistrano. | ||
| 564 | Help conquer the IQ shortage: worry less and think more. | ||
| 565 | Help me, i'm a prisoner in a chinese computer terminal! | ||
| 566 | Hey, I've got it -- let's put on a show! | ||
| 567 | Hi, this is Ken. What's the root password? | ||
| 568 | Hindsight is an exact science. | ||
| 569 | His heart was yours from the first moment that you met. | ||
| 570 | His money is twice tainted: 'taint yours and 'taint mine. | ||
| 571 | History is a race between education and catastrophe. -H. G. Wells | ||
| 572 | Hit space to start | ||
| 573 | Hodie tempum scriptire in Latinum non habeo. Cras epistlum submissibo. | ||
| 574 | Home is the place where, when you have to go there, they have to take you in. | ||
| 575 | Home is where / is. | ||
| 576 | Honi soit la vache qui rit. | ||
| 577 | Hop before you skip. | ||
| 578 | Horse sense is the thing a horse has which keeps it from betting on people. | ||
| 579 | How I want a drink, alcoholic of course, after the chapters involving quantum mechanics. | ||
| 580 | How can I take an interest in my work when I don't like it? | ||
| 581 | How can you work when the system's so crowded? | ||
| 582 | How did the Universe manage to go bang in such an unreasonable way? -PCW Davies | ||
| 583 | How do I love thee? Hand me my calculator... | ||
| 584 | How is it far, if you can think of it? | ||
| 585 | How long you live has nothing to do with how long you are going to be dead. | ||
| 586 | How sharper than a child's tooth it is to have a thankless serpent. | ||
| 587 | How sharper than a serpent's tooth it is to have a thankless child. | ||
| 588 | How the elephant got into my pyjamas I'll never know. -Marx, Animal Crackers | ||
| 589 | How wonderful opera would be if there were no singers. | ||
| 590 | How you look depends on where you go. | ||
| 591 | Human beings are the only animals of which I am thoroughly and cravenly afraid. | ||
| 592 | Human kind cannot bear very much reality. -T.S. Eliot | ||
| 593 | Hypocrisy is the tribute vice pays to virtue. | ||
| 594 | Hypothesize and test. | ||
| 595 | I am Magnus. You are registered in my memory banks... | ||
| 596 | I am a high-pressure guy, and I didn't take this job to conduct a going-out-of-business sale. - A.A. Penzias | ||
| 597 | I am free of the wheel of Maya; I am dead to the dance of life. | ||
| 598 | I am large; I contain multitudes. | ||
| 599 | I am the Supreme Being. I'm not entirely dim. | ||
| 600 | I am the beast, I am the Word of the Aeon...I am a hell of a Holy Guru. | ||
| 601 | I am the wandering glitch -- catch me if you can. | ||
| 602 | I can call spirits from the vasty deep./Why, so can I, or so can any man. | ||
| 603 | I can resist everything except temptation. -Oscar Wilde. | ||
| 604 | I can't decide whether to throw you overboard or just change the way you look. | ||
| 605 | I cannot teach him. The boy has no patience. | ||
| 606 | I contradict myself? Very well, then: I contradict myself. I am large. | ||
| 607 | I dinna believe she'll hold up much longer, Captin. | ||
| 608 | I do not sketch or design a work, I merely begin. -Joan Miro | ||
| 609 | I don't even know what street Canada is on. - Al Capone | ||
| 610 | I don't have a moral plan... I'm a Canadian. -David Cronenberg | ||
| 611 | I don't like to walk, and I don't like to paddle. -James Watt | ||
| 612 | I don't love you any more since you ate my dog. | ||
| 613 | I don't mind your thinking slowly; i mind your publishing faster than you think. -W. Pauli | ||
| 614 | I give presents to the mother, but I think of the daughter. | ||
| 615 | I hate programs that chdir on you - Boyd Roberts | ||
| 616 | I have 36 rolls of 5247 for our use in the laser fridge... | ||
| 617 | I have NEVER written a program in C! Narain Gehani | ||
| 618 | I have discovered the art of deceiving diplomats; I tell them the truth and they never believe me. -Cavour | ||
| 619 | I have everything we will need. | ||
| 620 | I have never let my schooling interfere with my educations. | ||
| 621 | I have nothing to say and I am saying it and that is poetry as I need it. -Cage | ||
| 622 | I have the most perfect confidence in your indiscretion. | ||
| 623 | I haven't lost my mind. I've got it backed up on tape somewhere. | ||
| 624 | I hope that there are sour apples in every bushel. | ||
| 625 | I kissed my first cigarette on the herpolhode lying in the invariable plane. | ||
| 626 | I kissed my first cigarette on the stage unless someone intends to fire it. | ||
| 627 | I kissed my first lady and smoked my first cigarette on the same day. I have never had time for tobacco since. -Arturo Toscanini | ||
| 628 | I know nothing. -Ken Thompson | ||
| 629 | I know the difference between real-real and drug-real. | ||
| 630 | I like user-hostile ignorance-based amateur systems. | ||
| 631 | I like work; it fascinates me; I can sit and look at it for hours. | ||
| 632 | I love Pascal ... I'm also into leather. | ||
| 633 | I love the smell of napalm in the morning. | ||
| 634 | I love you. | ||
| 635 | I must have slipped a disk; my pack hurts. | ||
| 636 | I never dringk ... wine. -Bela Lugosi | ||
| 637 | I never refuse. I never contradict. I sometimes forget. -Disraeli | ||
| 638 | I knew it was coming and I still felt as if I'd swallowed a snowcone whole. | ||
| 639 | I regard an original error as better than a borrowed truth. -Merton. | ||
| 640 | I regard an original error as better than no Moon at all. | ||
| 641 | I see no login here! | ||
| 642 | I see only darkness in the crystal ball | ||
| 643 | I sense something -- a presence I haven't felt since.... | ||
| 644 | I taught him everything he knows. Now he knows more. -Randal L. Schwartz | ||
| 645 | I thank you from the heart of my bottom. | ||
| 646 | I think Isaac Newton is doing most of the driving right now. | ||
| 647 | I think my spaceship knows which way to go. | ||
| 648 | I think that I shall never see a billboard as lovely as a tree. -Ogden Nash | ||
| 649 | I think; therefore I am confused. | ||
| 650 | I was just going to call you. | ||
| 651 | I will not suffer fools gladly, but I will gladly make fools suffer. -Bimmler | ||
| 652 | I wish I had time to explain dimensional transcendentalism -Dr. Who | ||
| 653 | I wish you humans would leave me alone. | ||
| 654 | I wonder what will happen if I touch these two wires together. | ||
| 655 | I would be perfectly happy being Kepler, [but] I have been Kepler many times over.-B. Mandelbrot | ||
| 656 | I wouldn't let a knight out on a dog like this! | ||
| 657 | I wouldn't marry her to a ten foot Pole. | ||
| 658 | I wouldn't marry him with a ten foot pole. | ||
| 659 | I'd give my right arm to be ambidextrous. | ||
| 660 | I'd rather have a free bottle in front of me than a pre-frontal lobotomy. -Martin Mull | ||
| 661 | I'd rather have my mail delivered by Lockheed than ride in a plane built by the Post Office. | ||
| 662 | I'll eat it if I'm wrong. I mean a potato. - Danny Sleator | ||
| 663 | I'll produce anything that gets high ratings. -Anonymous NBC official | ||
| 664 | I'll smoke when the pope's wife takes the pill. | ||
| 665 | I'm a Hollywood writer; so I put on a sports jacket and take off my brain. | ||
| 666 | I'm free -- and freedom tastes of reality. | ||
| 667 | I'm from the government, and I'm here to help you. | ||
| 668 | I'm prepared for all emergencies but totally unprepared for everyday life. | ||
| 669 | I'm so hip I have difficulty seeing over my pelvis. | ||
| 670 | I'm sorry, but I've made other plans. | ||
| 671 | I've done this before and never had any trouble. | ||
| 672 | I've got a ferret sticking up my nose. | ||
| 673 | ICIKL: DO I = 1 /* BY +1 FELTETELEZESEVEL */ TO 2*N; | ||
| 674 | IOT trap -- core dumped | ||
| 675 | IOT trap -- core melted | ||
| 676 | If A=B and B=C, then A=C, except where void or prohibited by law. -Roy Santoro | ||
| 677 | If Congress must do a painful thing, it must be done in an odd-numbered year. | ||
| 678 | If God could perform the tricks we do, He'd be a happy man. | ||
| 679 | If God had meant Texans to ski, he would have made bullshit white. | ||
| 680 | If God had wanted you to go around nude, He would have given you bigger hands. | ||
| 681 | If God is perfect, why did He create discontinuous functions? | ||
| 682 | If God lived on Earth, people would knock out all His windows. | ||
| 683 | If God meant for Texans to ski, He would have made them a mountain. | ||
| 684 | If God wanted us to have a President, He would have sent us a candidate. | ||
| 685 | If I could remember the names of all these particles I would have been a botanist. -- Enrico Fermi | ||
| 686 | If I had only known, I would have been a locksmith. -Albert Einstein | ||
| 687 | If I had to choose between System V and 4.2, I'd resign. - Peter Honeyman | ||
| 688 | If I owned Texas and Hell, I'd rent out Texas and live in Hell. | ||
| 689 | If I say it's safe to surf this beach, Captain, it's safe to surf this beach. | ||
| 690 | If I should return in my absence, kindly detain me until I get back. | ||
| 691 | If I wanted your opinion, I'd tell it to you. -Samuel Goldwyn | ||
| 692 | If Lincoln were alive today he would be spinning in his grave. -G. Ford | ||
| 693 | If MS/DOS is the only operating system you're ever going to use, then the procedure is simple | ||
| 694 | If a thousand people say a foolish thing, it remains a foolish thing. | ||
| 695 | If all economists were laid end to end, they would not reach a conclusion. | ||
| 696 | If anything can go wrong, it will. | ||
| 697 | If at first you don't succeed, quit; don't be a nut about success. | ||
| 698 | If at first you succeed, try to hide your astonishment. | ||
| 699 | If bankers can count, why do they have eight windows and only four tellers? | ||
| 700 | If butterflies had teeth like tigers they would never make it out of the hangar. | ||
| 701 | If double-bubble inflation did occur, then the shadow world is exponentially uninteresting. | ||
| 702 | If ever I utter an oath again may my soul be blasted to eternal damnation. | ||
| 703 | If everything is coming your way, you're in the wrong lane. | ||
| 704 | If ignorance were cornflakes, you'd be General Mills. | ||
| 705 | If it ain't broke, don't fix it. | ||
| 706 | If it doesn't matter, it does not matter. | ||
| 707 | If it happens, it must be possible. | ||
| 708 | If it isn't like TECO, it's not worth using. -Rae McLellan | ||
| 709 | If it pours before seven, it has rained by eleven. | ||
| 710 | If it were dangerous they would post a sign... | ||
| 711 | If it's boring, turn it off. | ||
| 712 | If it's gratitude you want, get a dog. -P. T. Barnum | ||
| 713 | If it's not broken, don't fix it. | ||
| 714 | If it's not worth doing, it's not worth doing well. | ||
| 715 | If it's worth doing well, it's worth doing. | ||
| 716 | If more is better then too much is just enough. | ||
| 717 | If music be the breakfast food of love, kindly do not disturb until lunch time. | ||
| 718 | If some day it should happen that a victim must be found, I've got a little list, I've got a little list. | ||
| 719 | If the "medium is the message" then the message of low-bandwidth timesharing is "blah". -- Alan Kay | ||
| 720 | If the check is truly in the mail, it is surely made out to someone else. | ||
| 721 | If the coin is heads up don't pick it up. | ||
| 722 | If the experiment works, you must be using the wrong equipment. | ||
| 723 | If the facts do not support the theory, they must be disposed of. | ||
| 724 | If the government doesn't trust the people, why doesn't it elect a new people? | ||
| 725 | If the shoe fits, buy the other one, too. | ||
| 726 | If there are any resources you need to get this job done, just let us know. | ||
| 727 | If there is no God, who pops up the next Kleenex? -Art Hoppe | ||
| 728 | If they gave me a goldfish, I would cook it. -Feng Jicai | ||
| 729 | If time heals all wounds, how come the belly button stays the same? | ||
| 730 | If voting could change the system, it would be against the law. | ||
| 731 | If we turn on the lights fast enough, we'll see what the dark looks like. | ||
| 732 | If we'd all been living in California, we wouldn't have worked at ALL. | ||
| 733 | If you ask how much it is, you can't afford it. | ||
| 734 | If you can't find enough radiation at Ralph's, you can probably do without it. | ||
| 735 | If you can't stand the heat, remove your clothing! | ||
| 736 | If you cannot convince them, confuse them. -Harry S. Truman | ||
| 737 | If you do a job too well, you'll get stuck with it. | ||
| 738 | If you don't care where you are, then you ain't lost. | ||
| 739 | If you don't insist on correct answers, I can make it run as fast as you want. | ||
| 740 | If you don't know where you're going, it doesn't matter how you get there. | ||
| 741 | If you don't like the weather in New England, just wait a few minutes. | ||
| 742 | If you don't pay attention to every little detail, you miss most of the jokes. | ||
| 743 | If you gaze long enough into the abyss, the abyss will gaze back into you. | ||
| 744 | If you grab the bull by the horns, feathers will fly. | ||
| 745 | If you have to lie to someone, it's their fault. | ||
| 746 | If you have to think twice about it, you're wrong. | ||
| 747 | If you have to travel on the Titanic, why not go first class? | ||
| 748 | If you know high class quality merchandise, you know this is CHEAP! | ||
| 749 | If you start now you might finish on time. | ||
| 750 | If you suspect a man, don't employ him. | ||
| 751 | If you take the last cup, make a new pot. | ||
| 752 | If you take the last pot, make a new cup. | ||
| 753 | If you think before you speak the other guy gets his joke in first. | ||
| 754 | If you think big enough, you'll never have to do it. | ||
| 755 | If you think it's hard going to the moon, you should try staying home. | ||
| 756 | If you think last Tuesday was a drag, wait till you see what happens tomorrow! | ||
| 757 | If you want to go somewhere, goto is the best way to get there. K Thompson | ||
| 758 | If you want to have clean ideas, change them like shirts. | ||
| 759 | If you were able to count up to infinity I'll bet you would never get over it. | ||
| 760 | If you're asked to join a parade, don't march behind the elephants. | ||
| 761 | If you're feeling good, don't worry. You'll get over it. | ||
| 762 | If you're not apprehensive then you don't understand the situation. | ||
| 763 | If you're not part of the solution, you're part of the precipitate. | ||
| 764 | If your experiment needs statistics, you ought to have done a better experiment. - E. Rutherford | ||
| 765 | Ignore alien orders. | ||
| 766 | Ignore previous fortune. | ||
| 767 | Ignore the fatal errors. It's O.K. | ||
| 768 | Il faut cultiver son jardins. -Voltaire | ||
| 769 | Illegal Arbitrator - Line 23 | ||
| 770 | Illegitimi non carborundum. | ||
| 771 | Immanuel Kant but Kubla Khan. | ||
| 772 | In Africa the tusks are too firmly rooted, but in Alabama the Tuscaloosa. | ||
| 773 | In addition to a yes and a no, the universe contains a maybe. -D. Finkelstein | ||
| 774 | In an evolving universe, who stands still moves backwards. | ||
| 775 | In any society, the correct pronunciation is the dialect that has an army. | ||
| 776 | In case of fire, stand in the hall and shout "Fire!". | ||
| 777 | In challenging a kzin, a simple scream of rage is sufficient. | ||
| 778 | In communism Man exploits Man. In capitalism it's the other way around. | ||
| 779 | In comparison with the ancients, we stand like dwarfs on the shoulders of giants. -Bernard of Chartres | ||
| 780 | In girum imus nocte et consumimur igni. | ||
| 781 | In marriage, as in war, it is permitted to take every advantage of the enemy. | ||
| 782 | In nature there is immediate adjustment but no compulsion. -Chuang Chou | ||
| 783 | In order to make an omelette, you have to break a few cooks. | ||
| 784 | In rebus mathematicis errores quam minimi non sunt contemnendi. | ||
| 785 | In the Unix tradition, vi is intended to be a small tool that does one thing well. | ||
| 786 | In the future, all programmers will be able to use malloc. | ||
| 787 | In the land of the blind the one-eyed man can see across the road and prove it. | ||
| 788 | In the land of the blind, the one-eyed man is king. | ||
| 789 | In the land of the one-eyed men, the blind have to wear glasses. | ||
| 790 | In this world, truth can wait; she's used to it. | ||
| 791 | Incest, like charity, begins at home. | ||
| 792 | Insanity is always the best defense against boredom. | ||
| 793 | Inside every large problem is a small problem struggling to get out. -N. Wirth | ||
| 794 | Intermittent resolutions lack potency. -Robert Silverberg | ||
| 795 | Into each life a little fallout must rain. -Baba Rebop | ||
| 796 | It got to a point where I had to get a haircut or a violin. -F.D.Roosevelt | ||
| 797 | It is a poor judge who cannot award a prize. | ||
| 798 | It is a tale told by an idiot, full of sound and fury, signifying nothing. | ||
| 799 | It is a very sad thing nowadays that there is so little useless information. | ||
| 800 | It is absurd to deny the role of fantasy in even the strictest science. -Lenin | ||
| 801 | It is bad luck to be superstitious. -Andrew W. Mathis | ||
| 802 | It is better to have loved and lost -- much better. | ||
| 803 | It is better to have loved and lost than just to have lost. | ||
| 804 | It is better to kiss an avocado than to get in a fight with an aardvark. | ||
| 805 | It is better to light a single candle than to curse the darkness, except at the Browns Ferry reactor. | ||
| 806 | It is better to rule in Hell than to serve in Heaven. -Milton | ||
| 807 | It is better to wear out than to rust out. | ||
| 808 | It is easier to get forgiveness than permission. | ||
| 809 | It is far better to vote for a loser than to elect one. | ||
| 810 | It is far better to vote for a loser than to elect? | ||
| 811 | It is fruitless to become lachrymal over precipitately departed lacteal fluid. | ||
| 812 | It is hard to sit with the turkeys when you soar with the eagles. | ||
| 813 | It is much easier to suggest solutions when you know nothing about the problem. | ||
| 814 | It is the business of the future to be dangerous. -Hawkwind | ||
| 815 | It is the wise bird who builds her nest in a tree. | ||
| 816 | It is useless to put on your brakes when you're upside down. -Paul Newman | ||
| 817 | It seems like the less a statesman amounts to, the more he loves the flag. | ||
| 818 | It seems to make an auto driver mad if he misses you. | ||
| 819 | It steam-engines when it becomes steam-engine time. -Charles Fort | ||
| 820 | It takes approximately two minutes to reposition the continents from one geological era to another. | ||
| 821 | It was a book to kill time for those who liked it better dead. | ||
| 822 | It works better if you plug it in. | ||
| 823 | It would appear that even BTL employees put their pants on one leg at a time. | ||
| 824 | It would be wise to cut expectations in half. | ||
| 825 | It's 5 o'clock. Do you know where your files are? | ||
| 826 | It's Your Environment -- Use It Up! | ||
| 827 | It's a hardware problem. | ||
| 828 | It's a sad woman who buys her own perfume. | ||
| 829 | It's a small world, but I'd hate to have to paint it. | ||
| 830 | It's a software problem. | ||
| 831 | It's a useless but absolutely vital precaution. | ||
| 832 | It's an empty head that wears a hairpiece. - Pauline Kael | ||
| 833 | It's business doing pleasure with you. | ||
| 834 | It's clever, but is it art? | ||
| 835 | It's deja vu all over again. | ||
| 836 | It's difficult to explain Kleenex to an aborigine. | ||
| 837 | It's earlier than you think. | ||
| 838 | It's funny how they work so well, even when they're not appropriate. | ||
| 839 | It's hard to be humble when you're perfect. | ||
| 840 | It's hard to be mellow when you bite your nails. | ||
| 841 | It's hard to be mellow when you can't stand up. | ||
| 842 | It's hard to love someone who looks down on you because your hands get bloody protecting him. | ||
| 843 | It's just a silly native superstition. | ||
| 844 | It's later than you think. | ||
| 845 | It's lonely at the top, but it's lonelier at the bottom. | ||
| 846 | It's morally wrong to allow suckers to keep their money. | ||
| 847 | It's not Camelot, but it's not Cleveland, either. -Boston Mayor Kevin White | ||
| 848 | It's not a car, it's a Volkswagen. | ||
| 849 | It's not cool enough for the eighties. | ||
| 850 | It's not easy to play the clown when you've got to run the whole circus. | ||
| 851 | It's not my fault -- it's a mechanical problem! | ||
| 852 | It's not my fault! | ||
| 853 | It's not reality that's important, but how you perceive things. | ||
| 854 | It's not reality that's important, it's how you perceive things. | ||
| 855 | It's not the time between the takes that takes the time - it's changing your mind between the takes that takes the time. -Stage Dept. | ||
| 856 | It's not the time it takes to take the takes that takes the time, it's the time it takes between the takes that takes the time. -S. Spielberg | ||
| 857 | It's not the years, it's the mileage. | ||
| 858 | It's only a game! | ||
| 859 | It's simple, clean, it works, and you can get it right now. -Mike O'Dell | ||
| 860 | It's some kind of instinct...This was an important place in their lives. | ||
| 861 | It's the law: Use a pun, go to prism (for minor refractions of the law only!) | ||
| 862 | It's the thought, if any, that counts! -Dick Grantges | ||
| 863 | It's time to gearshift up from the crawl we've been in to a full trot. - Jack Scanlon | ||
| 864 | It's worse than being at the theatre. | ||
| 865 | Jam tomorrow and jam yesterday -- but never jam today. | ||
| 866 | Jesus Rodrigues has a 9-inch duck. | ||
| 867 | Jesus saves, Moses invests, the Mongol Hoards, but only Buddha pays dividends. | ||
| 868 | Join me and I will complete your training. | ||
| 869 | Journalism will kill you, but it will keep you alive while you're at it. | ||
| 870 | Just be glad you don't get all the government you pay for. -Will Rogers | ||
| 871 | Just because you're paranoid doesn't mean they're not out to get you. | ||
| 872 | Justice for the poor is much less popular than revenge on the rich. | ||
| 873 | Keep emotionally active. Cater to your favorite neurosis. | ||
| 874 | Ken Thompson can't beat Belle. So what? How fast can Seymour Cray add? | ||
| 875 | Kids are always the only future the human race has. -William Saroyan | ||
| 876 | Kill ugly radio! | ||
| 877 | Klaatu barada nikto. | ||
| 878 | Kleeneliness is next to Goedeliness. | ||
| 879 | Label on a bottle of pills: "Do not take these pills if this label is missing" | ||
| 880 | Lack of leadership is no substitute for inaction. | ||
| 881 | Lando's not a system, he's a man. He's a gambler, scoundrel. You'd like him. | ||
| 882 | Language is a virus from outer space. -William Burroughs. | ||
| 883 | Language is all that separates us from the lower animals and the bureaucrats. | ||
| 884 | Last login: Sat Aug 10 09:22:14 on ttym0 | ||
| 885 | Laugh and the world laughs with you; snore and you sleep alone. | ||
| 886 | Laugh, and the world ignores you. Crying doesn't help either. | ||
| 887 | Lay on, MacDuff, and curs'd be him who first cries, `Hold, enough!' | ||
| 888 | Leadership means taxes. | ||
| 889 | Lest men suspect your tale untrue,/Keep probability in view. -John Gay (1727) | ||
| 890 | Let a fool hold his tongue and he will pass for a sage. | ||
| 891 | Let him who takes the Plunge remember to return it by Tuesday. | ||
| 892 | Let no one unskilled in geometry enter here. -Plato | ||
| 893 | Let not the sands of time get in your lunch. | ||
| 894 | Let sleeping wraiths lie. | ||
| 895 | Let's just take this shortcut across this field. That bull doesn't see us. | ||
| 896 | Let's look at the record. -Al Smith | ||
| 897 | Li'l dollink, always fetful. | ||
| 898 | Liar: One who tells an unpleasant truth. | ||
| 899 | Life is a game: whoever dies with the most toys wins. | ||
| 900 | Life is a giant shell and we're just processes. | ||
| 901 | Life is a mystery -- love is a dancer. | ||
| 902 | Life is a yo-yo, and mankind ties knots in the string. | ||
| 903 | Life is hard but unjust. | ||
| 904 | Life is just a bowl. | ||
| 905 | Life is not for everyone. -M. O'Donoghue | ||
| 906 | Life is what happens to you while you're busy making other plans. | ||
| 907 | Like winter snow on summer lawn, time past is time gone. | ||
| 908 | Little girls have pretty curls, but I like Oreos. | ||
| 909 | Little things come in small packages. | ||
| 910 | Live forever, or die trying. | ||
| 911 | Live long and perspire. | ||
| 912 | Living in the past has one thing in its favour - it's cheaper. | ||
| 913 | Load average too high now (11.358253), please try later | ||
| 914 | Local disks are our FORTRAN. -Warren Teitelman | ||
| 915 | Long computations which yield 0 (zero) are probably all for naught. | ||
| 916 | Longevity is an optimist's heaven and a pessimist's hell. | ||
| 917 | Look after the molehills and the mountains will look after themselves. | ||
| 918 | Look on my works, oh ye mighty, and giggle. | ||
| 919 | Lord? We don't have no lord. We're an anarcho-syndicalist commune. | ||
| 920 | Lose a few, lose a few. | ||
| 921 | Losing your servo track is just God's way of saying `BOOGA, BOOGA!' | ||
| 922 | Love and scandal are the best sweeteners of tea. | ||
| 923 | Love is a many gendered thing. | ||
| 924 | Love is in the offing, said the homicidal maniac. | ||
| 925 | Love is only love, but money is forever. | ||
| 926 | Love the sea? I dote upon it - from the beach. | ||
| 927 | Love, and do what thou wilt. | ||
| 928 | Luchamos contra el Wombat, otra enemigo de la humanidad. -Frente Wombato de Liberacion Nacional | ||
| 929 | Luke, don't give in to hate. That leads to the dark side. | ||
| 930 | MOUNT TAPE U1439 ON B3, NO RING | ||
| 931 | Machne oprating at olny tn prcnt eficiency. | ||
| 932 | Macro context switch under way, please do not log out! | ||
| 933 | Make War, not Love: killing is fun too. -Nicholas von Hoffman | ||
| 934 | Make a list of all the facts you know about the universe. | ||
| 935 | Make is like Pascal: everybody likes it, so they go in and change it. -DM Ritchie | ||
| 936 | Make use of whatever advanced technology is available | ||
| 937 | Make: Don't know how to make love. Stop. | ||
| 938 | Making outside money using our computers has resulted in suspension. | ||
| 939 | Making sense makes more sense than not making sense. -T. Duff | ||
| 940 | Male tyrannosaurs may have used their diminutive front legs to titillate female partners, but this will not explain why they got so small. - Gould and Lewontin | ||
| 941 | Man cannot live by bread alone: frequently, there must be beverage, too. | ||
| 942 | Man cannot live by bread alone; he needs a little peanut butter on it. | ||
| 943 | Man has created death. -William Butler Yeats | ||
| 944 | Man is in doubt to deem himself a god or beast. -Alexander Pope | ||
| 945 | Man is in session. | ||
| 946 | Man who falls in vat of molten optical glass makes spectacle of self. | ||
| 947 | Man's horizons are bounded by his vision. | ||
| 948 | Many are called, few are chosen. Fewer still get to do the choosing. | ||
| 949 | Many are called, few volunteer. | ||
| 950 | Many are cold, but few are frozen. | ||
| 951 | Many pages make a thick book. | ||
| 952 | Marriage is a ghastly public confession of a strictly private intention. | ||
| 953 | Marriage is an attempt to change a night owl into a homing pigeon. | ||
| 954 | Masterpieces make their own rules. | ||
| 955 | May I have a large container of coffee? | ||
| 956 | May the bluebird of happiness twiddle your bits. | ||
| 957 | May you live all the days of your life. | ||
| 958 | May your rolling stone always grow grass that is greener underneath. | ||
| 959 | Maybe I should have screwed up. - Ken Thompson | ||
| 960 | Mcc may be slow and generate bad code, but it took a long time to develop. | ||
| 961 | Medeis ageometretos eisito mou ten stegen. -Plato | ||
| 962 | Members of an avian species of identical plumage congregate. | ||
| 963 | Men seldom make passes at girls who wear glasses. -Dorothy Parker. | ||
| 964 | Men seldom show dimples to girls who have pimples. | ||
| 965 | Message will arrive in the mail. Destroy, before the FBI sees it. | ||
| 966 | Micronics makes it simple. | ||
| 967 | Might as well be frank, monsieur. It would take a miracle to get you out of Casablanca. | ||
| 968 | Military justice is to justice as military music is to music. -Clemenceau | ||
| 969 | Military music is to music as military intelligence is to intelligence | ||
| 970 | Mind your own business, Spock. I'm sick of your halfbreed interference. | ||
| 971 | Misery loves company, but company does not reciprocate. | ||
| 972 | Misfortunes arrive on wings and leave on foot. | ||
| 973 | Mistakes are oft the stepping stones to failure. | ||
| 974 | Money cannot buy happiness, but happiness will not buy groceries. | ||
| 975 | Money is a terrible thing to follow but a charming thing to meet. | ||
| 976 | Money is the root of all evil, and man needs roots. | ||
| 977 | Money may buy friendship but money can not buy love. | ||
| 978 | Money will say more in one moment than the most eloquent lover can in years. | ||
| 979 | Most sacrilegious murder hath broke ope/The Lord's anointed temple. -MacBeth | ||
| 980 | Most users are within a 10 mile radius. | ||
| 981 | Mr. President! We cannot allow ... a MINE-SHAFT GAP! | ||
| 982 | Multi sunt vocati, pauci vero electi. | ||
| 983 | Multilevel standards are like onions. They're smelly and make you cry a lot. -Ron Natalie | ||
| 984 | My broker is E. F. Hutton, and E. F. Hutton says... | ||
| 985 | My karma just ran over your dogma. | ||
| 986 | My program is so jammed with clever tricks - GJ Holzmann | ||
| 987 | My way of joking is to tell the truth; it's the funniest joke in the world. | ||
| 988 | NOT NOT NOT ALLOWED | ||
| 989 | Naked is the best disguise. | ||
| 990 | National security is the chief cause of national insecurity. | ||
| 991 | Need a personal problem? Get a personal computer. - C. P. Killian | ||
| 992 | Neither a borrower nor a lender be/For loan oft loses both itself and friend. | ||
| 993 | Nembutal numbs it all, but I prefer alcohol. -Strummer/Jones | ||
| 994 | Netnews is someone yelling "Anybody wanna buy a used car?" in a crowded theater. | ||
| 995 | Never argue with a fool -- people might not know the difference. | ||
| 996 | Never attribute to malice what can be found in scientific american, under computer recreations. | ||
| 997 | Never buy a case of wine with eleven bottles. | ||
| 998 | Never call a man a fool. Borrow from him. | ||
| 999 | Never eat anything bigger than your head. | ||
| 1000 | Never eat in a restaurant that rotates or is above the 10th floor. | ||
| 1001 | Never eat rutabaga on any day of the week that has a "y" in it. | ||
| 1002 | Never give a inch! | ||
| 1003 | Never hatchet your Counts before they chicken. | ||
| 1004 | Never lick a gift horse in the mouth. | ||
| 1005 | Never put off till tomorrow what you can avoid altogether. | ||
| 1006 | Never speak ill of yourself; your friends will always say enough on that subject. | ||
| 1007 | Never stow away on a kamikaze plane. | ||
| 1008 | Never worry the boss unnecessarily. Don't tell him. | ||
| 1009 | New career ideas are worth pursuing. | ||
| 1010 | New crypt. See /usr/news/crypt. | ||
| 1011 | Niagara Falls is the second-biggest disappointment in a bride's life. -O. Wilde | ||
| 1012 | Niagara Falls is the wise bird who builds her nest in a chinese computer terminal! | ||
| 1013 | Niagara Falls would be much more impressive if it flowed the other way. - Oscar Wilde | ||
| 1014 | Nihilism means nothing to the dancing peasants. | ||
| 1015 | Nihilism should commence with oneself. | ||
| 1016 | No amount of genius can overcome a preoccupation with detail. | ||
| 1017 | No branch is better than its trunk. | ||
| 1018 | No directory | ||
| 1019 | No directory! Logging in with home=/ | ||
| 1020 | No good deed goes unpunished. -Clare Booth Luce. | ||
| 1021 | No jaggies! | ||
| 1022 | No man's life, liberty or property are safe while the legislature is in session. | ||
| 1023 | No mistake is too small to be fixed, but first make sure it's a mistake. | ||
| 1024 | No news is good news. | ||
| 1025 | No note is too high to be taken down an octave. | ||
| 1026 | No one can feel as helpless as the owner of a sick goldfish. | ||
| 1027 | No two ways about it, there are two sides to every story. | ||
| 1028 | No user jobs will be lost because of the crash. | ||
| 1029 | Nobody can be as agreeable as an uninvited guest. | ||
| 1030 | Nobody expects the Spanish Inquisition! | ||
| 1031 | Nobody goes to the theatre unless suffering from acute bronchitis. | ||
| 1032 | Nobody is truly sane until he feels gratitude to the whole universe. | ||
| 1033 | Nobody knows anything, or if they do, they are careful to hide the fact. | ||
| 1034 | Nobody takes computer graphics seriously, even the guys that do it. -T. Duff | ||
| 1035 | Non serviam. | ||
| 1036 | Nostalgia isn't what it used to be. | ||
| 1037 | Not all the water in a rough rude sea/Can wash the balm from an anointed king. | ||
| 1038 | Not only is there no God, but try getting a plumber on Sundays. | ||
| 1039 | Nothing astonishes men so much as common sense and plain dealing. | ||
| 1040 | Nothing difficult is ever easy. -Steve Falco | ||
| 1041 | Nothing is as easy as it looks. | ||
| 1042 | Nothing is capable of being well set to music that is not nonsense. - Joseph Addison. | ||
| 1043 | Nothing is impossible for the man who doesn't have to do it himself. | ||
| 1044 | Nothing is impossible for the man who will not listen to reason. | ||
| 1045 | Nothing is true. Everything is permissible. -Hassan i Sabbah | ||
| 1046 | Nothing matters indeed, it's all in your mind... | ||
| 1047 | Nothing more certain than incertainties; Fortune is full of fresh variety: Constant in nothing but inconstancy. - Richard Barnfield. | ||
| 1048 | Nothing of interest ever happened on this day. | ||
| 1049 | Nothing works. No one knows why. And some jerk is talking French. -Bob Lied | ||
| 1050 | Now and then an innocent man is sent to the legislature. | ||
| 1051 | Now is the winter of our discontent, made glorious summer in Northern California. | ||
| 1052 | Now is the winter of our discontent/Made glorious summer by this sun of York. | ||
| 1053 | O brave new world,/That has such people in't! | ||
| 1054 | O dear Ophelia! I am ill at these numbers: I have not art to reckon my groans. | ||
| 1055 | O.T.O. wants you. | ||
| 1056 | OK, I think I understand. | ||
| 1057 | OS 360 -- Not uranium. | ||
| 1058 | Of all forms of caution, caution in love is the most fatal. | ||
| 1059 | Of all things man is the measure. -Protagoras | ||
| 1060 | Oh, don't the days seem lank and long, when all goes right and nothing goes wrong. | ||
| 1061 | Oh, so there you are! | ||
| 1062 | Old MacDonald had an agricultural real estate tax abatement. | ||
| 1063 | Old age -- it's the only disease that you don't look forward to being cured of. | ||
| 1064 | Omnibus ex nihil ducendis sufficit unum. -Gottfried Wilhelm von Leibniz | ||
| 1065 | On a clear disk you can seek forever. | ||
| 1066 | Once TOAD is operational, how frequently would you expect to access TOAD? | ||
| 1067 | One Bell System -- it sometimes works. | ||
| 1068 | One Bell System -- it works. | ||
| 1069 | One bad apple can ruin a snake. | ||
| 1070 | One horse-laugh is worth ten thousand syllogisms. -H. L. Mencken | ||
| 1071 | One man tells a falsehood, a hundred repeat it as true. | ||
| 1072 | One man's Mede is another man's Persian. | ||
| 1073 | One picture is worth 128k words. | ||
| 1074 | One scythe fits all. | ||
| 1075 | One starts life with a swelled head and ends with swelled feet. -Ezra Pound | ||
| 1076 | Only %d shopping days until Christmas. | ||
| 1077 | Only God can make a random selection. | ||
| 1078 | Only someone with nothing to be sorry for smiles back at the rear of an elephant. | ||
| 1079 | Only two things are infinite: the universe and human ignorance. -A. Einstein | ||
| 1080 | Ontogeny recapitulates phylogeny, or is that ontology recapitulates philology? | ||
| 1081 | Ontogeny recapitulates phylogeny. -Haeckel | ||
| 1082 | Ontogeny rehashes phylogeny. | ||
| 1083 | Ooh, Andy Tannenbaum? His netnews is SO derivative. | ||
| 1084 | Options can cause undesirable operations, so it is important to ensure they are set up properly. | ||
| 1085 | Order ignorant aliens. | ||
| 1086 | Others will look to you for stability, so hide when you bite your nails. | ||
| 1087 | Otto's too so-so to toss soot, too sot to toot SOSs. So? | ||
| 1088 | Our ancestors may have been ignorant, but they were not stupid. | ||
| 1089 | Our sponsor thought it was for ADA. In fact it was for C. | ||
| 1090 | Our vision will speed up time, eventually deleting it. -Alexander Schure | ||
| 1091 | Out of memory saving lines for undo - try using ed. | ||
| 1092 | Out of the mouths of babes comes semi-digested Pablum. | ||
| 1093 | Overall there is a smell of fried onions. (fnord) | ||
| 1094 | Pack my box with five dozen liquor jugs. | ||
| 1095 | Panem et circenses, that's what the public wants. | ||
| 1096 | Paranoia doesn't mean the whole world really isn't out to get you. | ||
| 1097 | Pardon me for breathing, which I never do anyway oh, God, I'm so depressed... | ||
| 1098 | Passing over a black hole temporarily disables ship. | ||
| 1099 | Password: | ||
| 1100 | People get it into their heads that this is a democracy. Well it isn't. -gwl | ||
| 1101 | People never go there anymore; it's too crowded. -Yogi Berra | ||
| 1102 | People really shouldn't spread gossip, but what else is it good for? | ||
| 1103 | People tend to congregate in the back of the church and the front of the bus. | ||
| 1104 | People usually do what other people have done before them. | ||
| 1105 | People who deal with bits should expect to get bitten. -Jon Bentley | ||
| 1106 | People who take cat naps don't usually sleep in a cat's cradle. | ||
| 1107 | People who think they know everything greatly annoy us who do. | ||
| 1108 | People will buy anything that's one to a customer. | ||
| 1109 | Per omnia saecula vombatidae. | ||
| 1110 | Perfect day for scrubbing the floor and other exciting things. | ||
| 1111 | Perfect love casteth out fear. | ||
| 1112 | Person who falls in blast furnace is certain to feel overwrought. | ||
| 1113 | Personality is a flimsy thing on which to build an art. -John Cage | ||
| 1114 | Philosophy is the Rule of Life. | ||
| 1115 | Philosopy: unintelligible answers to insoluble problems. | ||
| 1116 | Physician, bill thyself. | ||
| 1117 | Planning dooms most projects. | ||
| 1118 | Please log off, the computer is out to get in your room and drink? | ||
| 1119 | Please log off, the computer is out to lunch. | ||
| 1120 | Please take note: | ||
| 1121 | Please to remember the Fifth of November, Gunpowder Treason and Plot. | ||
| 1122 | Plunk your magic twanger, froggy. | ||
| 1123 | Pluralites non est punenda sine necessitate. -Wm. of Occam | ||
| 1124 | Plus ça change, plus c'est la même chose. | ||
| 1125 | Politicians, ugly buildings and whores all get respectable if they last long enough. | ||
| 1126 | Populus vult decipi. | ||
| 1127 | Pornography is in the groin of the beholder. -William F. Buckley | ||
| 1128 | Post hoc, ergo propter hoc. | ||
| 1129 | Post proelium, praemium. | ||
| 1130 | Pregnant ropuli. | ||
| 1131 | Premature optimization is the root of all evil. -D. E. Knuth | ||
| 1132 | Preserve wildlife -- pickle a squirrel today! | ||
| 1133 | Prevention makes the heart grow fonder. | ||
| 1134 | Primate behaviour only changes under the impact of new technology. | ||
| 1135 | Pro is to con as progress is to Congress. | ||
| 1136 | Procrastination is the art of keeping up with yesterday. -Don Marquis | ||
| 1137 | Programming and puddings demand consistency. | ||
| 1138 | Progress is made on alternate Fridays. | ||
| 1139 | Promptness is its own reward, if one lives by the clock instead of the sword. | ||
| 1140 | Proofreading is more effective after publication. | ||
| 1141 | Proper planning includes admitting that your plan may not work. | ||
| 1142 | Pulchritude possesses solely cutaneous profundity. | ||
| 1143 | Put not your trust in money, but your money in trust. | ||
| 1144 | Put your mouth where your mouth is. | ||
| 1145 | Quantity is no substitute for quality, but it's the only one we've got. | ||
| 1146 | Quantum mechanics do it with uncertainty. | ||
| 1147 | Questions are a burden for others; answers are a prison for oneself. | ||
| 1148 | Rain before sunset, dark by midnight. | ||
| 1149 | Rainy days and Mondays always get me down. | ||
| 1150 | Reach out and grep someone. | ||
| 1151 | Reading is thinking with someone else's head instead of one's own. | ||
| 1152 | Real programmers can't say `lint' without adding `hbaxcu' -Wm Leler | ||
| 1153 | Real programs don't eat cache. | ||
| 1154 | Reality is for those who can't handle drugs. | ||
| 1155 | Reality is good for you...in small doses. | ||
| 1156 | Reality is silly-putty. -Paul Krassner | ||
| 1157 | Reality seems harsher in the early morning. | ||
| 1158 | Reason establishes the foundation of faith. Faith compensates the error of reason. | ||
| 1159 | Reason is a universal instrument which can serve on any kind of occasion. -Descartes | ||
| 1160 | Reform always comes from below. No man with four aces asks for a new deal. | ||
| 1161 | Regnant populi. | ||
| 1162 | Rei panta. | ||
| 1163 | Religions revolve madly around sexual questions. | ||
| 1164 | Remember that "almost" means "not". | ||
| 1165 | Remember the Unknown Buffalo. | ||
| 1166 | Remember when you asked me to tell you when you were being inconsiderate? | ||
| 1167 | Remember why the good Lord made your eyes -- Pla-gi-a-rize! -Tom Lehrer | ||
| 1168 | Remember, UNIX spelled backwards is XINU. | ||
| 1169 | Remember, even if you win the rat race -- you're still a rat. | ||
| 1170 | Render unto Caesar if line 54 is larger than line 62. | ||
| 1171 | Repetition is a form of change. -B. Eno | ||
| 1172 | Research is a great career: you get paid for looking, regardless of results. | ||
| 1173 | Respect you in the morning?! Hell, I don't even respect you now. | ||
| 1174 | Restrain your octopus! The canoes are going fishing tomorrow. | ||
| 1175 | Ring around the collar. | ||
| 1176 | Ring the bell; close the book; quench the candle. | ||
| 1177 | Ritual is to the inner sciences what experiment is to the outer sciences. -Leary | ||
| 1178 | Rog-O-Matic callidus est. | ||
| 1179 | Rog-O-Matic perditus est. | ||
| 1180 | Rog-O-Matic's not expert enough. It could handle rogue, but it couldn't handle More. | ||
| 1181 | Rotten wood can not be carved -Confucius (Analects, Book 5, Ch. 9) | ||
| 1182 | Round numbers are always false. -Samuel Johnson (c. 1750) | ||
| 1183 | Rule 5 Violation | ||
| 1184 | SCCS: the source-code motel -- your code checks in but it never checks out. Ken Thompson | ||
| 1185 | SYS ERROR 0 - no error detected | ||
| 1186 | Sailors in ships, sail on! Even while we died, others rode out the storm. | ||
| 1187 | Satire does not look pretty upon a tombstone. | ||
| 1188 | Save a forest -- eat a beaver! | ||
| 1189 | Save the dot files! | ||
| 1190 | Save yourself! Reboot in 5 seconds! | ||
| 1191 | Say "no" to long-sleeved shirts!! Support your right to bare arms! | ||
| 1192 | Say your prayers, you're going to Zen heaven. | ||
| 1193 | Schroedinger might have been here. | ||
| 1194 | Schroedinger's cat is sitting on Heisenberg's shoulder and they are both laughing at you. | ||
| 1195 | Scintillate, scintillate, aster minific. | ||
| 1196 | Screw up your courage! You've screwed up everything else. | ||
| 1197 | Secrecy is the beginning of tyranny. | ||
| 1198 | Secret mail has arrived. | ||
| 1199 | See that ocean -- that used to be some ocean. -Burt Lancaster in Atlantic City | ||
| 1200 | Seek not to understand that you may believe, but believe that you may understand. | ||
| 1201 | Self denial is better than self degradation. | ||
| 1202 | Sell everything. Market top has been reached. -Joseph Granville | ||
| 1203 | Send not to ask for whom the bell tolls; it tolls for thee. | ||
| 1204 | Señor, if you hurry from here, you will wait longer there. -Mexico taxi driver | ||
| 1205 | Sex with someone you don't love is just gymnastics--and I hate exercise. -John Derek | ||
| 1206 | Shadows slick as eels slither through. | ||
| 1207 | Share your happiness with others today. | ||
| 1208 | She canna take much more o' this, Mr. Spock. | ||
| 1209 | Shift to the left! Shift to the right! Pop up! Push Down! Byte, byte, byte! | ||
| 1210 | Show respect for age. Drink good Scotch for a change. | ||
| 1211 | Si nummi immunis. | ||
| 1212 | Silver is pure. It's been a symbol of justice and purity since the year of the sun. | ||
| 1213 | Sin has many tools, but a lie is the handle which fits them all. | ||
| 1214 | Sink or Swim with Teddy! | ||
| 1215 | Sleep is an excellent way of listening to an opera. | ||
| 1216 | Smile ... tomorrow will be worse. | ||
| 1217 | Smoked carp is terrible unless you're out of smoked salmon. | ||
| 1218 | Smooth rotation butters no parsnips. -J. W. Tukey | ||
| 1219 | Snatch the pebble from my hand, Grasshopper. | ||
| 1220 | Snob intellectual bachelors can't have fun in San Antonio. -Ted Nelson | ||
| 1221 | Snoopy has fleas. | ||
| 1222 | Snow Day -- stay home. | ||
| 1223 | So long as radicals honor theory over facts, they will continue to dismantle their successes. | ||
| 1224 | So narrow minded is the boss that he has to stack his ideas vertically. | ||
| 1225 | Social innovations tend to the level of minimum tolerable well being. | ||
| 1226 | Soft soap often has a high percentage of lye in it. -- Salada Tea | ||
| 1227 | Solve et coagule. | ||
| 1228 | Some books are to be tasted, others to be swallowed. -- Francis Bacon | ||
| 1229 | Some day this war's gonna end. | ||
| 1230 | Some men are discovered; others are found out. | ||
| 1231 | Some of us feel that there is a loss of scholarship here, and we're not too happy about it. -Irvin Lustig | ||
| 1232 | Some scholars are like donkeys, they merely carry a lot of books. | ||
| 1233 | Some things are better left unsaid. | ||
| 1234 | Sometimes a cigar is just a cigar. -Sigmund Freud | ||
| 1235 | Sometimes it seems to me that men are children grown incompetent. -Carl Whitaker | ||
| 1236 | Sometimes you've gotta give it all you've got, because it just isn't enough. | ||
| 1237 | Soon you will be sitting on top of the world. | ||
| 1238 | Sooner or later everybody's gotta pay their tab. | ||
| 1239 | Sorting on the part of mendicants must be interdicted. | ||
| 1240 | Space travel is utter bilge. -Sir Richard Van Der Riet Wolley | ||
| 1241 | Spare no expense to save money on this one. -Samuel Goldwyn | ||
| 1242 | Speaking of poison, I'll see that you get some fresh breakfast immediately. | ||
| 1243 | Specialization is for insects. -Robt. A. Heinlein | ||
| 1244 | Spend extra time on hobby. Get plenty of rolling papers. | ||
| 1245 | Split a stick of wood, and the Christ is there, too. | ||
| 1246 | Spock: We suffered 23 casualties in that attack, Captain. | ||
| 1247 | Stack overflow in crawlout. User environment re-initialized. (FATAL$) | ||
| 1248 | Standing on head makes smile of frown, but rest of face also upside down. | ||
| 1249 | Status: R | ||
| 1250 | Stay away from flying saucers today. | ||
| 1251 | Stay away from hurricanes for a while. | ||
| 1252 | Stereotypes are one of the worst things in the world. -miteddie!nessus | ||
| 1253 | Sticks and stones may break my bones, but a laser beam is another matter. | ||
| 1254 | Stop searching forever. Happiness is just next to you. | ||
| 1255 | Stop searching forever. Happiness is unattainable. | ||
| 1256 | Stop searching. Happiness is right next to you. | ||
| 1257 | Stop worrying, you'll never get out of this world alive. | ||
| 1258 | Subject: Re: Re: Clar ... HUMBUG! - Wrongthink st - (nf) | ||
| 1259 | Succumb to natural tendencies. Be hateful and boring. | ||
| 1260 | Sum quod eris. | ||
| 1261 | Sun UNIX 4.2 Release 1.1 (IAS) #1: Tue Jan 29 01:25:15 PST 1985 | ||
| 1262 | Sunday clears away the rust of the whole week. - Joseph Addison. | ||
| 1263 | Sure [Somoza]'s a son-of-a-bitch, but he's OUR son-of-a-bitch. -F.D. Roosevelt | ||
| 1264 | Surprise due today. Also the rent. | ||
| 1265 | Surprise your boss. Get to work on time. | ||
| 1266 | Surveillance should precede salientation. | ||
| 1267 | System down Tues. am for COBOL compiler installation. | ||
| 1268 | System going down at 1:45 this afternoon for disk crash. | ||
| 1269 | System going down for 5 minutes -- back up in barrels. | ||
| 1270 | System going down for 5 minutes -- back up in half an hour. | ||
| 1271 | System going down in 5 minutes. | ||
| 1272 | System might crash at any moment. | ||
| 1273 | System went down at Fri Dec 13 21:54:56 1901 | ||
| 1274 | TERROR IN THE OUTPUT FILE A A | ||
| 1275 | TNT allows students the freedom to make mistakes. | ||
| 1276 | TSO -- it may be slow, but it's hard to use. | ||
| 1277 | Tai Chi is self-defense for people on Quaaludes. | ||
| 1278 | Take care of the luxuries and the necessities will take care of themselves. | ||
| 1279 | Take care of your peonies and the dahlias will take care of themselves. | ||
| 1280 | Te ayudare a recorder la cantidad a indoctos si releesme bien. | ||
| 1281 | Teach it ... phenomenology. | ||
| 1282 | Technological unemployment is total today -- 300 years ago we were all farmers. | ||
| 1283 | Tell the girls to slice the ham thin. | ||
| 1284 | Ten years of rejection slips is nature's way of telling you to stop writing. | ||
| 1285 | Terminals at home are always in the bedroom. | ||
| 1286 | Thank God I'm an atheist. -Aleister Crowley | ||
| 1287 | Thank you for choosing UNIX -- batteries not included, some assembly required. | ||
| 1288 | That goes against the laws of Physics. | ||
| 1289 | That must be wonderful! I don't understand it at all. | ||
| 1290 | That we can comprehend the little we know already is mindboggling in itself. | ||
| 1291 | That which does not kill me makes me stronger. | ||
| 1292 | That which does not kill me missed. | ||
| 1293 | That which is above is in that which is below. | ||
| 1294 | That's as American as pie charts. | ||
| 1295 | That's the nice thing about standards -- there's so many to choose from. -trb | ||
| 1296 | The $SIGNON command is a risky practice. | ||
| 1297 | The 3B2 Model 100 - the first machine with cat -v in ROM! | ||
| 1298 | The Angels want to wear my red shoes. | ||
| 1299 | The Beatles? Isn't that Paul McCartney's old band? | ||
| 1300 | The Blit is a nice terminal, but it runs emacs. | ||
| 1301 | The Constitution gives us freedom of religion, not freedom from religion -R Reagan | ||
| 1302 | The Emperor is not as forgiving as I am. | ||
| 1303 | The Force is strong with this one. | ||
| 1304 | The Force is with you, young Skywalker, but you are not a Jedi yet. | ||
| 1305 | The Government urges you to remain calm. | ||
| 1306 | The Inuit have dozens of words for snow, so why do the Dutch only have one word for rain? | ||
| 1307 | The Italians make money out of funding their own deficit. | ||
| 1308 | The Luddites always lose. Always. | ||
| 1309 | The Moral Majority are the people our ancestors came from Europe to escape. | ||
| 1310 | The PIXAR -- it's not just a job, it's an adventure. | ||
| 1311 | The SUN really is a hunk of junk. - Tom Duff | ||
| 1312 | The Tao which can be talked about is not the Tao. -Lao Tzu | ||
| 1313 | The Tree of Learning bears the noblest fruit, but noble fruit tastes bad. | ||
| 1314 | The UFO and the BVM seem to be the same phenomenon. -Jacques Vallee | ||
| 1315 | The UNIX system is harder to use than a toaster. -Kaare Christian | ||
| 1316 | The United States Army: 194 years of proud service, unhampered by progress. | ||
| 1317 | The aim of existence is to have clean ideas, change them like shirts. | ||
| 1318 | The aim of existence is to offer resistance to the flow of time. | ||
| 1319 | The answer you seek is in an envelope. | ||
| 1320 | The attacker must vanquish; the defender need only survive. | ||
| 1321 | The average legislator is somewhere nearly all the time. -Herb Nore | ||
| 1322 | The barge was in my blind spot. - Peter Hobson, Cambridge cox | ||
| 1323 | The best prophet of the future is the past. | ||
| 1324 | The better part of valour is discretion; in the which better part I have saved my life. | ||
| 1325 | The boundary condition of the universe is that it has no boundary. - S. Hawking | ||
| 1326 | The check is in the mail. | ||
| 1327 | The churches must learn humility as well as teach it. | ||
| 1328 | The common Welsh name Bzjxxllwcp is pronounced Jackson. | ||
| 1329 | The connotation depends on the beacon. - Mark V. Shaney | ||
| 1330 | The contrary of a compound is the aggregate of the contraries of the components. - De Morgan | ||
| 1331 | The contrary of an aggregate is the compound of the contraries of the aggregates. - De Morgan | ||
| 1332 | The coroner gave you a clean bill of health. | ||
| 1333 | The darkest hour is just before the storm. | ||
| 1334 | The dawning of the Information Age is bringing about dramatic changes in the fundamental fabric of our civilization. - AA Penzias | ||
| 1335 | The decision doesn't have to be logical, it was unanimous. | ||
| 1336 | The difference between a thief and the IRS is that the thief doesn't audit you afterwards. | ||
| 1337 | The difficult we gave up on yesterday, the impossible we are giving up on now. | ||
| 1338 | The early bird gets the coffee left over from the night before. | ||
| 1339 | The early worm gets the bird. | ||
| 1340 | The earth is like a tiny grain of sand, only much, much heavier. | ||
| 1341 | The empty fist always makes the deepest wound. | ||
| 1342 | The end is closer than you think. | ||
| 1343 | The end justifies the meanness. | ||
| 1344 | The enemy is ignorance [our own]. -Ezra Pound | ||
| 1345 | The eyes believe themselves, the ears believe other people. | ||
| 1346 | The fear of the lord was discovered before vitamins. | ||
| 1347 | The first piece of luggage out of the chute doesn't belong to anyone, ever. | ||
| 1348 | The first step in fixing something is getting it to break. | ||
| 1349 | The first thing we do, let's kill all the lawyers. - Henry VI, part II. | ||
| 1350 | The fit between the world and the human symbols describing it is never perfect. | ||
| 1351 | The following file systems are due for backup at this time: | ||
| 1352 | The fruits of impatience are bitter. | ||
| 1353 | The function of the sun is not to help the cabbages along. - Flaubert | ||
| 1354 | The further you get, the better it looks. | ||
| 1355 | The future isn't what it used to be. (It never was.) | ||
| 1356 | The future isn't what it used to be. -Arthur C. Clarke | ||
| 1357 | The gods do not protect fools. Fools are protected by more capable fools. | ||
| 1358 | The hardest job kids face today is learning good manners without seeing any. | ||
| 1359 | The hardest part of raising children is teaching them to ride bicycles. | ||
| 1360 | The hippo has no sting, but the wise man would rather be sat upon by the bee. | ||
| 1361 | The human brain is not a pretty sight. | ||
| 1362 | The human mind treats a new idea the way the body treats a strange protein - it rejects it. -Peter Medawar | ||
| 1363 | The invention of the multiple-choice exam was the death blow to competent writing. | ||
| 1364 | The judge's jokes are always funny. | ||
| 1365 | The ketchup of sorrow is better than the mustard of happiness. | ||
| 1366 | The last twenty-nine days of the month are the worst. -Nicola Tesla | ||
| 1367 | The lion will lie down with the lamb, but the lamb won't get much sleep. | ||
| 1368 | The love of money is the mucilage of many a tragic friendship -Stuart McMillan | ||
| 1369 | The man of knowledge can see several things at once. | ||
| 1370 | The map is not the territory. -A. E. Van Vogt, in World of Null-A | ||
| 1371 | The measure of the rigor of a science is the index of its ability to predict. | ||
| 1372 | The meek shall inherit the earth -- they are careful to hide the fact. | ||
| 1373 | The meek shall inherit the earth -- they are pronounced "o". | ||
| 1374 | The meek shall inherit the earth -- they are too weak to refuse. | ||
| 1375 | The more complicated the mind, the more simple the play. | ||
| 1376 | The more things change, the more they'll never be the same again. | ||
| 1377 | The more you run over a dead cat, the flatter it gets. | ||
| 1378 | The move of bambam functionality to the new AP bugs is re-scheduled to Friday night | ||
| 1379 | The nervous system sees no color, feels no pain. -T. Leary | ||
| 1380 | The null string has always been a locksmith. -Albert Einstein | ||
| 1381 | The null string has always been a productive source of off-by-0 errors. | ||
| 1382 | The number of UNIX installations has grown to 10, with more expected. - 2nd Edition UNIX manual | ||
| 1383 | The number of approved [COBOL] subsets has been reduced from 104,976 to 54. - JM Triance | ||
| 1384 | The official state animal of New York is the cabbie. | ||
| 1385 | The official state tree of North Dakota is the telephone pole? | ||
| 1386 | The one interesting fact about the Diplodocus is that the accent is on the second syllable. | ||
| 1387 | The only imperfect thing in nature is the human race. | ||
| 1388 | The only one who got everything done by Friday was Robinson Crusoe. | ||
| 1389 | The only people who listen to both sides of an argument are the neighbors. | ||
| 1390 | The only sure things in life are net.suicide and net.taxes. | ||
| 1391 | The only thing cheaper than hardware is talk. | ||
| 1392 | The only way out of a circle is through the center. | ||
| 1393 | The opera isn't over until the fat lady sings. | ||
| 1394 | The opposite of a trivial truth is false; the opposite of a great truth is also true. | ||
| 1395 | The pale companion is not for our pomp. | ||
| 1396 | The pearl the squirrel the girl hit bit split. | ||
| 1397 | The planes in Spain fall mainly in the rain. | ||
| 1398 | The play's the thing/Wherein I'll catch the conscience of the king. | ||
| 1399 | The plural of spouse is spice. | ||
| 1400 | The polhode rolls without slipping on the herpolhode lying in the invariable plane. | ||
| 1401 | The problem with a just economy is, who runs the Bureau of Economic Justice? | ||
| 1402 | The prudent man does not hold his breath. | ||
| 1403 | The reason Swedes put little o's over some A's is that ontology recapitulates philology. | ||
| 1404 | The reason Swedes put little o's over some A's is that they are pronounced "o". | ||
| 1405 | The religion that is afraid of science dishonors God and commits suicide. | ||
| 1406 | The rich man has his motor car, His country and his town estate. He smokes a fifty-cent cigar And jeers at Fate. - F. P. Adams | ||
| 1407 | The screen rectangle must be charged with emotion. Hitchcock | ||
| 1408 | The sheep - symbolic creature of docility, sacrifice and stupidity. | ||
| 1409 | The shorter the line, the slower it moves. | ||
| 1410 | The shortest distance between two points is off the wall. | ||
| 1411 | The shortest distance between two points is under construction. -Noelie Altito | ||
| 1412 | The skeletons in the cupboard will all come out in the wash. | ||
| 1413 | The solution to the problem of life is seen in the vanishing of the problem. | ||
| 1414 | The sooner you fall behind, the more time you have to catch up. | ||
| 1415 | The stapler runs out of staples only while you are trying to staple something. | ||
| 1416 | The sterile pleasure of being right tends to get stale in the course of a lifetime. EW Dijkstra | ||
| 1417 | The strength of a nation lies in the integrity of its homes. -Confucius | ||
| 1418 | The stylus is more potent than the claymore. | ||
| 1419 | The sword he sang a song of death/But could not make the sickle yield. -Blake | ||
| 1420 | The thing about Chinatown is, you can never be sure of anything down there. | ||
| 1421 | The three laws of physics: f=ma; things fall down; you can't push a rope. | ||
| 1422 | The tide of change approaches. | ||
| 1423 | The time is right to make new friends. | ||
| 1424 | The unexamined life is not worth examining. | ||
| 1425 | The universe is laughing behind your back. | ||
| 1426 | The vanity of teaching often tempteth a man to forget that he is a blockhead. | ||
| 1427 | The voice of the people is odd,/It is, and it is not, the voice of God. -Pope | ||
| 1428 | The wheels of justice grind slow but fine. | ||
| 1429 | The whole UNIX operating system was ripped off electronically. | ||
| 1430 | The whole UNIX operating system whose documentation fits in a chinese computer terminal! | ||
| 1431 | The wise shepherdess never trusts her flock to a smiling wolf. | ||
| 1432 | The world cannot be understood from a single point of view. -Eleanor Roosevelt | ||
| 1433 | The world ended yesterday-this is only a dream! | ||
| 1434 | The world ended yesterday-why are you still here? | ||
| 1435 | The world is a conspiracy of the unthinking against the unwitting. | ||
| 1436 | The world is all that is the case. -Wittgenstein | ||
| 1437 | The world is coming to an end! Repent and return those library books! | ||
| 1438 | Them that dishes it out need not fall over every time someone blows hard. | ||
| 1439 | There are more old drunkards than old doctors. | ||
| 1440 | There are more things in heaven and earth, Horatio,/Than are dreamt of in your philosophy. | ||
| 1441 | There are more ways of killing a cat than choking her with cream. | ||
| 1442 | There are no color bars in Cuba. | ||
| 1443 | There are only three kinds of proof: induction, exhaustion, and intimidation. | ||
| 1444 | There are two kinds of people in the world -- those who are, and those who aren't. | ||
3791 more lines aren’t shown here.
Binary file not shown.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 48 lines aren’t shown here.
This diff is large: its 2 lines aren’t shown here.
This diff is large: its 2 lines aren’t shown here.
This diff is large: its 4 lines aren’t shown here.
This diff is large: its 60 lines aren’t shown here.
This diff is large: its 96 lines aren’t shown here.
This diff is large: its 6 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 26 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 4 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 13 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 13 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 15 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 6 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 3 lines aren’t shown here.
This diff is large: its 2 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 3 lines aren’t shown here.
This diff is large: its 99 lines aren’t shown here.
This diff is large: its 15 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 339 lines aren’t shown here.
This diff is large: its 338 lines aren’t shown here.
This diff is large: its 6 lines aren’t shown here.
This diff is large: its 12 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 30 lines aren’t shown here.
This diff is large: its 36 lines aren’t shown here.
This diff is large: its 42 lines aren’t shown here.
This diff is large: its 48 lines aren’t shown here.
This diff is large: its 54 lines aren’t shown here.
This diff is large: its 7 lines aren’t shown here.
This diff is large: its 12 lines aren’t shown here.
This diff is large: its 13 lines aren’t shown here.
This diff is large: its 7 lines aren’t shown here.
This diff is large: its 7 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 160 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 13 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 15 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 160 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 7 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 98 lines aren’t shown here.
This diff is large: its 4 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 53 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 13 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 15 lines aren’t shown here.
This diff is large: its 35 lines aren’t shown here.
This diff is large: its 13 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 4 lines aren’t shown here.
This diff is large: its 6 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 6 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 4 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 79 lines aren’t shown here.
This diff is large: its 15 lines aren’t shown here.
This diff is large: its 15 lines aren’t shown here.
This diff is large: its 21 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 26 lines aren’t shown here.
This diff is large: its 13 lines aren’t shown here.
This diff is large: its 35 lines aren’t shown here.
This diff is large: its 6 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 73 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 7 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 4 lines aren’t shown here.
This diff is large: its 97 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 12 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 3 lines aren’t shown here.
This diff is large: its 4 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 3 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 7 lines aren’t shown here.
This diff is large: its 7 lines aren’t shown here.
This diff is large: its 13 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 92 lines aren’t shown here.
This diff is large: its 4 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 35 lines aren’t shown here.
This diff is large: its 40 lines aren’t shown here.
This diff is large: its 15 lines aren’t shown here.
This diff is large: its 28 lines aren’t shown here.
This diff is large: its 33 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 6 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 2 lines aren’t shown here.
This diff is large: its 4 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 57 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 12 lines aren’t shown here.
This diff is large: its 49 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 4 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 7 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 4 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 34 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 71 lines aren’t shown here.
This diff is large: its 4 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 64 lines aren’t shown here.
This diff is large: its 7 lines aren’t shown here.
This diff is large: its 7 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 7 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 6 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 6 lines aren’t shown here.
This diff is large: its 6 lines aren’t shown here.
This diff is large: its 6 lines aren’t shown here.
This diff is large: its 26 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
This diff is large: its 12 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 15 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
This diff is large: its 31 lines aren’t shown here.
This diff is large: its 28 lines aren’t shown here.
This diff is large: its 6 lines aren’t shown here.
This diff is large: its 7 lines aren’t shown here.
This diff is large: its 7 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 6 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 7 lines aren’t shown here.
This diff is large: its 3 lines aren’t shown here.
This diff is large: its 7 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 30 lines aren’t shown here.
This diff is large: its 30 lines aren’t shown here.
This diff is large: its 6 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 31 lines aren’t shown here.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
This diff is large: its 82 lines aren’t shown here.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
This diff is large: its 1550 lines aren’t shown here.
This diff is large: its 1522 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 44 lines aren’t shown here.
This diff is large: its 100 lines aren’t shown here.
This diff is large: its 452 lines aren’t shown here.
This diff is large: its 832 lines aren’t shown here.
This diff is large: its 38 lines aren’t shown here.
This diff is large: its 32 lines aren’t shown here.
This diff is large: its 383 lines aren’t shown here.
This diff is large: its 515 lines aren’t shown here.
This diff is large: its 96 lines aren’t shown here.
This diff is large: its 12 lines aren’t shown here.
This diff is large: its 308 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
This diff is large: its 371 lines aren’t shown here.
This diff is large: its 482 lines aren’t shown here.
This diff is large: its 388 lines aren’t shown here.
This diff is large: its 1346 lines aren’t shown here.
This diff is large: its 53 lines aren’t shown here.
This diff is large: its 702 lines aren’t shown here.
This diff is large: its 124 lines aren’t shown here.
This diff is large: its 434 lines aren’t shown here.
This diff is large: its 139 lines aren’t shown here.
This diff is large: its 53 lines aren’t shown here.
This diff is large: its 1094 lines aren’t shown here.
This diff is large: its 65 lines aren’t shown here.
This diff is large: its 761 lines aren’t shown here.
This diff is large: its 149 lines aren’t shown here.
This diff is large: its 214 lines aren’t shown here.
This diff is large: its 52 lines aren’t shown here.
This diff is large: its 70 lines aren’t shown here.
This diff is large: its 56 lines aren’t shown here.
This diff is large: its 224 lines aren’t shown here.
This diff is large: its 39 lines aren’t shown here.
This diff is large: its 323 lines aren’t shown here.
This diff is large: its 40 lines aren’t shown here.
This diff is large: its 297 lines aren’t shown here.
This diff is large: its 67 lines aren’t shown here.
This diff is large: its 73 lines aren’t shown here.
This diff is large: its 67 lines aren’t shown here.
This diff is large: its 739 lines aren’t shown here.
This diff is large: its 54 lines aren’t shown here.
This diff is large: its 302 lines aren’t shown here.
This diff is large: its 72 lines aren’t shown here.
This diff is large: its 1677 lines aren’t shown here.
This diff is large: its 80 lines aren’t shown here.
This diff is large: its 355 lines aren’t shown here.
This diff is large: its 197 lines aren’t shown here.
This diff is large: its 639 lines aren’t shown here.
This diff is large: its 67 lines aren’t shown here.
This diff is large: its 13 lines aren’t shown here.
This diff is large: its 162 lines aren’t shown here.
This diff is large: its 46 lines aren’t shown here.
This diff is large: its 524 lines aren’t shown here.
This diff is large: its 116 lines aren’t shown here.
This diff is large: its 145 lines aren’t shown here.
This diff is large: its 107 lines aren’t shown here.
This diff is large: its 373 lines aren’t shown here.
This diff is large: its 64 lines aren’t shown here.
This diff is large: its 4665 lines aren’t shown here.
This diff is large: its 1340 lines aren’t shown here.
This diff is large: its 56 lines aren’t shown here.
This diff is large: its 43 lines aren’t shown here.
This diff is large: its 61 lines aren’t shown here.
This diff is large: its 55 lines aren’t shown here.
This diff is large: its 102 lines aren’t shown here.
This diff is large: its 59 lines aren’t shown here.
This diff is large: its 65 lines aren’t shown here.
This diff is large: its 51 lines aren’t shown here.
This diff is large: its 1879 lines aren’t shown here.
This diff is large: its 68 lines aren’t shown here.
This diff is large: its 476 lines aren’t shown here.
This diff is large: its 66 lines aren’t shown here.
This diff is large: its 83 lines aren’t shown here.
This diff is large: its 49 lines aren’t shown here.
This diff is large: its 58 lines aren’t shown here.
This diff is large: its 53 lines aren’t shown here.
This diff is large: its 143 lines aren’t shown here.
This diff is large: its 336 lines aren’t shown here.
This diff is large: its 536 lines aren’t shown here.
This diff is large: its 2047 lines aren’t shown here.
This diff is large: its 548 lines aren’t shown here.
This diff is large: its 919 lines aren’t shown here.
This diff is large: its 42 lines aren’t shown here.
This diff is large: its 362 lines aren’t shown here.
This diff is large: its 292 lines aren’t shown here.
This diff is large: its 1338 lines aren’t shown here.
This diff is large: its 837 lines aren’t shown here.
This diff is large: its 991 lines aren’t shown here.
This diff is large: its 296 lines aren’t shown here.
This diff is large: its 315 lines aren’t shown here.
This diff is large: its 865 lines aren’t shown here.
This diff is large: its 83 lines aren’t shown here.
This diff is large: its 585 lines aren’t shown here.
This diff is large: its 52 lines aren’t shown here.
This diff is large: its 690 lines aren’t shown here.
This diff is large: its 47 lines aren’t shown here.
This diff is large: its 350 lines aren’t shown here.
This diff is large: its 1355 lines aren’t shown here.
This diff is large: its 560 lines aren’t shown here.
This diff is large: its 643 lines aren’t shown here.
This diff is large: its 133 lines aren’t shown here.
This diff is large: its 148 lines aren’t shown here.
This diff is large: its 45 lines aren’t shown here.
This diff is large: its 387 lines aren’t shown here.
This diff is large: its 581 lines aren’t shown here.
This diff is large: its 73 lines aren’t shown here.
This diff is large: its 854 lines aren’t shown here.
This diff is large: its 63 lines aren’t shown here.
This diff is large: its 491 lines aren’t shown here.
This diff is large: its 744 lines aren’t shown here.
This diff is large: its 116 lines aren’t shown here.
This diff is large: its 54 lines aren’t shown here.
This diff is large: its 807 lines aren’t shown here.
This diff is large: its 173 lines aren’t shown here.
This diff is large: its 452 lines aren’t shown here.
This diff is large: its 88 lines aren’t shown here.
This diff is large: its 727 lines aren’t shown here.
This diff is large: its 45 lines aren’t shown here.
This diff is large: its 63 lines aren’t shown here.
This diff is large: its 49 lines aren’t shown here.
This diff is large: its 139 lines aren’t shown here.
This diff is large: its 992 lines aren’t shown here.
This diff is large: its 73 lines aren’t shown here.
This diff is large: its 805 lines aren’t shown here.
This diff is large: its 110 lines aren’t shown here.
This diff is large: its 229 lines aren’t shown here.
This diff is large: its 290 lines aren’t shown here.
This diff is large: its 294 lines aren’t shown here.
This diff is large: its 227 lines aren’t shown here.
This diff is large: its 1469 lines aren’t shown here.
This diff is large: its 87 lines aren’t shown here.
This diff is large: its 2131 lines aren’t shown here.
This diff is large: its 93 lines aren’t shown here.
This diff is large: its 494 lines aren’t shown here.
This diff is large: its 120 lines aren’t shown here.
This diff is large: its 577 lines aren’t shown here.
This diff is large: its 79 lines aren’t shown here.
This diff is large: its 1845 lines aren’t shown here.
This diff is large: its 55 lines aren’t shown here.
This diff is large: its 467 lines aren’t shown here.
This diff is large: its 87 lines aren’t shown here.
This diff is large: its 21 lines aren’t shown here.
This diff is large: its 1662 lines aren’t shown here.
This diff is large: its 485 lines aren’t shown here.
This diff is large: its 555 lines aren’t shown here.
This diff is large: its 161 lines aren’t shown here.
This diff is large: its 124 lines aren’t shown here.
This diff is large: its 29 lines aren’t shown here.
This diff is large: its 492 lines aren’t shown here.
This diff is large: its 591 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 342 lines aren’t shown here.
This diff is large: its 165 lines aren’t shown here.
This diff is large: its 380 lines aren’t shown here.
This diff is large: its 1285 lines aren’t shown here.
This diff is large: its 157 lines aren’t shown here.
This diff is large: its 227 lines aren’t shown here.
This diff is large: its 29 lines aren’t shown here.
This diff is large: its 475 lines aren’t shown here.
This diff is large: its 640 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 796 lines aren’t shown here.
This diff is large: its 166 lines aren’t shown here.
This diff is large: its 91 lines aren’t shown here.
This diff is large: its 532 lines aren’t shown here.
This diff is large: its 218 lines aren’t shown here.
This diff is large: its 447 lines aren’t shown here.
This diff is large: its 335 lines aren’t shown here.
This diff is large: its 150 lines aren’t shown here.
This diff is large: its 100 lines aren’t shown here.
This diff is large: its 234 lines aren’t shown here.
This diff is large: its 115 lines aren’t shown here.
This diff is large: its 21 lines aren’t shown here.
This diff is large: its 239 lines aren’t shown here.
This diff is large: its 1182 lines aren’t shown here.
This diff is large: its 98 lines aren’t shown here.
This diff is large: its 21 lines aren’t shown here.
This diff is large: its 342 lines aren’t shown here.
This diff is large: its 438 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 398 lines aren’t shown here.
This diff is large: its 455 lines aren’t shown here.
This diff is large: its 822 lines aren’t shown here.
This diff is large: its 393 lines aren’t shown here.
This diff is large: its 251 lines aren’t shown here.
This diff is large: its 341 lines aren’t shown here.
This diff is large: its 32 lines aren’t shown here.
This diff is large: its 71 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 71 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 71 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 71 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 71 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 71 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 71 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 71 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 71 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 71 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 70 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 70 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 70 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 70 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 70 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 70 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 70 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 70 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 70 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 70 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 70 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 145 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 70 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 70 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 765 lines aren’t shown here.
This diff is large: its 62 lines aren’t shown here.
This diff is large: its 70 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 145 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 145 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
This diff is large: its 2 lines aren’t shown here.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
This diff is large: its 2 lines aren’t shown here.
Binary file not shown.
This diff is large: its 145 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 70 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 71 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 70 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 145 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 70 lines aren’t shown here.
This diff is large: its 250 lines aren’t shown here.
This diff is large: its 13 lines aren’t shown here.
This diff is large: its 14 lines aren’t shown here.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
This diff is large: its 58 lines aren’t shown here.
This diff is large: its 158 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 121 lines aren’t shown here.
This diff is large: its 31 lines aren’t shown here.
This diff is large: its 5 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 1092 lines aren’t shown here.
This diff is large: its 298 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 153 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 758 lines aren’t shown here.
This diff is large: its 7 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 118 lines aren’t shown here.
This diff is large: its 617 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 490 lines aren’t shown here.
This diff is large: its 7 lines aren’t shown here.
This diff is large: its 45 lines aren’t shown here.
This diff is large: its 6 lines aren’t shown here.
This diff is large: its 215 lines aren’t shown here.
This diff is large: its 52 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 101 lines aren’t shown here.
This diff is large: its 893 lines aren’t shown here.
This diff is large: its 95 lines aren’t shown here.
This diff is large: its 6 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 374 lines aren’t shown here.
This diff is large: its 148 lines aren’t shown here.
This diff is large: its 21 lines aren’t shown here.
This diff is large: its 92 lines aren’t shown here.
This diff is large: its 47 lines aren’t shown here.
This diff is large: its 310 lines aren’t shown here.
This diff is large: its 454 lines aren’t shown here.
This diff is large: its 109 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 34 lines aren’t shown here.
This diff is large: its 558 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 338 lines aren’t shown here.
This diff is large: its 345 lines aren’t shown here.
This diff is large: its 146 lines aren’t shown here.
This diff is large: its 436 lines aren’t shown here.
This diff is large: its 1053 lines aren’t shown here.
This diff is large: its 85 lines aren’t shown here.
This diff is large: its 648 lines aren’t shown here.
This diff is large: its 31 lines aren’t shown here.
This diff is large: its 656 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 955 lines aren’t shown here.
This diff is large: its 413 lines aren’t shown here.
This diff is large: its 749 lines aren’t shown here.
This diff is large: its 195 lines aren’t shown here.
This diff is large: its 23 lines aren’t shown here.
This diff is large: its 61 lines aren’t shown here.
This diff is large: its 125 lines aren’t shown here.
This diff is large: its 102 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 137 lines aren’t shown here.
This diff is large: its 281 lines aren’t shown here.
This diff is large: its 379 lines aren’t shown here.
This diff is large: its 120 lines aren’t shown here.
This diff is large: its 437 lines aren’t shown here.
This diff is large: its 201 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 423 lines aren’t shown here.
This diff is large: its 56 lines aren’t shown here.
This diff is large: its 892 lines aren’t shown here.
This diff is large: its 25 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.