1-- startup.lua: version 1.1.99/07 2-- 3-- NMDC Listeners: 4-- chat = normal chat message (you won't get your own messages) 5-- f( hub, user, "message" ) 6-- DISCARDABLE: 7-- return non-nil to hide the msg from BCDC++, 8-- all discardable functions also get an optional last 9-- argument stating whether some previous listener returned non-nil 10-- unknownchat= incoming messages displayed without any nick 11-- f( hub, "message" ) 12-- DISCARDABLE 13-- ownChat = normal chat message from yourself (incoming from the hub) 14-- f( hub, "message" ) 15-- DISCARDABLE 16-- pm = normal pm message 17-- f( hub, user, "message" ) 18-- DISCARDABLE 19-- hubPm = pm message with a different prefix than the nick in the From field 20-- f( hub, user, "message which may include a <nickname>" ) 21-- DISCARDABLE 22-- userConnected = a user connected (or rather.. the first getUser call was made) 23-- f( hub, user ) 24-- userMyInfo = a myinfo message from a user, use this as "userConnected" 25-- f( hub, user, "$MyINFO $ALL ... 1234$|" ) 26-- DISCARDABLE 27-- userQuit = a quit message from a user 28-- f( hub, nick ) 29-- DISCARDABLE 30-- raw = a full message 31-- f( hub, "line" ) 32-- DISCARDABLE (message won't get parsed.. no other listeners will be called) 33-- ADC Listeners: 34-- adcChat = normal chat message (you won't get your own messages). 35-- f( hub, user, "message", me_msg ) 36-- DISCARDABLE: 37-- * return non-nil to hide the msg from BCDC++, 38-- * all discardable functions also get an optional last 39-- argument stating whether some previous listener returned non-nil 40-- * me_msg is true if a /me-style message is sent 41-- adcOwnChat = normal chat message from yourself (incoming from the hub) 42-- f( hub, "message", me_msg ) 43-- DISCARDABLE 44-- adcPm = normal pm message 45-- f( hub, user, "message", me_msg ) 46-- DISCARDABLE 47-- groupPm = pm message with a different reply-sid than the one who talks (probably chatroom or bot) 48-- f( hub, user, "message", reply_sid, me_msg ) 49-- DISCARDABLE 50-- userInf = an INF message from a user 51-- f( hub, user, flags ) 52-- flags is a table where all named flags are stored (ie: flags["NI"], flags["I4"], ...) 53-- DISCARDABLE 54-- adcUserCon = a user connected (or rather.. the first getUser call was made) 55-- f( hub, user ) 56-- adcUserQui = a quit message from a user 57-- f( hub, sid, flags ) 58-- flags is a table where all named flags are stored (ie: flags["ID"], flags["MS"], ...) 59-- Common Listeners: 60-- ownChatOut = normal chat message from yourself (outgoing to the hub) 61-- f( hub, "message" ) 62-- DISCARDABLE 63-- connected = connecting to a hub (many functions may be unavailable (return nil)) 64-- f( hub ) 65-- disconnected = disconnected from a hub 66-- f( hub ) 67-- timer = called every second (if DC():RunTimer(1) is called), use 68-- dcpp:getHubs()[k]:getAddress() or :getUrl() to select a hub 69-- f() 70-- clientIn = peer to peer line oriented transfer control input, userp is a pointer 71-- (lightuserdata) 72-- f( userp, "line" ) 73-- DISCARDABLE (returning non-nil kills the connection) 74-- clientOut = peer to peer line oriented transfer control output, userp is a pointer 75-- (lightuserdata) 76-- f( userp, "line" ) 77-- DISCARDABLE (returning non-nil kills the connection) 78-- 79-- Example listener (load _after_ this script): 80-- dcpp:setListener( "chat", "bier", 81-- function( hub, user, text ) 82-- local s = string.lower( text ) 83-- if string.find( s, "[^a-z]bier+[^a-z]" ) or string.find( s, "[^a-z]biertje[^a-z]" ) then 84-- hub:sendChat( "bier? ja lekker! :)" ) 85-- end 86-- end 87-- ) 88-- 89-- If you want to remove the "bier" chat listener, simply type: 90-- /lua dcpp:setListener( "chat", "bier" ) 91-- in any chat window 92 93 94DC():PrintDebug( "** Started startup.lua **" ) 95 96--///////////////////////////////////// 97--// Helper functions 98--///////////////////////////////////// 99 100if not dcu then 101 dcu = {} 102end 103 104dcu.NmdcEscape = function(this, msg ) 105 msg = string.gsub( msg, "%$", "$") 106 msg = string.gsub( msg, "|", "|") 107 return msg 108end 109 110dcu.AdcEscape = function(this, msg, inverse) 111 msg = string.gsub(msg, "\r", "") 112 local ret = "" 113 if inverse then 114 local replacetable = {} 115 replacetable["\\\\"] = [[\]] 116 replacetable["\\s"] = [[ ]] 117 replacetable["\\n"] = "\n" 118 local skip = false 119 for k = 1, string.len(msg) do 120 if skip then 121 skip = false 122 else 123 local c = string.sub( msg, k, k + 1) 124 if replacetable[c] then 125 ret = ret .. replacetable[c] 126 skip = true 127 else 128 ret = ret .. string.sub(c, 1, 1) 129 end 130 end 131 end 132 else 133 local replacetable = {} 134 replacetable["\\"] = [[\\]] 135 replacetable[" "] = [[\s]] 136 replacetable["\n"] = [[\n]] 137 138 for k = 1, string.len(msg) do 139 local c = string.sub( msg, k, k) 140 if replacetable[c] then 141 ret = ret .. replacetable[c] 142 else 143 ret = ret .. c 144 end 145 end 146 end 147 return ret 148end 149 150--// Checks if the given decimal number has the 2^exp bit set 151dcu.BBit = function(this, num, exp) 152 local ret = false 153 if string.find(tostring(math.floor(num / 2^exp)), "[13579]$") then 154 ret = true 155 end 156 return ret 157end 158 159--///////////////////////////////////// 160--// Hub manager 161--///////////////////////////////////// 162 163if not dcpp or dcpp._init_me_anyway == true then 164 dcpp = {} 165 dcpp._hubs = {} 166 dcpp._listeners = {} 167end 168 169dcpp.addHub = function( this, hub, isitadc ) 170 if not this._hubs[hub] then 171 -- DC():PrintDebug( "Hub added (id = "..tostring( hub )..")" ) 172 if isitadc then 173 this._hubs[hub] = createAdcHub( hub ) 174 DC():PrintDebug( "ADC hub added (id = " .. tostring( hub ) ..")" ) 175 else 176 this._hubs[hub] = createNmdcHub( hub ) 177 end 178 for k,f in pairs(dcpp:getListeners( "connected" )) do 179 f( this._hubs[hub] ) 180 end 181 return this._hubs[hub] 182 else 183 --DC():PrintDebug( "Tried to add existing hub on: "..this._hubs[hub]:getHubName().. 184 -- " (id = "..tostring( hub )..")" ) 185 return nil 186 end 187end 188 189dcpp.getHub = function( this, hub ) 190 if this._hubs[hub] then 191 return this._hubs[hub] 192 else 193 --DC():PrintDebug( "Tried to fetch an unknown hub (id = "..tostring( hub )..")" ) 194 return this:addHub( hub ):setPartial() -- tell the object that we missed the logon 195 end 196end 197 198dcpp.getHubs = function( this ) 199 return this._hubs 200end 201 202dcpp.hasHub = function( this, hub ) 203 if this._hubs[hub] then 204 return 1 205 else 206 return nil 207 end 208end 209 210dcpp.findHub = function( this, url ) 211 for k, h in pairs(this._hubs) do 212 if h:getUrl() == url then 213 return h 214 end 215 end 216 return false 217end 218 219dcpp.removeHub = function( this, hub ) 220 if this._hubs[hub] then 221 --DC():PrintDebug( "Hub removed: "..this._hubs[hub]:getHubName().." (id = "..tostring( hub )..")" ) 222 for k,f in pairs(dcpp:getListeners( "disconnected" )) do 223 f( this._hubs[hub] ) 224 end 225 this._hubs[hub]:destroy() 226 this._hubs[hub] = nil 227 else 228 --DC():PrintDebug( "Tried to remove non-existent hub (id = "..tostring( hub )..")" ) 229 end 230end 231 232dcpp.listHubs = function( this ) 233 DC():PrintDebug( "** Listing hubs **" ) 234 for k,v in pairs(this._hubs) do 235 DC():PrintDebug( tostring( k ).." ("..v:getHubName()..")" ) 236 end 237end 238 239dcpp.setListener = function( this, ltype, id, func ) 240 if not dcpp._listeners[ltype] then 241 dcpp._listeners[ltype] = {} 242 end 243 dcpp._listeners[ltype][id] = func 244end 245 246dcpp.getListeners = function( this, ltype ) 247 if dcpp._listeners[ltype] then 248 return dcpp._listeners[ltype] 249 else 250 return {} 251 end 252end 253 254 255--///////////////////////////////////// 256--// Hub object 257--///////////////////////////////////// 258 259function createAdcHub( hubid ) 260 local hub = {} 261 262 hub._id = hubid 263 hub._mySID = nil 264 hub._myNick = nil 265 hub._myCID = nil 266 hub._nick = nil 267 hub._description = nil 268 hub._users = {} 269 hub._uptime = os.time() 270 271 hub.getId = function( this ) 272 return this._id 273 end 274 275 hub.getUptime = function( this ) 276 return ( os.time() - hub._uptime ) / 60 277 end 278 279 hub.getProtocol = function( this ) 280 return "adc" 281 end 282 283 hub.getAddress = function( this ) 284 return DC():GetHubIpPort( this._id ) 285 end 286 287 hub.getHubName = function( this ) 288 --// TODO: Shall we return with NI or DE? or both? 289 --// For now just returning the nick with the url 290 if this._nick then 291 return this._nick .. " ("..this:getUrl()..")" 292 else 293 return this:getUrl() 294 end 295 end 296 297 hub.getUrl = function( this ) 298 return DC():GetHubUrl( this._id ) 299 end 300 301 hub.getOwnNick = function( this ) 302 return this._myNick 303 end 304 305 hub.setOwnNick = function( this, newnick ) 306 this._myNick = newnick 307 DC():PrintDebug("[STATUS] Own nick set: " .. newnick ) 308 end 309 310 hub.getOwnSid = function( this ) 311 if this._mySID then 312 return this._mySID 313 end 314 DC():PrintDebug( "[" .. this:getUrl() .."] Own SID not set, your scripts are failing. Reconnect please." ) 315 end 316 317 hub.getOwnCid = function( this ) 318 if this._myCID then 319 return this._myCID 320 end 321 DC():PrintDebug( "[" .. this:getUrl() .."] Own CID not set, your scripts are failing. Reconnect please." ) 322 end 323 324 hub.getUser = function( this, sid, inf ) 325 local newuser = false 326 if sid == "HUB9" and inf then 327 -- INF is about the hub itself 328 local params = {} 329 string.gsub(inf, "([^ ]+)", function(s) table.insert(params, s) end ) 330 for k in pairs(params) do 331 local name = string.sub( params[k], 1, 2 ) 332 if name == "NI" then 333 local NI = dcu:AdcEscape(string.sub( params[k], 3), true) 334 this._nick = NI 335 DC():PrintDebug("[STATUS] HUB nick set: " .. NI ) 336 elseif name == "DE" then 337 local DE = dcu:AdcEscape(string.sub( params[k], 3), true) 338 this._description = DE 339 DC():PrintDebug("[STATUS] HUB description set: " .. DE ) 340 this:addLine("The current hub topic is: " .. DE) 341 end 342 end 343 end 344 345 if not this._users[sid] then 346 this._users[sid] = createAdcUser( this, sid ) 347 newuser = true 348 if this:getUptime() >= 2 then -- start sending messages AFTER logon 349 for k,f in pairs(dcpp:getListeners( "adcUserCon" )) do 350 f( this, this._users[sid] ) 351 end 352 end 353 end 354 local r = this._users[sid] 355 if inf then 356 local params = {} 357 string.gsub(inf, "([^ ]+)", function(s) table.insert(params, s) end ) 358 for k in pairs(params) do 359 local name = string.sub( params[k], 1, 2 ) 360 if name == "ID" then 361 local ID = string.sub( params[k], 3) 362 r:setCid(ID) 363 if sid == this._mySID then 364 this._myCID = ID 365 DC():PrintDebug("[STATUS] Own CID set: " .. ID ) 366 end 367 elseif name == "CT" then 368 local CT = string.sub( params[k], 3) 369 r:processCt(CT) 370 elseif name == "I4" then 371 local I4 = string.sub( params[k], 3) 372 r:setIp(I4) 373 elseif name == "NI" then 374 local NI = dcu:AdcEscape(string.sub( params[k], 3), true) 375 if not newuser then 376 local oldNI = r:getNick() 377 r:setNick(NI) 378 this:addLine( oldNI .. " is now known as " .. NI ) 379 else 380 r:setNick(NI) 381 end 382 if sid == this._mySID then 383 this:setOwnNick(NI) 384 end 385 end 386 end 387 end 388 return r 389 end 390 391 hub.removeUser = function( this, sid ) 392 this._users[sid] = nil 393 end 394 395 hub.isOp = function( this, sid ) 396 if this._users[sid] then 397 return this._users[sid]._op 398 end 399 return nil 400 end 401 402 hub.getSidbyNick = function( this, nick ) 403 for k in pairs(this._users) do 404 if this._users[k]._nick == nick then 405 return k 406 end 407 end 408 return nil 409 end 410 411 hub.getSidbyCid = function( this, cid ) 412 for k in pairs(this._users) do 413 if this._users[k]._cid == cid then 414 return k 415 end 416 end 417 return nil 418 end 419 420 hub.getUserByCid = function( this, cid ) 421 for k in pairs(this._users) do 422 if this._users[k]._cid == cid then 423 return this._users[k] 424 end 425 end 426 return nil 427 end 428 429 hub.sendChat = function( this, msg ) 430 local ownSid = this:getOwnSid() 431 msg = dcu:AdcEscape( msg ) 432 DC():SendHubMessage( this:getId(), "BMSG " .. ownSid .. " " .. msg .. "\n" ) 433 end 434 435 hub.injectChat = function( this, msg ) 436 DC():PrintDebug("[WARNING] Your scripts trying to use hub:injectChat on ADC hub. Please use hub:injectMessage() to inject an ADC message or hub:addLine() to inject a chat line." ) 437 end 438 439 hub.injectMessage = function( this, msg ) 440 DC():InjectHubMessageADC( this:getId(), msg ) 441 end 442 443 hub.addLine = function( this, msg, fmt ) 444 --// TODO: need a function which adds a chat line without nick 445 msg = dcu:AdcEscape( msg ) 446 DC():InjectHubMessageADC( this:getId(), "ISTA 000 " .. msg ) 447 end 448 449 hub.sendPrivMsgTo = function( this, victimSid, msg_unescaped, hideFromSelf ) 450 local ownSid = this:getOwnSid() 451 local msg = dcu:AdcEscape( msg_unescaped ) 452 if ownSid then 453 if hideFromSelf then 454 DC():SendHubMessage( this:getId(), "DMSG ".. ownSid .. " " .. victimSid .." " .. msg .. " PM" .. ownSid .."\n" ) 455 else 456 DC():SendHubMessage( this:getId(), "EMSG ".. ownSid .. " " .. victimSid .." " .. msg .. " PM" .. ownSid .."\n" ) 457 end 458 end 459 end 460 461 hub.injectPrivMsg = function( this, victimSid, fromSid, msg ) 462 DC():InjectHubMessageADC( this:getId(), "DMSG " .. fromSid .." ".. victimSid .." ".. msg .. " PM" .. victimSid .. "\n" ) 463 end 464 465 hub.findUsers = function( this, nick, notag ) 466 -- you get a possibly empty table of users 467 if not notag then 468 return { this._users[this:getSidbyNick(nick)] } 469 else 470 local list = {} 471 for k in pairs(this._users) do 472 local ret,c,n = string.find( this._users[k]._nick, "^%[.*%](.-)$" ) 473 if n == nick then 474 table.insert( list, this._users[k] ) 475 end 476 end 477 return list 478 end 479 end 480 481 hub.destroy = function( this ) 482 end 483 484 --// events 485 486 hub.onChatMessage = function( this, user, text, me_msg ) 487 local ret 488 for k,f in pairs(dcpp:getListeners( "adcChat" )) do 489 ret = f( this, user, text, me_msg, ret ) or ret 490 end 491 return ret 492 end 493 494 hub.onChatFromSelf = function( this, text, me_msg ) 495 local ret 496 for k,f in pairs(dcpp:getListeners( "adcOwnChat" )) do 497 ret = f( this, text, me_msg, ret ) or ret 498 end 499 return ret 500 end 501 502 hub.onINF = function( this, user, flags ) 503 local ret 504 for k,f in pairs(dcpp:getListeners( "userInf" )) do 505 ret = f( this, user, flags, ret ) or ret 506 end 507 return ret 508 end 509 510 hub.onQUI = function( this, sid, flags ) 511 for k,f in pairs(dcpp:getListeners( "adcUserQui" )) do 512 f( this, sid, flags ) 513 end 514 end 515 516 hub.onPrivateMessage = function( this, user, targetSid, replySid, text, me_msg ) 517 if targetSid == this:getOwnSid() then 518 if user:getSid() == replySid then 519 local ret 520 for k,f in pairs(dcpp:getListeners( "adcPm" )) do 521 ret = f( this, user, text, me_msg, ret ) or ret 522 end 523 return ret 524 else 525 local ret 526 for k,f in pairs(dcpp:getListeners( "groupPm" )) do 527 ret = f( this, user, replySid, text, me_msg, ret ) or ret 528 end 529 return ret 530 end 531 end 532 end 533 534 hub.attention = function( this ) 535 DC():HubWindowAttention( this:getId() ) 536 end 537 538 return hub 539end 540 541function createNmdcHub( hubid ) 542 local hub = {} 543 544 hub._id = hubid 545 hub._users = {} 546 hub._name = nil 547 hub._myNick = nil 548 hub._partial = nil 549 hub._gotOpList = nil 550 hub._uptime = os.time() 551 hub._hubUC = {} 552 hub._customUC = {} 553 554 hub.getId = function( this ) 555 return this._id 556 end 557 558 hub.getProtocol = function( this ) 559 return "nmdc" 560 end 561 562 hub.getUptime = function( this ) 563 return ( os.time() - hub._uptime ) / 60 564 end 565 566 hub.getUser = function( this, nick, op ) 567 if not this._users[nick] then 568 this._users[nick] = createNmdcUser( this, nick ) 569 if this:getUptime() >= 2 then -- start sending messages AFTER logon 570 for k,f in pairs(dcpp:getListeners( "userConnected" )) do 571 f( this, this._users[nick] ) 572 end 573 end 574 end 575 local r = this._users[nick] 576 if op then 577 r:setOp( true ) 578 r:setClass( "op" ) 579 this._gotOpList = 1 580 end 581 return r 582 end 583 584 hub.findUsers = function( this, nick, notag ) 585 -- you get a possibly empty table of users 586 if not notag then 587 return { this._users[nick] } 588 else 589 local list = {} 590 for k,v in pairs(this._users) do 591 local ret,c,n = string.find( k, "^%[.*%](.-)$" ) 592 if n == nick then 593 table.insert( list, v ) 594 end 595 end 596 return list 597 end 598 end 599 600 hub.gotOpList = function( this ) 601 return this._gotOpList 602 end 603 604 hub.isOp = function( this, nick ) 605 if this._users[nick] and this._users[nick]:isOp() then 606 return 1 607 end 608 end 609 610 hub.removeUser = function( this, nick ) 611 this._users[nick] = nil 612 end 613 614 hub.setPartial = function( this ) 615 --// we're most likely missing logon info 616 this._partial = 1 617 end 618 619 hub.isPartial = function( this ) 620 --// are we missing logon info? 621 return this._partial 622 end 623 624 hub.setHubName = function( this, msg ) 625 this._name = msg 626 end 627 628 hub.getAddress = function( this ) 629 return DC():GetHubIpPort( this._id ) 630 end 631 632 hub.getUrl = function( this ) 633 return DC():GetHubUrl( this._id ) 634 end 635 636 hub.getHubName = function( this ) 637 if this._name then 638 return this._name.." ("..this:getUrl()..")" 639 else 640 return this:getUrl() 641 end 642 end 643 644 hub.setOwnNick = function( this, nick ) 645 this._myNick = nick 646 end 647 648 hub.getOwnNick = function( this ) 649 if not this:isPartial() then 650 return this._myNick 651 end 652 DC():PrintDebug( "[" .. this:getUrl() .."] Your scripts are failing. ".. 653 "Own nick not set. Reconnect please." ) 654 end 655 656 hub.destroy = function( this ) 657 end 658 659 hub.sendChat = function( this, msg ) 660 local ownNick = this:getOwnNick() 661 msg = dcu:NmdcEscape( msg ) 662 if ownNick then 663 DC():SendHubMessage( this:getId(), "<"..ownNick.."> "..msg.."|" ) 664 end 665 end 666 667 hub.injectChat = function( this, msg, skipusercommand ) 668 DC():InjectHubMessage( this:getId(), msg ) 669 -- test if it's usercommand 670 if ( string.sub(msg, 1, 13) == "$UserCommand " ) and (not skipusercommand) then 671 this:customUC( msg ) 672 end 673 end 674 675 hub.addLine = function( this, msg, fmt ) 676 if not fmt then 677 msg = "*** " .. msg 678 end 679 DC():InjectHubMessage( this:getId(), msg ) 680 end 681 682 hub.sendPrivMsgTo = function( this, victim, msg, hideFromSelf ) 683 local ownNick = this:getOwnNick() 684 msg = dcu:NmdcEscape( msg ) 685 if ownNick then 686 DC():SendHubMessage( this:getId(), "$To: "..victim.." From: "..ownNick.." $"..msg.."|" ) 687 if not hideFromSelf then 688 this:injectPrivMsg( victim, ownNick, msg ) 689 end 690 end 691 end 692 693 hub.injectPrivMsg = function( this, from, to, msg ) 694 DC():InjectHubMessage( this:getId(), "$To: "..to.." From: "..from.." $"..msg ) 695 end 696 697 hub.injectPrivMsgFmt = function( this, from, to, msg ) 698 this:injectPrivMsg( from, to, "<"..from.."> "..msg ) 699 end 700 701 hub.attention = function( this ) 702 -- TODO old method was broken, probably worthwhile functionality though 703 end 704 705 --/////////////////////////// 706 --// $UserCommand manager 707 --/////////////////////////// 708 -- Todo: context sensitivitiy at UC 255 709 710 hub.hubUC = function( this, msg ) 711 local uc_type = string.gsub( msg, "%$UserCommand (%d+) .+", "%1") 712 -- DC():PrintDebug( "UserCommand " .. uc_type .. " arrived from " .. this:getHubName() .. " : " .. msg) 713 if uc_type == "255" then 714 -- clear user command list and resend our own commands to prevent it from disappearing 715 -- DC():PrintDebug( "Clearing Hub UC list.." ) 716 this:clearHubUCList() 717 -- DC():PrintDebug( "Resending Custom commands.." ) 718 this:reSendCustomUC() 719 else 720 -- add usercommands to UClist 721 -- DC():PrintDebug( "Adding hubUC.." ) 722 this:addHubUC( msg ) 723 end 724 725 return true 726 end 727 728 hub.customUC = function ( this, msg ) 729 local uc_type = string.gsub( msg, "%$UserCommand (%d+) .+", "%1") 730 -- DC():PrintDebug( "UserCommand " .. uc_type .. " arrived from a script: " .. msg) 731 if uc_type == "255" then 732 -- clear own user command list and resend hub usercommands to prevent it from disappearing 733 this:clearCustomUCList() 734 this:reSendHubUC() 735 else 736 -- add usercommands to UClist 737 this:addCustomUC( msg ) 738 end 739 return true 740 end 741 742 hub.addHubUC = function( this, msg ) 743 table.insert( this._hubUC, msg ) 744 return true 745 end 746 747 hub.addCustomUC = function( this, msg) 748 table.insert( this._customUC, msg ) 749 return true 750 end 751 752 hub.clearHubUCList = function( this ) 753 this._hubUC = {} 754 return true 755 end 756 757 hub.clearCustomUCList = function( this ) 758 this._customUC = {} 759 return true 760 end 761 762 hub.reSendCustomUC = function( this ) 763 for k in pairs(this._customUC) do 764 hub:injectChat( this._customUC[k] , true ) 765 -- DC():PrintDebug("Sending custom uc from stored table: " .. this._customUC[k] ) 766 end 767 return true 768 end 769 770 hub.reSendHubUC = function( this ) 771 for k in pairs(this._hubUC) do 772 hub:injectChat( this._hubUC[k] , true) 773 end 774 return true 775 end 776 777 --//////////////// 778 --// Own functions 779 --//////////////// 780 781 hub.onRaw = function( this, msg ) 782 local ret 783 for k,f in pairs(dcpp:getListeners( "raw" )) do 784 ret = f( this, msg ) or ret 785 end 786 return ret 787 end 788 789 hub.onSearch = function( this, msg ) 790 --DC():PrintDebug( this:getHubName().."> "..msg ) 791 end 792 793 hub.onHello = function( this, user, msg ) 794 end 795 796 hub.onMyInfo = function( this, user, msg ) 797 local ret 798 for k,f in pairs(dcpp:getListeners( "userMyInfo" )) do 799 ret = f( this, user, msg, ret ) or ret 800 end 801 return ret 802 end 803 804 hub.onQuit = function( this, nick, msg ) 805 local ret 806 for k,f in pairs(dcpp:getListeners( "userQuit" )) do 807 ret = f( this, nick, ret ) or ret 808 end 809 return ret 810 end 811 812 hub.onHubName = function( this, hubname, msg ) 813 end 814 815 hub.onPrivateMessage = function( this, user, to, prefix, text, full ) 816 -- DC():PrintDebug("user: " .. tostring(user) .. " to: " .. tostring(to) .. " prefix: " .. tostring(prefix) .. " text: " .. tostring(text) .. " full: " .. tostring(full) ) 817 if to == this:getOwnNick() then 818 if prefix == "<"..user:getNick().."> " then 819 local ret 820 for k,f in pairs(dcpp:getListeners( "pm" )) do 821 ret = f( this, user, text, ret ) or ret 822 end 823 return ret 824 elseif not prefix then 825 local ret 826 for k,f in pairs(dcpp:getListeners( "hubPm" )) do 827 ret = f( this, user, text, ret ) or ret 828 end 829 return ret 830 else 831 local ret 832 for k,f in pairs(dcpp:getListeners( "hubPm" )) do 833 ret = f( this, user, prefix .. text, ret ) or ret 834 end 835 return ret 836 end 837 end 838 end 839 840 hub.onChatMessage = function( this, user, text ) 841 local ret 842 for k,f in pairs(dcpp:getListeners( "chat" )) do 843 ret = f( this, user, text, ret ) or ret 844 end 845 return ret 846 end 847 848 hub.onUnknownChatMessage = function( this, text ) 849 local ret 850 for k,f in pairs(dcpp:getListeners( "unknownchat" )) do 851 ret = f( this, text, ret ) or ret 852 end 853 return ret 854 end 855 856 hub.onChatFromSelf = function( this, text ) 857 local ret 858 for k,f in pairs(dcpp:getListeners( "ownChat" )) do 859 ret = f( this, text, ret ) or ret 860 end 861 return ret 862 end 863 864 return hub 865end 866 867 868--///////////////////////////////////// 869--// User object 870--///////////////////////////////////// 871 872function createNmdcUser( hub, nick ) 873 local user = {} 874 875 user._hub = hub 876 user._nick = nick 877 user._op = false 878 user._ip = "" 879 user._class = "user" 880 user._handled_messages = {} -- flood protection 881 882 user.getProtocol = function( this ) 883 return "nmdc" 884 end 885 886 user.setOp = function( this, op ) 887 this._op = op 888 return this 889 end 890 891 user.isOp = function( this ) 892 return this._op 893 end 894 895 user.setClass = function( this, param ) 896 this._class = param 897 return this 898 end 899 900 user.getClass = function( this ) 901 return this._class 902 end 903 904 user.setIp = function( this, ip ) 905 this._ip = ip 906 end 907 908 user.getIp = function( this ) 909 return this._ip 910 end 911 912 user.getNick = function( this ) 913 return this._nick 914 end 915 916 user.sendPrivMsgFmt = function( this, msg, hideFromSelf ) 917 local ownNick = this._hub:getOwnNick() 918 if ownNick then 919 this._hub:sendPrivMsgTo( this._nick, "<"..ownNick.."> "..msg, hideFromSelf ) 920 end 921 return this 922 end 923 924 user.setMsgHandled = function( this, which ) 925 this._handled_messages[which] = 1 926 return this 927 end 928 929 user.msgHandled = function( this, which ) 930 return this._handled_messages[which] 931 end 932 933 return user 934end 935 936function createAdcUser( hub, sid ) 937 local user = {} 938 939 user._sid = sid 940 user._cid = "" 941 user._hub = hub 942 user._nick = "" 943 user._op = false 944 user._bot = false 945 user._registered = false 946 user._hubitself = false 947 user._class = "user" 948 user._ip = "" 949 user._handled_messages = {} -- flood protection 950 951 user.getProtocol = function( this ) 952 return "adc" 953 end 954 955 user.setOp = function( this, op ) 956 this._op = op 957 return this 958 end 959 960 user.isOp = function( this ) 961 return this._op 962 end 963 964 user.processCt = function( this, param ) 965 local num = tonumber(param) 966 if num then 967 968 --// Init 969 this._class = "user" 970 971 --// 2^0: bot 972 if dcu:BBit(num, 0) then 973 this:setBot(true) 974 DC():PrintDebug("BOT set: " .. this:getSid()) 975 else 976 this:setBot(false) 977 end 978 979 --// 2^1: registered 980 if dcu:BBit(num, 1) then 981 this:setReg(true) 982 else 983 this:setReg(false) 984 end 985 986 --// 2^2, 2^3, 2^4: some type of operator 987 if dcu:BBit(num, 2) or dcu:BBit(num, 3) or dcu:BBit(num, 4) then 988 this:setOp(true) 989 if dcu:BBit(num, 2) then 990 this._class = "op" 991 elseif dcu:BBit(num, 3) then 992 this._class = "su" 993 else 994 this._class = "owner" 995 end 996 else 997 this:setOp(false) 998 end 999 1000 if dcu:BBit(num, 5) then 1001 this:setHub(true) 1002 this._class = "hub" 1003 else 1004 this:setHub(false) 1005 end 1006 1007 else 1008 --// Empty CT field should cause all properties gone 1009 this:setBot(false) 1010 this:setOp(false) 1011 this:setReg(false) 1012 this:setHub(false) 1013 this._class = "user" 1014 end 1015 1016 --// DC():PrintDebug("CLASS: " .. this._class .. " [" .. tostring(param) .. "]" ) 1017 return this 1018 end 1019 1020 --// Possible values: "user", "op", "su", "owner", "hub" 1021 user.getClass = function( this ) 1022 return this._class 1023 end 1024 1025 user.setBot = function(this, bot) 1026 this._bot = bot 1027 return this 1028 end 1029 1030 user.isBot = function(this) 1031 return this._bot 1032 end 1033 1034 user.setReg = function(this, registered) 1035 this._registered = registered 1036 return this 1037 end 1038 1039 user.isReg = function(this) 1040 return this._registered 1041 end 1042 1043 user.setHub = function(this, hubitself) 1044 this._hubitself = hubitself 1045 return this 1046 end 1047 1048 user.isHub = function(this) 1049 return this._hubitself 1050 end 1051 1052 user.setIp = function( this, ip ) 1053 this._ip = ip 1054 end 1055 1056 user.getIp = function( this ) 1057 return this._ip 1058 end 1059 1060 user.setCid = function( this, cid ) 1061 this._cid = cid 1062 end 1063 1064 user.getCid = function( this ) 1065 return this._cid 1066 end 1067 1068 user.getSid = function( this ) 1069 return this._sid 1070 end 1071 1072 user.getNick = function( this ) 1073 return this._nick 1074 end 1075 1076 user.setNick = function( this, nick ) 1077 this._nick = nick 1078 -- DC():PrintDebug("Nick set: " .. nick ) 1079 end 1080 1081 user.sendPrivMsg = function( this, msg, hideFromSelf ) 1082 local victimSid = this:getSid() 1083 this._hub:sendPrivMsgTo( victimSid, msg, hideFromSelf ) 1084 return this 1085 end 1086 1087 -- Backward compatibility 1088 user.sendPrivMsgFmt = user.sendPrivMsg 1089 1090 user.setMsgHandled = function( this, which ) 1091 this._handled_messages[which] = 1 1092 return this 1093 end 1094 1095 user.msgHandled = function( this, which ) 1096 return this._handled_messages[which] 1097 end 1098 1099 return user 1100end 1101 1102 1103--///////////////////////////////////// 1104--// Handlers 1105--///////////////////////////////////// 1106 1107nmdch = {} 1108 1109function nmdch.DataArrival( hub, msg ) 1110 local h = dcpp:getHub( hub ) 1111 1112 --// If we missed the logon, we really have no business here, 1113 --// modify only if you really have to. 1114 --// Note that if not h:isPartial and not h:getOwnNick(), 1115 --// functions requiring an ownNick will silently fail. 1116 if h:isPartial() then 1117 return 1118 end 1119 1120 --// raw/unparsed message 1121 if h:onRaw( msg ) then 1122 return 1 1123 end 1124 1125 --// parse message and fire appropriate 1126 local ret,c,cmd = string.find( msg, "^%$([^ ]+)" ) 1127 if ret then 1128 if cmd == "Search" then 1129 return h:onSearch( msg ) 1130 elseif cmd == "Hello" then 1131 local nick = string.sub( msg, 8 ) 1132 if not h:getOwnNick() then 1133 h:setOwnNick( nick ) -- don't trust this nick on h:isPartial() 1134 end 1135 return h:onHello( h:getUser( nick ), msg ) 1136 elseif cmd == "MyINFO" and string.sub( msg, 1, 13 ) == "$MyINFO $ALL " then 1137 local nick = string.sub( msg, 14, string.find( msg, " ", 14, 1 ) - 1 ) 1138 return h:onMyInfo( h:getUser( nick ), msg ) 1139 elseif cmd == "Quit" then 1140 local nick = string.sub( msg, 7 ) 1141 h:removeUser( nick ) 1142 return h:onQuit( nick, msg ) 1143 elseif cmd == "HubName" then 1144 local hubname = string.sub( msg, 10 ) 1145 h:setHubName( hubname ) 1146 return h:onHubName( hubname, msg ) 1147 elseif cmd == "OpList" then 1148 for nick in string.gfind( string.sub( msg, 9 ), "[^$]+") do 1149 h:getUser( nick, 1 ) 1150 end 1151 return nil 1152 elseif cmd == "UserIP" then 1153 local nick,ip 1154 for combo in string.gfind( string.sub( msg, 9 ), "[^$]+") do 1155 ret,c,nick,ip = string.find( combo, "^(%S+) (%S+)$" ) 1156 if ret then 1157 h:getUser( nick ):setIp( ip ) 1158 end 1159 end 1160 return nil 1161 elseif cmd == "UserCommand" then 1162 h:hubUC( msg ) 1163 --elseif string.sub( msg, 1, 10 ) == "$NickList " then 1164 -- for nick in string.gfind( string.sub( msg, 9, -1), "[^$]+") do 1165 -- h:getUser( nick ) 1166 -- end 1167 -- return nil 1168 elseif cmd == "To:" then 1169 local ret,c,to,from,fulltext = string.find( msg, "^%$To: ([^ ]+) From: ([^ ]+) %$(.*)$" ) 1170 if ret then 1171 local ret,c,prefix,text = string.find( fulltext, "^(%b<> )(.*)$" ) 1172 if ret then 1173 return h:onPrivateMessage( h:getUser( from ), to, prefix, text, msg ) 1174 else 1175 return h:onPrivateMessage( h:getUser( from ), to, nil, fulltext, msg ) 1176 end 1177 end 1178 end 1179 elseif string.sub( msg, 1, 1 ) == "<" then 1180 local ret,c,nick,text = string.find( msg, "^<([^>]+)> (.*)$" ) 1181 if ret and h:getOwnNick() then 1182 if nick ~= h:getOwnNick() then -- don't be flooding mainchat now.. 1183 return h:onChatMessage( h:getUser( nick ), text ) 1184 else 1185 return h:onChatFromSelf( text ) 1186 end 1187 end 1188 elseif msg ~= "" then 1189 return h:onUnknownChatMessage(msg) 1190 end 1191end 1192 1193function dcpp.UserDataIn( user, msg ) 1194 local ret 1195 for k,f in pairs(dcpp:getListeners( "clientIn" )) do 1196 ret = f( user, msg ) or ret 1197 end 1198 return ret 1199end 1200 1201function dcpp.UserDataOut( user, msg ) 1202 local ret 1203 for k,f in pairs(dcpp:getListeners( "clientOut" )) do 1204 ret = f( user, msg ) or ret 1205 end 1206 return ret 1207end 1208 1209function dcpp.OnCommandEnter( hub, text ) 1210 local h = dcpp:getHub( hub ) 1211 local ret 1212 for k,f in pairs(dcpp:getListeners( "ownChatOut" )) do 1213 ret = f( h, text, ret ) or ret 1214 end 1215 return ret 1216end 1217 1218function dcpp.OnTimer() 1219 -- Called every second. 1220 for k,f in pairs(dcpp:getListeners( "timer" )) do 1221 f() 1222 end 1223end 1224 1225function nmdch.OnHubAdded( hub ) 1226 dcpp:addHub( hub, false ) 1227end 1228 1229function nmdch.OnHubRemoved( hub ) 1230 dcpp:removeHub( hub ) 1231end 1232 1233adch = {} 1234 1235function adch.DataArrival( hub, msg ) 1236 if msg == "" then 1237 return nil 1238 end 1239 local h = dcpp:getHub( hub ) 1240 1241 local params = {} 1242 string.gsub(msg, "([^ ]+)", function(s) table.insert(params, s) end ) 1243 1244 local mtype = string.sub(params[1], 1, 1) 1245 local cmd = string.sub(params[1], 2, 4) 1246 local sid, targetSid, parameters = false, false, "" 1247 1248 if mtype == "I" then 1249 parameters = string.sub( msg, 6) 1250 sid = "HUB9" 1251 elseif mtype == "B" then 1252 parameters = string.sub( msg, 11) 1253 sid = params[2] 1254 elseif mtype == "D" or mtype == "E" then 1255 parameters = string.sub( msg, 16 ) 1256 sid = params[2] 1257 targetSid = params[3] 1258 end 1259 1260 -- Building flags table 1261 local flags = {} 1262 string.gsub(parameters, "([^ ]+)", function(s) flags[string.sub(s, 1, 2)] = dcu:AdcEscape( string.sub(s, 3), true ) end ) 1263 1264 if cmd == "SID" then 1265 DC():PrintDebug( "[STATUS] SID received: " .. params[2] ) 1266 h._mySID = params[2] 1267 elseif cmd == "QUI" then 1268 h:removeUser( params[2] ) 1269 h:onQUI( params[2], flags ) 1270 elseif cmd == "INF" then 1271 local u = h:getUser( sid, parameters ) 1272 return h:onINF( u, flags ) 1273 elseif cmd == "MSG" then 1274 local pm, replySid, me_msg = false, false, false 1275 local tmp = {} 1276 1277 string.gsub(parameters, "([^ ]+)", function(s) table.insert(tmp, s) end ) 1278 local text = dcu:AdcEscape(tmp[1], true) 1279 tmp[1] = nil 1280 1281 -- Check for named parameters 1282 for k in pairs(tmp) do 1283 local name = string.sub(tmp[k], 1,2) 1284 local value = string.sub(tmp[k], 3) 1285 if name == "ME" then 1286 if value == "1" then 1287 me_msg = true 1288 end 1289 elseif name == "PM" then 1290 pm = true 1291 replySid = value 1292 end 1293 end 1294 1295 if pm then 1296 return h:onPrivateMessage( h:getUser( sid ), targetSid, replySid, text, me_msg ) 1297 else 1298 if sid ~= h:getOwnSid() then -- don't be flooding mainchat now.. 1299 return h:onChatMessage( h:getUser( sid ), text, me_msg ) 1300 else 1301 return h:onChatFromSelf( text, me_msg ) 1302 end 1303 end 1304 1305 end 1306end 1307 1308function adch.OnHubAdded( hub ) 1309 dcpp:addHub( hub, true ) 1310end 1311 1312function adch.OnHubRemoved( hub ) 1313 dcpp:removeHub( hub ) 1314end 1315 1316--///////////////////////////////////// 1317--// Utility functions 1318--///////////////////////////////////// 1319 1320function SendActiveSearchResult( hub, ip_port, search_nick, filename, filesize, open_slots, 1321 total_slots ) 1322 DC():SendUDP( ip_port, "$SR "..search_nick.." "..filename.."\005".. filesize.." "..open_slots.. 1323 "/"..total_slots.."\005"..dcpp:getHub( hub ):getHubName() ) -- no pipe in UDP $SR 1324end 1325 1326 1327--///////////////////////////////////// 1328--// Execute your own scripts 1329--///////////////////////////////////// 1330 1331-- do you need the timer? 1332--DC():RunTimer(1) 1333 1334--dofile( DC():GetScriptsPath() .. "bier.lua" ) 1335--dofile( DC():GetScriptsPath() .. "slots.lua" ) 1336--dofile( DC():GetScriptsPath() .. "formatting.lua" ) 1337dofile( DC():GetScriptsPath() .. "uptime.lua" ) 1338--dofile( DC():GetScriptsPath() .. "onjoin.lua" ) 1339--dofile( DC():GetScriptsPath() .. "monologue.lua" ) 1340dofile( DC():GetScriptsPath() .. "ignore.lua" ) 1341--dofile( DC():GetScriptsPath() .. "p2pblock.lua" ) 1342--dofile( DC():GetScriptsPath() .. "quiet_login.lua" ) 1343--dofile( DC():GetScriptsPath() .. "log.lua" ) 1344--dofile( DC():GetScriptsPath() .. "kickfilter.lua" ) 1345dofile( DC():GetScriptsPath() .. "adccommands.lua" ) 1346