Mercurial > ~darius > hgwebdir.cgi > mservtk
comparison mservtk.tcl @ 1:c36994199c5e MSERVTK_0_1
Initial revision
author | darius |
---|---|
date | Wed, 03 May 2000 12:20:47 +0000 |
parents | |
children | 4343bc7f829a |
comparison
equal
deleted
inserted
replaced
0:c5aa7d041ea8 | 1:c36994199c5e |
---|---|
1 #!/usr/bin/env wish8.0 | |
2 | |
3 # | |
4 # This software is copyright Daniel O'Connor (darius@dons.net.au) 2000 | |
5 # | |
6 # Redistribution and use in source and binary forms, with or without | |
7 # modification, are permitted provided that the following conditions | |
8 # are met: | |
9 # 1. Redistributions of source code must retain the above copyright | |
10 # notice, this list of conditions and the following disclaimer. | |
11 # 2. Redistributions in binary form must reproduce the above copyright | |
12 # notice, this list of conditions and the following disclaimer in the | |
13 # documentation and/or other materials provided with the distribution. | |
14 # 3. Neither the name Daniel O'Connor nor the names of its contributors | |
15 # may be used to endorse or promote products derived from this software | |
16 # without specific prior written permission. | |
17 # | |
18 # THIS SOFTWARE IS PROVIDED BY DANIEL O'CONNOR AND CONTRIBUTORS ``AS IS'' AND | |
19 # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
20 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
21 # ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
22 # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
23 # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
24 # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
25 # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
26 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
27 # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
28 # SUCH DAMAGE. | |
29 # | |
30 | |
31 proc main {} { | |
32 global argv0 argv state albums songs; | |
33 | |
34 set state(exit) 0; | |
35 set state(host) "lot"; | |
36 set state(port) "4444"; | |
37 set state(user) "Darius"; | |
38 set state(pass) "Fnordish"; | |
39 set state(sortmode) "Title"; | |
40 set state(tmpphrase) ""; | |
41 | |
42 gui_build; | |
43 | |
44 con_mserv; | |
45 | |
46 con_getalbums albums; | |
47 con_getsongs songs albums; | |
48 | |
49 gui_updatesongs; | |
50 gui_updatequeue; | |
51 | |
52 update_timer; | |
53 | |
54 while {1} { | |
55 vwait state(exit); | |
56 | |
57 if {$state(exit) == 1} { | |
58 exit; | |
59 } | |
60 } | |
61 } | |
62 | |
63 proc quit_now {} { | |
64 global state; | |
65 | |
66 set state(exit) 1; | |
67 } | |
68 | |
69 proc gui_build {} { | |
70 # create the toplevel | |
71 eval destroy [winfo child .]; | |
72 wm title . "MServ-Tk"; | |
73 wm minsize . 600 500; | |
74 wm geometry . 600x500; | |
75 | |
76 # Let's have a menubar | |
77 frame .menubar -relief raised -bd 2; | |
78 pack .menubar -side top -fill x; | |
79 | |
80 # Add the File menu | |
81 menubutton .menubar.file -text "File" -menu .menubar.file.m -underline 0; | |
82 menu .menubar.file.m -tearoff 0; | |
83 .menubar.file.m add command -label " Quit" -command "quit_now" \ | |
84 -underline 2 -accelerator "Alt-q"; | |
85 pack .menubar.file -side left; | |
86 | |
87 # Add the Rate menu | |
88 menubutton .menubar.rate -text "Rate" -menu .menubar.rate.m -underline 0; | |
89 menu .menubar.rate.m -tearoff 0; | |
90 .menubar.rate.m add command -label " Superb" -command "rate_song SUPERB"; | |
91 .menubar.rate.m add command -label " Good" -command "rate_song GOOD"; | |
92 .menubar.rate.m add command -label " Neutral" -command "rate_song NEUTRAL"; | |
93 .menubar.rate.m add command -label " Bad" -command "rate_song BAD"; | |
94 .menubar.rate.m add command -label " Awful" -command "rate_song AWFUL"; | |
95 | |
96 pack .menubar.rate -side left; | |
97 | |
98 # Add the Control menu | |
99 menubutton .menubar.control -text "Control" -menu .menubar.control.m -underline 0; | |
100 menu .menubar.control.m -tearoff 0; | |
101 .menubar.control.m add command -label " Next" -command "control_player NEXT"; | |
102 .menubar.control.m add command -label " Pause" -command "control_player PAUSE"; | |
103 .menubar.control.m add command -label " Stop" -command "control_player STOP" | |
104 .menubar.control.m add command -label " Play" -command "control_player PLAY"; | |
105 | |
106 pack .menubar.control -side left; | |
107 | |
108 # Add the Volume menu | |
109 menubutton .menubar.vol -text "Volume" -menu .menubar.vol.m -underline 0; | |
110 menu .menubar.vol.m -tearoff 0; | |
111 .menubar.vol.m add command -label " Increase" -command "set_vol +3" \ | |
112 -accelerator "+"; | |
113 .menubar.vol.m add command -label " Decrease" -command "set_vol -3" \ | |
114 -accelerator "-"; | |
115 .menubar.vol.m add separator; | |
116 .menubar.vol.m add command -label " 100%" -command "set_vol 100"; | |
117 .menubar.vol.m add command -label " 90%" -command "set_vol 90"; | |
118 .menubar.vol.m add command -label " 80%" -command "set_vol 80"; | |
119 .menubar.vol.m add command -label " 70%" -command "set_vol 70"; | |
120 .menubar.vol.m add command -label " 60%" -command "set_vol 60"; | |
121 .menubar.vol.m add command -label " 50%" -command "set_vol 50"; | |
122 .menubar.vol.m add command -label " 40%" -command "set_vol 40"; | |
123 .menubar.vol.m add command -label " 30%" -command "set_vol 30"; | |
124 .menubar.vol.m add command -label " 20%" -command "set_vol 20"; | |
125 .menubar.vol.m add command -label " 10%" -command "set_vol 10"; | |
126 .menubar.vol.m add command -label " 0%" -command "set_vol 0"; | |
127 | |
128 pack .menubar.vol -side left; | |
129 | |
130 # Add the Sort menu | |
131 menubutton .menubar.sort -text "Sort" -menu .menubar.sort.m -underline 0; | |
132 menu .menubar.sort.m -tearoff 0; | |
133 .menubar.sort.m add command -label " Artist" \ | |
134 -command "global state; set state(sortmode) Artist; gui_updatesongs"; | |
135 .menubar.sort.m add command -label " Title" \ | |
136 -command "global state; set state(sortmode) Title; gui_updatesongs"; | |
137 .menubar.sort.m add command -label " Album" \ | |
138 -command "global state; set state(sortmode) Album; gui_updatesongs"; | |
139 | |
140 pack .menubar.sort -side left; | |
141 | |
142 # Add the Help menu | |
143 menubutton .menubar.help -text "Help" -menu .menubar.help.m -underline 0; | |
144 menu .menubar.help.m -tearoff 0; | |
145 .menubar.help.m add command -label " About" -command "about_box" \ | |
146 -underline 2; | |
147 pack .menubar.help -side right; | |
148 | |
149 # Top frame holding tracklist and trackinfo frames | |
150 frame .top -relief raised -bd 1; | |
151 pack .top -fill both -expand 1; | |
152 | |
153 # Tracklist | |
154 frame .top.tlist -relief raised -bd 1; | |
155 pack .top.tlist -side left -fill both -expand 1; | |
156 label .top.tlist.label -text "Track List"; | |
157 pack .top.tlist.label -side top -expand 0; | |
158 listbox .top.tlist.list -relief raised -borderwidth 2 \ | |
159 -yscrollcommand ".top.tlist.scr set"; | |
160 pack .top.tlist.list -side left -fill both -expand 1; | |
161 scrollbar .top.tlist.scr -command ".top.tlist.list yview"; | |
162 pack .top.tlist.scr -side right -fill y; | |
163 bind .top.tlist.list <Double-Button-1> { | |
164 queue_song [.top.tlist.list curselection]; | |
165 } | |
166 | |
167 # Trackinfo | |
168 frame .top.tinfo -relief raised -bd 1; | |
169 pack .top.tinfo -side right -fill both -expand 0; | |
170 label .top.tinfo.label -text "Track Info"; | |
171 pack .top.tinfo.label -side top -expand 0; | |
172 frame .top.tinfo.sub -relief raised -bd 1; | |
173 pack .top.tinfo.sub -side right -fill both -expand 0; | |
174 label .top.tinfo.sub.author -text "Author:"; | |
175 pack .top.tinfo.sub.author -side top -expand 0; | |
176 label .top.tinfo.sub.title -text "Title:"; | |
177 pack .top.tinfo.sub.title -side top -expand 0; | |
178 label .top.tinfo.sub.length -text "Length:"; | |
179 pack .top.tinfo.sub.length -side top -expand 0; | |
180 label .top.tinfo.sub.time -text "Time:"; | |
181 pack .top.tinfo.sub.time -side top -expand 0; | |
182 label .top.tinfo.sub.album -text "Album:"; | |
183 pack .top.tinfo.sub.album -side top -expand 0; | |
184 label .top.tinfo.sub.trackno -text "Misc:"; | |
185 pack .top.tinfo.sub.trackno -side top -expand 0; | |
186 label .top.tinfo.sub.vol -text "Volume:"; | |
187 pack .top.tinfo.sub.vol -side top -expand 0; | |
188 | |
189 # Queue (and the frame holding it) | |
190 frame .bot -relief raised -bd 1; | |
191 pack .bot -fill both -expand 1; | |
192 label .bot.qlabel -text "Queue"; | |
193 pack .bot.qlabel -side top -expand 0; | |
194 frame .bot.queue; | |
195 pack .bot.queue -fill both -expand 1; | |
196 listbox .bot.queue.list -relief raised -borderwidth 2 \ | |
197 -yscrollcommand ".bot.queue.scr set"; | |
198 pack .bot.queue.list -side left -fill both -expand 1; | |
199 scrollbar .bot.queue.scr -command ".bot.queue.list yview"; | |
200 pack .bot.queue.scr -side right -fill y; | |
201 bind .bot.queue.list <Double-Button-1> { | |
202 gui_delqueue [.bot.queue.list curselection]; | |
203 } | |
204 | |
205 bind . <Destroy> {quit_now}; | |
206 bind all <Alt-q> {quit_now}; | |
207 | |
208 bind all <KP_Add> {set_vol +3}; | |
209 bind all <KP_Subtract> {set_vol -3}; | |
210 bind all <plus> {set_vol +3}; | |
211 bind all <equal> {set_vol +3}; | |
212 bind all <minus> {set_vol -3}; | |
213 bind all <F1> {set_vol 10}; | |
214 bind all <F2> {set_vol 20}; | |
215 bind all <F3> {set_vol 30}; | |
216 bind all <F4> {set_vol 40}; | |
217 bind all <F5> {set_vol 50}; | |
218 bind all <F6> {set_vol 60}; | |
219 bind all <F7> {set_vol 70}; | |
220 bind all <F8> {set_vol 80}; | |
221 bind all <F9> {set_vol 90}; | |
222 bind all <F10> {set_vol 100}; | |
223 | |
224 bind all <Pause> {control_player PAUSE}; | |
225 bind all <End> {control_player NEXT}; | |
226 bind all <Delete> {control_player STOP}; | |
227 bind all <Home> {control_player PLAY}; | |
228 | |
229 update; | |
230 } | |
231 | |
232 proc queue_song {id} { | |
233 global songs state; | |
234 | |
235 set tmp [lindex [lindex [array get songs *:listid:$id] 1] 0]; | |
236 log "%s" "Queue - '$songs($tmp:name)' by '$songs($tmp:author)' ($tmp)"; | |
237 | |
238 n_write "QUEUE [split $tmp {:}]"; | |
239 n_getrtn rtn; | |
240 | |
241 if {$rtn(code) != 247} { | |
242 if {$rtn(code) == 510} { | |
243 msg_box "Queue" "You can't have the same\nsong in the queue twice!"; | |
244 } else { | |
245 log "Failed to queue track ($rtn(code) $rtn(data))"; | |
246 } | |
247 } | |
248 } | |
249 | |
250 proc msg_box {title msg} { | |
251 global state; | |
252 | |
253 catch {destroy .msg}; | |
254 | |
255 toplevel .msg -class Dialog; | |
256 wm title .msg $title; | |
257 wm iconname .msg $title; | |
258 | |
259 # text region | |
260 frame .msg.frame; | |
261 pack .msg.frame -side top -fill both -expand yes; | |
262 text .msg.frame.text -font fixed -height 10 -width 40 -yscroll ".msg.frame.scroll set" \ | |
263 -wrap none; | |
264 scrollbar .msg.frame.scroll -command ".msg.frame.text yview"; | |
265 pack .msg.frame.text -side left -expand y -fill both; | |
266 pack .msg.frame.scroll -side right -fill y; | |
267 | |
268 # close button | |
269 button .msg.close -text "Close" -command "destroy .msg"; | |
270 pack .msg.close -side bottom -fill x; | |
271 | |
272 # read text into the text widget | |
273 .msg.frame.text insert end $msg; | |
274 } | |
275 | |
276 proc about_box {} { | |
277 global state; | |
278 | |
279 catch {destroy .about}; | |
280 | |
281 toplevel .about -class Dialog; | |
282 wm title .about "About..."; | |
283 wm iconname .about "About"; | |
284 | |
285 # text region | |
286 frame .about.frame; | |
287 pack .about.frame -side top -fill both -expand yes; | |
288 text .about.frame.text -font fixed -height 10 -width 40 -yscroll ".about.frame.scroll set" \ | |
289 -wrap none; | |
290 scrollbar .about.frame.scroll -command ".about.frame.text yview"; | |
291 pack .about.frame.text -side left -expand y; | |
292 pack .about.frame.scroll -side right -fill y; | |
293 | |
294 # close button | |
295 button .about.close -text "Close" -command "destroy .about"; | |
296 pack .about.close -side bottom -fill x; | |
297 | |
298 # read text into the text widget | |
299 .about.frame.text insert end "Mserv Client\n"; | |
300 .about.frame.text insert end "Copyright Daniel O'Connor 2000\n"; | |
301 .about.frame.text insert end "\n"; | |
302 .about.frame.text insert end "http://www.dons.net.au/~darius/\n"; | |
303 } | |
304 | |
305 proc set_vol {vol} { | |
306 global state; | |
307 | |
308 n_write "VOLUME $vol" | |
309 n_getrtn rtn; | |
310 | |
311 if {$rtn(code) != 255} { | |
312 log "%s" "Couldn't set volume ($rtn(code) $rtn(data))"; | |
313 } | |
314 } | |
315 | |
316 proc rate_song {rate} { | |
317 global state; | |
318 | |
319 n_write "RATE $rate"; | |
320 n_getrtn rtn; | |
321 | |
322 if {$rtn(code) != 270} { | |
323 log "%s" "Failed to get rate song ($rtn(code) $rtn(data))"; | |
324 } | |
325 | |
326 } | |
327 | |
328 proc control_player {cmd} { | |
329 global state; | |
330 | |
331 n_write "$cmd"; | |
332 n_getrtn rtn; | |
333 | |
334 log "%s" "Control Got $rtn(code) $rtn(data)"; | |
335 } | |
336 | |
337 proc gui_updatesongs {} { | |
338 global state songs; | |
339 | |
340 .top.tlist.list delete 0 end; | |
341 | |
342 set tmp ""; | |
343 | |
344 foreach tag [array names songs "*:id"] { | |
345 set a $songs($tag); | |
346 lappend tmp [list $a $songs($a:name) $songs($a:author) $songs($a:albumname)]; | |
347 } | |
348 | |
349 switch -- $state(sortmode) { | |
350 "Title" { | |
351 set idx 1; | |
352 } | |
353 | |
354 "Artist" { | |
355 set idx 2; | |
356 } | |
357 | |
358 "Album" { | |
359 set idx 3; | |
360 } | |
361 | |
362 default { | |
363 set idx 1; | |
364 } | |
365 } | |
366 set tmp [lsort -dictionary -index $idx $tmp]; | |
367 | |
368 foreach a [array names songs *:listid:*] { | |
369 unset songs($a); | |
370 } | |
371 | |
372 set i 0; | |
373 foreach a $tmp { | |
374 .top.tlist.list insert end "'[lindex $a 1]' by '[lindex $a 2]' on '[lindex $a 3]'" | |
375 set songs([lindex $a 0]:listid:$i) $a; | |
376 incr i; | |
377 } | |
378 } | |
379 | |
380 proc gui_updatequeue {} { | |
381 global state songs queue; | |
382 | |
383 if {[info exists state(queuelock)]} { | |
384 return; | |
385 } | |
386 | |
387 set state(queuelock) ""; | |
388 | |
389 log "%s" "Updating queue"; | |
390 | |
391 .bot.queue.list delete 0 end; | |
392 | |
393 con_getqueue queue; | |
394 | |
395 foreach tag [lsort [array names queue]] { | |
396 .bot.queue.list insert end "'$songs($queue($tag):name)' by '$songs($queue($tag):author)' on '$songs($queue($tag):albumname)'"; | |
397 } | |
398 | |
399 unset state(queuelock); | |
400 } | |
401 | |
402 proc gui_delqueue {id} { | |
403 global queue; | |
404 | |
405 if {$id == ""} { | |
406 return; | |
407 } | |
408 | |
409 n_write "UNQUEUE [split $queue($id) {:}]"; | |
410 n_getrtn rtn; | |
411 | |
412 if {$rtn(code) != 254} { | |
413 log "%s" "Failed to remove $id ($queue($id))"; | |
414 msg_box "Queue" "Failed to dequeue the song"; | |
415 } | |
416 } | |
417 | |
418 proc gui_updateinfo {} { | |
419 global state; | |
420 | |
421 n_write "VOLUME"; | |
422 n_getrtn rtn; | |
423 | |
424 if {$rtn(code) != 235} { | |
425 set vol "??"; | |
426 } else { | |
427 set vol "[lindex [lindex $rtn(lines) 0] 0]"; | |
428 } | |
429 | |
430 n_write "INFO"; | |
431 n_getrtn rtn; | |
432 | |
433 if {$rtn(code) == 246} { | |
434 set data [split [lindex $rtn(lines) 0] "\t"]; | |
435 set author [lindex $data 4]; | |
436 set title [lindex $data 5]; | |
437 set length [lindex $data 14]; | |
438 set album [lindex $data 3]; | |
439 set tnum [lindex $data 15]; | |
440 } else { | |
441 set author "N/A"; | |
442 set title "N/A"; | |
443 set length "N/A"; | |
444 set album "N/A"; | |
445 set tnum "N/A"; | |
446 if {$rtn(code) != 401} { | |
447 log "%s" "Failed to get track info ($rtn(code) $rtn(data))"; | |
448 } | |
449 } | |
450 | |
451 | |
452 | |
453 n_write "STATUS"; | |
454 n_getrtn rtn; | |
455 | |
456 if {$rtn(code) != 222} { | |
457 set left "x:xx"; | |
458 set played "x:xx"; | |
459 } else { | |
460 set played [lindex [split [lindex $rtn(lines) 0] "\t"] 8]; | |
461 | |
462 # scan $played "%d:%d" played_m played_s; | |
463 # set played [expr ($played_m * 60) + $played_s]; | |
464 # scan $length "%d:%f" len_m len_s; | |
465 # set len [expr ($len_m * 60) + $len_s]; | |
466 | |
467 # set left [expr $len - $played]; | |
468 # set left_m [expr int($left / 60)]; | |
469 # set left [format "%02d:%02d" $left_m [expr int($left - ($left_m * 60))]]; | |
470 } | |
471 | |
472 .top.tinfo.sub.author configure -text "Author: $author"; | |
473 .top.tinfo.sub.title configure -text "Title: $title"; | |
474 .top.tinfo.sub.length configure -text "Length: $length"; | |
475 .top.tinfo.sub.time configure -text "Time: $played"; | |
476 .top.tinfo.sub.album configure -text "Album: $album"; | |
477 .top.tinfo.sub.trackno configure -text "Misc: $tnum"; | |
478 .top.tinfo.sub.vol configure -text "Volume: $vol"; | |
479 } | |
480 | |
481 proc con_getqueue {queuevar} { | |
482 upvar $queuevar queue; | |
483 | |
484 global state; | |
485 | |
486 catch {unset queue}; | |
487 | |
488 n_write "QUEUE" | |
489 n_getrtn rtn; | |
490 | |
491 if {$rtn(code) == 225} { | |
492 set i 0; | |
493 foreach line $rtn(lines) { | |
494 set foo [split $line \011]; | |
495 set id "[lindex $foo 1]:[lindex $foo 2]"; | |
496 | |
497 set queue($i) $id; | |
498 incr i; | |
499 } | |
500 } elseif {$rtn(code) == 404} { | |
501 log "%s" "Queue empty"; | |
502 } else { | |
503 log "%s" "Failed to get queue ($rtn(code) $rtn(data))"; | |
504 } | |
505 } | |
506 | |
507 proc con_getsongs {songsvar albumsvar} { | |
508 upvar $songsvar songs; | |
509 upvar $albumsvar albums; | |
510 | |
511 global state; | |
512 | |
513 catch { unset songs }; | |
514 | |
515 foreach i [array names albums "*:"] { | |
516 n_write "TRACKS $albums($i)"; | |
517 n_getrtn rtn; | |
518 if {$rtn(code) != "228"} { | |
519 error "Got bogus response to track request ($rtn(code) $rtn(data))"; | |
520 } | |
521 | |
522 foreach trk $rtn(lines) { | |
523 set foo [split $trk \011]; | |
524 if {[llength $foo] != 6} { | |
525 continue; | |
526 } | |
527 | |
528 set albid [lindex $foo 0]; | |
529 set num [lindex $foo 1] | |
530 set songs($albid:$num:id) "$albid:$num"; | |
531 set songs($albid:$num:author) [lindex $foo 2]; | |
532 set songs($albid:$num:name) [lindex $foo 3]; | |
533 set songs($albid:$num:rating) [lindex $foo 4]; | |
534 set songs($albid:$num:length) [lindex $foo 5]; | |
535 set songs($albid:$num:albumname) $albums($albid:name); | |
536 } | |
537 } | |
538 | |
539 } | |
540 | |
541 proc con_getalbums {albumsvar} { | |
542 upvar $albumsvar albums; | |
543 | |
544 global state; | |
545 | |
546 catch {unset albums}; | |
547 | |
548 n_write "ALBUMS"; | |
549 n_getrtn rtn; | |
550 if {$rtn(code) != 227} { | |
551 error "Server gave bogus response to album request ($rtn(code) $rtn(data))"; | |
552 } | |
553 | |
554 foreach alb $rtn(lines) { | |
555 set foo [split $alb \011]; | |
556 set id [lindex $foo 0]; | |
557 set albums($id:) [lindex $foo 0]; | |
558 set albums($id:author) [lindex $foo 1]; | |
559 set albums($id:name) [lindex $foo 2]; | |
560 | |
561 # log "%s" "Album $i, ID $albums($i:id) called $albums($i:name) by $albums($i:author)"; | |
562 } | |
563 } | |
564 | |
565 proc update_timer {} { | |
566 | |
567 gui_updateinfo; | |
568 | |
569 after 900 update_timer; | |
570 } | |
571 | |
572 proc con_mserv {} { | |
573 global state; | |
574 | |
575 # Close old FD | |
576 catch {close state(serv_fd)}; | |
577 catch {unset state(serv_fd)}; | |
578 | |
579 catch {fileevent $state(serv_fd) readable ""}; | |
580 set state(serv_fd) [ socket $state(host) $state(port) ]; | |
581 set state(pushbuf) ""; | |
582 fileevent $state(serv_fd) readable n_rtinput; | |
583 fconfigure $state(serv_fd) -blocking 0; | |
584 | |
585 # Greeting from server | |
586 n_getrtn rtn; | |
587 puts $rtn(data); | |
588 if {$rtn(code) != "200"} { | |
589 error "Server failed to send greeting"; | |
590 } | |
591 | |
592 # Login | |
593 n_write "USER $state(user)" | |
594 n_getrtn rtn; | |
595 if {$rtn(code) != "201"} { | |
596 error "Server failed to send password request"; | |
597 } | |
598 | |
599 n_write "PASS $state(pass) RTCOMPUTER"; | |
600 n_getrtn rtn; | |
601 if {$rtn(code) == "507"} { | |
602 error "Server rejected our credentials"; | |
603 } | |
604 | |
605 if {$rtn(code) != "202"} { | |
606 error "Unknown response to PASS command - $rtn(code) $rtn(data)" | |
607 } | |
608 | |
609 log "%s" "Logged in"; | |
610 } | |
611 | |
612 proc n_write {text} { | |
613 global state; | |
614 | |
615 puts $state(serv_fd) $text; | |
616 # log "%s" "Wrote - $text"; | |
617 | |
618 flush $state(serv_fd); | |
619 } | |
620 | |
621 proc n_rthandler {code data} { | |
622 global songs; | |
623 | |
624 log "%s" "Got RT - $code $data"; | |
625 | |
626 switch -- $code { | |
627 600 { | |
628 log "%s" "User '$data' connected"; | |
629 } | |
630 | |
631 601 { | |
632 log "%s" "User '$data' disconnected"; | |
633 } | |
634 | |
635 618 - | |
636 619 - | |
637 622 - | |
638 627 - | |
639 623 { | |
640 after idle gui_updatequeue; | |
641 } | |
642 } | |
643 } | |
644 | |
645 proc n_rtinput {} { | |
646 global state; | |
647 | |
648 set rth ""; | |
649 | |
650 set line [gets $state(serv_fd)]; | |
651 # log "%s" "Read - $line"; | |
652 | |
653 # Check for RT text | |
654 set foo [split $line "\t"]; | |
655 if {[string index $line 0] == "="} { | |
656 set rth [list [string range [lindex $foo 0] 1 3] [lrange $foo 1 end]]; | |
657 } else { | |
658 lappend state(tmpphrase) $line | |
659 if {$line == "."} { | |
660 set state(pushbuf) [linsert $state(pushbuf) 0 $state(tmpphrase)]; | |
661 set state(tmpphrase) ""; | |
662 } | |
663 } | |
664 | |
665 if {$rth != ""} { | |
666 n_rthandler [lindex $rth 0] [lindex $rth 1]; | |
667 } | |
668 } | |
669 | |
670 proc n_getrtn {var} { | |
671 upvar $var rtn; | |
672 global state; | |
673 | |
674 set gotcode 0; | |
675 catch {unset rtn(code)}; | |
676 catch {unset rtn(data)}; | |
677 catch {unset rtn(lines)} | |
678 | |
679 while {[llength $state(pushbuf)] == 0} { | |
680 vwait state(pushbuf); | |
681 } | |
682 | |
683 set buf [lindex $state(pushbuf) 0]; | |
684 set state(pushbuf) [lrange $state(pushbuf) 1 end]; | |
685 | |
686 while {1} { | |
687 if {[llength $buf] == 0} { | |
688 break; | |
689 } | |
690 | |
691 set line [lindex $buf 0]; | |
692 set buf [lrange $buf 1 end]; | |
693 | |
694 if {[string index $line 0] == "."} { | |
695 break; | |
696 } | |
697 | |
698 if {$gotcode == 0} { | |
699 set rtn(code) [string range $line 0 2]; | |
700 set rtn(data) [string range $line 4 end]; | |
701 set gotcode 1; | |
702 continue; | |
703 } | |
704 | |
705 lappend rtn(lines) $line; | |
706 } | |
707 | |
708 if {$gotcode == 0} { | |
709 log "%s" "Failed to parse phrase (got . before server responce)"; | |
710 } | |
711 } | |
712 | |
713 ################################################################## | |
714 # Log a message to stderr | |
715 # | |
716 proc log {format args} { | |
717 # Extract the calling function's name | |
718 set fname [lindex [info level -1] 0]; | |
719 | |
720 # Evaluate the supplied format string and arguments | |
721 if {[catch {set csm [eval format {$format} $args]} msg]} { | |
722 set csm "bad log message. format='$format' args='$args'"; | |
723 } | |
724 | |
725 # Emit the message | |
726 puts stderr "[clock format [clock seconds] -format {%y/%m/%d %H:%M:%S} -gmt yes]:$fname: $csm"; | |
727 flush stderr; | |
728 } | |
729 | |
730 main; |