kunt.go (19526B)
1 // Copyright 2013 TLH and dsp. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package main 6 7 import ( 8 "flag" 9 "fmt" 10 "games" 11 "io" 12 "io/ioutil" 13 "irc" 14 "log" 15 "mapfs" 16 "math/rand" 17 "net/http" 18 "os" 19 "os/exec" 20 "regexp" 21 "strings" 22 "syscall" 23 "time" 24 ) 25 26 type kuntCtx struct { 27 stime time.Time 28 ircCtx *irc.Context 29 } 30 31 func cmdKunt(msg irc.Message) { 32 replies := []string{ 33 "dn niotho maaaan", 34 "eimai kokalo telios... gama ta", 35 "pwpw gamise ta, den vlepo brosta mou", 36 "yoyoyoyo duuuuude", 37 "die", 38 "ok", 39 "maybe", 40 "yes", 41 } 42 if msg.Nick == "dsp" || msg.Nick == "TLH" || msg.Nick == "sovarofanis" { 43 replies = []string{ 44 "You are my Mastah!", 45 "I will always obey you my Mastah!", 46 "vv maaaaan", 47 "etimazo na stripso ena ro... ade vives", 48 "420 dawwwwwwg", 49 "You own all ma base niggah, chiiilll", 50 "spliff it up bro!", 51 } 52 } 53 if strings.Index(msg.Args[1], "vv") != -1 || 54 strings.Index(msg.Args[1], "vives") != -1 { 55 replies = []string{ 56 "vives alani", 57 "vv maaaan!!", 58 "skastoooo", 59 "vv http://www.youtube.com/watch?v=wHzxh9fneJ8 <-- varaeeiiiiii", 60 "vives!", 61 "vv!", 62 "vv dawg", 63 } 64 } 65 if strings.Index(msg.Args[1], "vi ") != -1 || 66 strings.Index(msg.Args[1], " vi") != -1 || 67 strings.Index(msg.Args[1], "vim ") != -1 || 68 strings.Index(msg.Args[1], " vim") != -1 { 69 replies = []string{ 70 "emax ftw", 71 "emacs ftw!", 72 "EMACS!", 73 "ed is the standard editor.", 74 "emax or die", 75 "mg or die", 76 "vi sux", 77 "vim sux ass", 78 } 79 } 80 idx := rand.Intn(len(replies)) 81 kunt.ircCtx.Privmsg(msg.Args[0], string(replies[idx])) 82 } 83 84 func cmdWisdom(msg irc.Message) { 85 out, err := exec.Command("./fortune").Output() 86 if err != nil { 87 log.Fatal(err) 88 } 89 lines := strings.Split(string(out), "\n") 90 for _, i := range lines { 91 if i == "" { 92 continue 93 } 94 kunt.ircCtx.Privmsg(msg.Args[0], i) 95 time.Sleep(512 * time.Millisecond) 96 } 97 } 98 99 func cmdHelp(msg irc.Message) { 100 help := []string{ 101 "!addquote <quote> -> Add a quote to the db", 102 "!randquote -> Print a random quote from the db", 103 "!countquotes -> Print the number of entries in the quote db", 104 "!addurl <url> -> Add a url to the db", 105 "!randurl -> Print a random url from the db", 106 "!counturls -> Print the number of entries in the url db", 107 "!uptime -> Show uptime", 108 "!wisdom -> Invoke fortune(6)", 109 "!radio -> Print now playing song", 110 "!game -> List or Play games", 111 "!src -> Fetch kunt's source code", 112 "!TODO -> Print the TODO list", 113 "!version -> Show version", 114 "!copyright -> Show copyright info", 115 } 116 for _, i := range help { 117 kunt.ircCtx.Privmsg(msg.Args[0], i) 118 time.Sleep(512 * time.Millisecond) 119 } 120 } 121 122 func cmdVersion(msg irc.Message) { 123 ver := "v0.2.9" 124 kunt.ircCtx.Privmsg(msg.Args[0], ver) 125 } 126 127 func cmdRandQuote(msg irc.Message) { 128 if quoteDb.Empty() { 129 kunt.ircCtx.Privmsg(msg.Args[0], "Empty quote database") 130 return 131 } 132 quote, idx := quoteDb.Rand() 133 quote = []byte(strings.TrimSpace(string(quote))) 134 // Print idx in red 135 text := fmt.Sprintf("%s%02d[%d]%s %s", 136 "\003", '5', idx, "\003", string(quote)) 137 kunt.ircCtx.Privmsg(msg.Args[0], text) 138 } 139 140 func cmdAddQuote(msg irc.Message) { 141 text := msg.Args[1] 142 if len(strings.Fields(text)) < 2 { 143 kunt.ircCtx.Privmsg(msg.Args[0], "Missing parameter for !addquote") 144 return 145 } 146 text = text[10:] 147 text = strings.TrimSpace(text) 148 text += "\n" 149 buf := []byte(text) 150 if quoteDb.CountMatches(buf) > 0 { 151 kunt.ircCtx.Privmsg(msg.Args[0], 152 fmt.Errorf("Duplicate entry: %s", buf).Error()) 153 return 154 } 155 _, err := quoteDb.Append(buf) 156 if err != nil { 157 kunt.ircCtx.Privmsg(msg.Args[0], err.Error()) 158 return 159 } 160 err = quoteDb.Sync() 161 if err != nil { 162 log.Fatal(err) 163 } 164 } 165 166 func cmdCountQuotes(msg irc.Message) { 167 text := fmt.Sprintf("The quote DB has %d quotes", quoteDb.Size()) 168 kunt.ircCtx.Privmsg(msg.Args[0], text) 169 } 170 171 func cmdTheoQuote(msg irc.Message) { 172 quotes := []string{ 173 "Write more code.", 174 "Make more commits.", 175 "That's because you have been slacking.", 176 "slacker!", 177 "That's what happens when you're lazy.", 178 "idler!", 179 "slackass!", 180 "lazy bum!", 181 "Stop slacking you lazy bum!", 182 "slacker slacker lazy bum bum bum slacker!", 183 "I could search... but I'm a lazy bum ;)", 184 "sshutup sshithead, ssharpsshooting susshi sshplats ssharking assholes.", 185 "Lazy bums slacking on your asses.", 186 "35 commits an hour? That's pathetic!", 187 "Fine software takes time to prepare. Give a little slack.", 188 "I am just stating a fact", 189 "you bring new meaning to the terms slackass. I will have to invent a new term.", 190 "if they cut you out, muddy their back yards", 191 "Make them want to start over, and play nice the next time.", 192 "It is clear that this has not been thought through.", 193 "avoid using abort(). it is not nice.", 194 "That's the most ridiculous thing I've heard in the last two or three minutes!", 195 "I'm not just doing this for crowd response. I need to be right.", 196 "I'd put a fan on my bomb.. And blinking lights...", 197 "I love to fight", 198 "No sane people allowed here. Go home.", 199 "you have to stop peeing on your breakfast", 200 "feature requests come from idiots", 201 "henning and darren / sitting in a tree / t o k i n g / a joint or three", 202 "KICK ASS. TIME FOR A JASON LOVE IN! WE CAN ALL GET LOST IN HIS HAIR!", 203 "shame on you for following my rules.", 204 "altq's parser sucks dead whale farts through the finest chemistry pipette's", 205 "screw this operating system shit, i just want to drive!", 206 "Search for fuck. Anytime you see that word, you have a paragraph to write.", 207 "Yes, but the ports people are into S&M.", 208 "Buttons are for idiots.", 209 "We are not hackers. We are turd polishing craftsmen.", 210 "who cares. style(9) can bite my ass", 211 "It'd be one fucking happy planet if it wasn't for what's under this fucking sticker.", 212 "I would explain, but I am too drunk.", 213 "you slackers don't deserve pictures yet", 214 "Vegetarian my ass", 215 "Wait a minute, that's a McNally's!", 216 "don't they recognize their moral responsibility to entertain me?", 217 "#ifdef is for emacs developers.", 218 "Many well known people become net-kooks in their later life, because they lose touch with reality.", 219 "You're not allowed to have an opinion.", 220 "tweep tweep tweep", 221 "Quite frankly, SSE's alignment requirement is the most utterly retarded idea since eating your own shit.", 222 "Holy verbose prom startup Batman.", 223 "Any day now, when we sell out.", 224 "optimism in man kind does not belong here", 225 "First user who tries to push this button, he pounds into the ground with a rant of death.", 226 "we did farts. now we do sperm. we are cutting edge.", 227 "the default configuration is a mixture of piss, puke, shit, and bloody entrails.", 228 "Stop wasting your time reading people's licenses.", 229 "doing it with environment variables is OH SO SYSTEM FIVE LIKE OH MY GOD PASS ME THE SPOON", 230 "Linux is fucking POO, not just bad, bad REALLY REALLY BAD", 231 "penguins are not much more than chickens that swim.", 232 "i am a packet sniffing fool, let me wipe my face with my own poo", 233 "Whiners. They scale really well.", 234 "in your world, you would have a checklist of 50 fucking workarounds just to make a coffee.", 235 "for once, I have nothing to say.", 236 "You have no idea how fucked we are", 237 "You can call it fart if you want to.", 238 "wavelan is a battle field", 239 "You are in a maze of gpio pins, all alike, all undocumented, and a few are wired to bombs.", 240 "And that is why humppa sucks... cause it has no cause.", 241 "cache aliasing is a problem that would have stopped in 1992 if someone had killed about 5 people who worked at Sun.", 242 "Don't spread rumours about me being gentle.", 243 "If municipal water filtering equipment was built by the gcc developers, the western world would be dead by now.", 244 "kettenis supported a new machine in my basement and all I got to do was fix a 1 character typo in his html page commit.", 245 "industry told us a lesson: when you're an asshole, they mail you hardware", 246 "I was joking, really. I think I am funny :-)", 247 "the kernel is a harsh mistress", 248 "Have I ever been subtle? If my approach ever becomes subtle, shoot me.", 249 "the acpi stabs you in the back. the acpi stabs you in the back. you die ...", 250 "My cats are more observant than you.", 251 "our kernels have no bugs", 252 "style(9) has all these fascist rules, and i have a problem with some of them because i didn't come up with them", 253 "I'm not very reliable", 254 "I don't like control", 255 "You aren't being conservative -- you are trying to be a caveman.", 256 "nfs loves everyone", 257 "basically, dung beetles fucking. that's what kerberosV + openssl is like", 258 "I would rather run Windows than use vi.", 259 "if you assign that responsibility to non-hikers I will walk over and cripple you now.", 260 "i ojbect two yoru splelng of achlhlocis.", 261 "We have two kinds of developers - those that deal with their own shit and those that deal with other people's shit.", 262 "If people keep adding such huge stuff, soon mg will be bigger than emacs.", 263 "this change comes down to: This year, next year, 5 years from now, 10 years from now, or Oh fuck.", 264 "backwards compatibility is king, and will remain king, until 2038.", 265 "I don't know if the Internet's safe yet.", 266 "Those who don't understand Unix are condemned to reinvent Multics in a browser", 267 "Don't tell anybody I said that.", 268 "Complaint forms are handled in another department.", 269 "You'd be safer using Windows than the code which was just deleted.", 270 "Shit should not be shared.", 271 "the randomization in this entire codebase is a grand experiment in stupid", 272 "My mailbox is full of shock.", 273 "my integer overflow spidey senses are tingling.", 274 "I'm just trying to improve the code...", 275 "It's a pleasure to work on code you can't make worse.", 276 "It's largely bad style to do (int)sizeof", 277 "When I see Makefile.in, I know that \"in\" is short for \"insane\".", 278 "This is the beer. And that's why we need a hackathon.", 279 } 280 281 idx := rand.Intn(len(quotes)) 282 kunt.ircCtx.Privmsg(msg.Args[0], quotes[idx]) 283 } 284 285 func cmdRandUrl(msg irc.Message) { 286 if urlDb.Empty() { 287 kunt.ircCtx.Privmsg(msg.Args[0], "Empty url database") 288 return 289 } 290 url, idx := urlDb.Rand() 291 url = []byte(strings.TrimSpace(string(url))) 292 // Print idx in red 293 r := fmt.Sprintf("%s%02d[%d]%s %s", 294 "\003", '5', idx, "\003", string(url)) 295 kunt.ircCtx.Privmsg(msg.Args[0], r) 296 } 297 298 func resolveYoutubeTitle(url string) (title string, ok bool) { 299 title = "" 300 ok = false 301 if len(ytregex.FindAllString(url, -1)) > 0 { 302 title = "Unresolved title" 303 ok = true 304 resp, err := http.Get(url) 305 if err == nil { 306 defer resp.Body.Close() 307 contents, err := ioutil.ReadAll(resp.Body) 308 if err == nil { 309 titles := titleregex.FindAllString(string(contents), 1) 310 if len(titles) > 0 { 311 //this relates to the way titleregex is 312 title = string(titles[0][35 : len(titles[0])-2]) 313 } else { 314 log.Printf(" [resolveYoutubeTitle] could not find the title regexp for url: %s \n", url) 315 } 316 } else { 317 log.Printf(" [resolveYoutubeTitle] could not read response body with ioutil\n") 318 } 319 } else { 320 log.Printf(" [resolveYoutubeTitle] could not connect to youtube url for title fetching \n") 321 } 322 //print [Youtube] tag in purple 323 title = fmt.Sprintf(" %s%02d[%s]%s %s", 324 "\003", '6', "Youtube", "\003", string(title)) 325 } 326 return 327 } 328 329 func cmdAddUrl(msg irc.Message) { 330 text := msg.Args[1] 331 title := "" 332 if len(strings.Fields(text)) < 2 { 333 kunt.ircCtx.Privmsg(msg.Args[0], "Missing parameter for !addurl") 334 return 335 } 336 text = text[8:] 337 text = strings.TrimSpace(text) 338 // Check for yt link 339 title, ok := resolveYoutubeTitle(text) 340 if ok { 341 text += title + "\n" 342 } else { 343 text += "\n" 344 } 345 buf := []byte(text) 346 if urlDb.CountMatches(buf) > 0 { 347 kunt.ircCtx.Privmsg(msg.Args[0], 348 fmt.Errorf("Duplicate entry: %s", buf).Error()) 349 return 350 } 351 _, err := urlDb.Append(buf) 352 if err != nil { 353 kunt.ircCtx.Privmsg(msg.Args[0], err.Error()) 354 return 355 } 356 err = urlDb.Sync() 357 if err != nil { 358 log.Fatal(err) 359 } 360 } 361 362 func cmdCountUrls(msg irc.Message) { 363 r := fmt.Sprintf("The url DB has %d urls", urlDb.Size()) 364 kunt.ircCtx.Privmsg(msg.Args[0], r) 365 } 366 367 func cmdRadio(msg irc.Message) { 368 np, e := http.Get("http://radio.2f30.org:8000/") 369 if e != nil { 370 kunt.ircCtx.Privmsg(msg.Args[0], "Is radio broken?") 371 } else { 372 defer np.Body.Close() 373 info, _ := ioutil.ReadAll(np.Body) 374 lines := strings.Split(string(info), "\n") 375 for _, i := range lines { 376 if i == "" { 377 continue 378 } 379 kunt.ircCtx.Privmsg(msg.Args[0], i) 380 time.Sleep(512 * time.Millisecond) 381 } 382 } 383 } 384 385 func cmdUptime(msg irc.Message) { 386 etime := time.Now() 387 r := fmt.Sprintf("%v", etime.Sub(kunt.stime)) 388 kunt.ircCtx.Privmsg(msg.Args[0], r) 389 } 390 391 func cmdSrc(msg irc.Message) { 392 src := "http://git.2f30.org/kunt" 393 kunt.ircCtx.Privmsg(msg.Args[0], src) 394 } 395 396 func cmdTodo(msg irc.Message) { 397 todo, err := ioutil.ReadFile("TODO") 398 if err != nil { 399 kunt.ircCtx.Privmsg(msg.Args[0], "No TODO list available") 400 return 401 } 402 sf := strings.FieldsFunc(string(todo), func(r rune) bool { 403 switch r { 404 case '\n': 405 return true 406 } 407 return false 408 }) 409 for _, v := range sf { 410 kunt.ircCtx.Privmsg(msg.Args[0], v) 411 time.Sleep(512 * time.Millisecond) 412 } 413 } 414 415 func cmdGame(msg irc.Message) { 416 text := msg.Args[1] 417 if len(strings.Fields(text)) < 2 { 418 for _, str := range geng.List() { 419 kunt.ircCtx.Privmsg(msg.Args[0], "[game] "+str) 420 } 421 return 422 } 423 text = strings.TrimSpace(text[5:]) 424 found := false 425 for _, str := range geng.List() { 426 if str == text { 427 found = true 428 break 429 } 430 } 431 if !found { 432 kunt.ircCtx.Privmsg(msg.Args[0], "[game] game not found") 433 return 434 } 435 gchan := make(chan irc.Message) 436 geng.New(text, kunt.ircCtx, &gchan) 437 time.Sleep(512 * time.Millisecond) 438 gchan <- irc.Message{Command: "SETNICK", Args: []string{botname}} //Let the game engine know. 439 gchan <- irc.Message{Command: "SETCHAN", Args: []string{msg.Args[0]}} 440 } 441 442 func cmdCopyright(msg irc.Message) { 443 copyright := []string{ 444 "Copyright 2013 TLH and dsp. All rights reserved.", 445 "Use of this source code is governed by a BSD-style", 446 "license that can be found in the LICENSE file.", 447 } 448 for _, i := range copyright { 449 kunt.ircCtx.Privmsg(msg.Args[0], i) 450 time.Sleep(512 * time.Millisecond) 451 } 452 } 453 454 func fifoCmdParse() { 455 fi, err := os.Open(".kfifo") 456 if err != nil { 457 log.Fatal(err) 458 } 459 defer func() { 460 if err := fi.Close(); err != nil { 461 log.Fatal(err) 462 } 463 }() 464 for { 465 buf := make([]byte, 1024) 466 n, err := fi.Read(buf) 467 if err != nil && err != io.EOF { 468 log.Fatal(err) 469 } 470 if n > 0 { 471 buf = buf[0 : n-1] 472 switch string(buf) { 473 case "netjoin": 474 kunt.ircCtx.JoinChannels() 475 case "urlupdate": 476 updateUrlDbTitles("db/urls-new") 477 case "quit": 478 donechan <- true 479 default: 480 log.Printf("Unknown fifo command:%s\n", string(buf)) 481 } 482 } 483 } 484 } 485 486 func updateUrlDbTitles(path string) { 487 log.Printf("*** starting urlDb update under path %s ***\n", path) 488 newurlPlain := mapfs.NewPlainMap() 489 _, err := os.Stat(path) 490 if err == nil { 491 log.Printf(" [updateUrlDbTitles] for the db to be updated, please provide a non-existant directory to be populated. %s exists\n", path) 492 return 493 } 494 newurlDb := mapfs.NewMapfs(newurlPlain, "Urls", path, "url") 495 err = newurlDb.Load() 496 if err != nil { 497 log.Printf("error on loading new urlDb: %s\n", err.Error()) 498 return 499 } 500 iter := mapfs.MakeMapIter(urlDb) 501 whitespacefunc := func(a rune) bool { 502 return a == '\t' || a == ' ' 503 } 504 for { 505 _, v, ok := iter() 506 if !ok { 507 break 508 } 509 stringv := strings.TrimSpace(string(v)) 510 strs := strings.FieldsFunc(stringv, whitespacefunc) 511 title, ok := resolveYoutubeTitle(strs[0]) 512 if ok { 513 stringv = strs[0] + title + "\n" 514 } else { 515 stringv = strs[0] + "\n" 516 } 517 buf := []byte(stringv) 518 _, err := newurlDb.Append(buf) 519 if err != nil { 520 log.Printf(" [updateUrlDbTitles] %s\n", err.Error()) 521 return 522 } 523 err = newurlDb.Sync() 524 if err != nil { 525 log.Fatal(err) 526 } 527 } 528 log.Printf("*** urlDb update finished ***\n") 529 } 530 531 532 var quoteDb *mapfs.Mapfs 533 var urlDb *mapfs.Mapfs 534 var kunt kuntCtx 535 var geng games.GameEnger 536 var botname string 537 var ytregex *regexp.Regexp 538 var titleregex *regexp.Regexp 539 var configfile string 540 var sslon = flag.Bool("s", false, "SSL support") 541 var cfg *irc.Config 542 var donechan chan bool 543 544 func init() { 545 flag.StringVar(&configfile,"c","","JSON configuration file") 546 } 547 548 func main() { 549 kunt.stime = time.Now() 550 botname = "kunt" 551 geng = games.NewGameEng() 552 log.SetPrefix("kunt: ") 553 554 flag.Parse() 555 if flag.NArg() < 1 && configfile == "" { 556 fmt.Fprintf(os.Stderr, "usage: %s [-s] [-c configfile] host:port\n", 557 os.Args[0]) 558 os.Exit(2) 559 } 560 561 562 quotePlain := mapfs.NewPlainMap() 563 quoteDb = mapfs.NewMapfs(quotePlain, "Quotes", "db/quotes", "quote") 564 urlPlain := mapfs.NewPlainMap() 565 urlDb = mapfs.NewMapfs(urlPlain, "Urls", "db/urls", "url") 566 567 err := quoteDb.Load() 568 if err != nil { 569 log.Fatal(err) 570 } 571 err = urlDb.Load() 572 if err != nil { 573 log.Fatal(err) 574 } 575 576 // Compile the yt regexp 577 ytregex = regexp.MustCompile("(((www.)?youtube.com/.*(.v=|&v=).+)|(youtu.be/.+))") 578 titleregex = regexp.MustCompile("<meta property=\"og:title\" content=\".*\">") 579 580 // Check for duplicate entries 581 iter := mapfs.MakeMapIter(quoteDb) 582 for { 583 k, v, ok := iter() 584 if !ok { 585 break 586 } 587 if quoteDb.CountMatches(v) > 1 { 588 log.Fatal(fmt.Errorf("Duplicate entry in quote DB with key: %d - val: %s", k, v)) 589 } 590 } 591 592 iter = mapfs.MakeMapIter(urlDb) 593 for { 594 k, v, ok := iter() 595 if !ok { 596 break 597 } 598 if urlDb.CountMatches(v) > 1 { 599 log.Fatal(fmt.Errorf("Duplicate entry in url DB with key: %d - val: %s", k, v)) 600 } 601 } 602 603 rand.Seed(time.Now().UnixNano()) 604 605 dispatch := map[string]func(irc.Message){ 606 botname: cmdKunt, 607 "!theo": cmdTheoQuote, 608 "!wisdom": cmdWisdom, 609 "!help": cmdHelp, 610 "!version": cmdVersion, 611 "!randquote": cmdRandQuote, 612 "!addquote": cmdAddQuote, 613 "!countquotes": cmdCountQuotes, 614 "!randurl": cmdRandUrl, 615 "!addurl": cmdAddUrl, 616 "!counturls": cmdCountUrls, 617 "!radio": cmdRadio, 618 "!uptime": cmdUptime, 619 "!src": cmdSrc, 620 "!TODO": cmdTodo, 621 "!game": cmdGame, 622 "!copyright": cmdCopyright, 623 } 624 if configfile == "" { 625 hostport := strings.Split(flag.Arg(0), ":") 626 627 cfg = &irc.Config{ 628 NetworkName: "freenode", 629 Nick: botname, 630 User: "z0mg", 631 RealName: botname, 632 Serv: hostport[0], 633 Port: hostport[1], 634 Ssl: *sslon, 635 Channels: []string{"#2f30"}, 636 } 637 } else { 638 cfg,err = irc.LoadConfig(configfile) 639 if err != nil { 640 log.Fatal(err) 641 } 642 } 643 644 kunt.ircCtx = irc.NewIrcContext(*cfg) 645 kunt.ircCtx.AddEventHandler(irc.Event{Command: "PRIVMSG", Fn: func(msg irc.Message) { 646 cmd := msg.Args[1] 647 for i, v := range dispatch { 648 if strings.HasPrefix(cmd, i) { 649 go v(msg) 650 } 651 } 652 }}) 653 654 kunt.ircCtx.AddEventHandler(irc.Event{Command: "PING", Fn: func(msg irc.Message) { 655 kunt.ircCtx.Pong(msg.Args[0]) 656 }}) 657 658 kunt.ircCtx.AddEventHandler(irc.Event{Command: "ERROR", Fn: func(msg irc.Message) { 659 os.Exit(0) 660 }}) 661 662 kunt.ircCtx.AddEventHandler(irc.Event{Command: "KICK", Fn: func(msg irc.Message) { 663 time.Sleep(750 * time.Millisecond) 664 kunt.ircCtx.Join("#2f30", "") 665 }}) 666 667 err = kunt.ircCtx.Connect() 668 if err != nil { 669 log.Fatal(err) 670 } 671 kunt.ircCtx.Login() 672 673 syscall.Mkfifo(".kfifo", 0600) 674 go fifoCmdParse() 675 676 donechan = make(chan bool) 677 select { 678 case stat := <-donechan: 679 if stat { 680 break 681 } 682 } 683 684 kunt.ircCtx.Quit("releasing entropy") 685 log.Println(" [Exiting] ") 686 }