Subversion Repositories Kolibri OS

Rev

Rev 3216 | Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

  1. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  2. ;;                                                                 ;;
  3. ;; Copyright (C) KolibriOS team 2004-2013. All rights reserved.    ;;
  4. ;; Distributed under terms of the GNU General Public License       ;;
  5. ;;                                                                 ;;
  6. ;;                                                                 ;;
  7. ;;         GNU GENERAL PUBLIC LICENSE                              ;;
  8. ;;          Version 2, June 1991                                   ;;
  9. ;;                                                                 ;;
  10. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  11.  
  12.  
  13. server_parser:
  14.  
  15.         mov     esi, servercommand
  16.  
  17.         cmp     byte [esi], ':'
  18.         jne     .parse
  19.  
  20.   .spaceloop:
  21.         lodsb
  22.         test    al, al
  23.         jz      .fail
  24.         cmp     al, ' '
  25.         jne     .spaceloop
  26.  
  27.   .parse:
  28.         mov     eax, [esi]
  29.         or      eax, 0x20202020
  30.         mov     edi, server_commands
  31.         mov     ecx, server_commands.number
  32.  
  33.   .loop:
  34.         scasd
  35.         je      .got_cmd
  36.         add     edi, 4
  37.         dec     ecx
  38.         jnz     .loop
  39.  
  40.   .fail:
  41.         ret
  42.  
  43.   .got_cmd:
  44.         jmp     dword[edi]
  45.  
  46.  
  47. server_commands:
  48.  
  49.         dd      '328 ', cmd_328
  50.         dd      '332 ', cmd_topic
  51.         dd      '333 ', cmd_333         ; nickname and time of topic
  52.         dd      '353 ', cmd_353         ; name reply
  53.         dd      '366 ', cmd_366         ; end of names list
  54.         dd      '372 ', cmd_372         ; motd
  55.         dd      '375 ', cmd_375         ; start of motd
  56.         dd      '376 ', cmd_376         ; end of motd
  57.         dd      '421 ', cmd_421         ; unknown command
  58.         dd      'join', cmd_join
  59.         dd      'kick', cmd_kick
  60.         dd      'mode', cmd_mode
  61.         dd      'nick', cmd_nick
  62.         dd      'part', cmd_part
  63.         dd      'ping', cmd_ping
  64.         dd      'priv', cmd_privmsg
  65.         dd      'quit', cmd_quit
  66.         dd      'noti', cmd_notice
  67.  
  68.         .number = ($ - server_commands) / 8
  69.  
  70. compare_to_nick:
  71.  
  72.         push    esi
  73.         mov     ecx, MAX_NICK_LEN
  74.         mov     esi, user_nick
  75.   .loop:
  76.         lodsb
  77.         cmp     al, ' '
  78.         jbe     .done
  79.         cmp     al, 'a'
  80.         jb      .ok
  81.         cmp     al, 'z'
  82.         ja      .ok
  83.         sub     al, 0x20
  84.   .ok:
  85.  
  86.         mov     bl, byte[edi]
  87.         cmp     bl, 'a'
  88.         jb      .ok2
  89.         cmp     bl, 'z'
  90.         ja      .ok2
  91.         sub     bl, 0x20
  92.   .ok2:
  93.         cmp     bl, al
  94.         jne     .not_equal
  95.         inc     edi
  96.         dec     ecx
  97.         jnz     .loop
  98.  
  99.   .done:
  100.         xor     eax, eax
  101.         pop     esi
  102.         ret
  103.  
  104.   .not_equal:
  105.         or      eax, -1
  106.         pop     esi
  107.         ret
  108.  
  109.  
  110.  
  111. find_window:
  112.  
  113. ;        mov     [window_print],
  114.  
  115.         ret
  116.  
  117.  
  118.  
  119. cmd_328:
  120. cmd_421:
  121. cmd_372:
  122. cmd_375:
  123. cmd_376:
  124.         add     esi, 4
  125.         jmp     cmd_notice.loop
  126.  
  127. cmd_notice:
  128.  
  129.         cmp     byte[servercommand], ':'
  130.         jne     .gogogo
  131.  
  132.         mov     byte [esi-1], 0
  133.         push    esi
  134.         mov     esi, str_1
  135.         call    print_text2
  136.         mov     esi, servercommand+1
  137.         call    print_text2
  138.         mov     esi, str_2
  139.         call    print_text2
  140.         pop     esi
  141.  
  142.   .gogogo:
  143.         add     esi, 6
  144.  
  145.   .loop:
  146.         inc     esi
  147.         cmp     byte [esi], 0
  148.         je      .fail
  149. ;        cmp     byte [esi], 10  ; newline
  150. ;        je      server_parser.parse
  151.         cmp     byte [esi], ' '
  152.         jne     .loop
  153.  
  154.   .loop2:
  155.         inc     esi
  156.         cmp     byte [esi], 0
  157.         je      .fail
  158.         cmp     byte [esi], ' '
  159.         je      .loop2
  160.         cmp     byte [esi], ':'
  161.         je      .loop2
  162.  
  163.         call    print_text2
  164.         mov     esi, str_newline
  165.         call    print_text2
  166.  
  167.   .fail:
  168.  
  169.         ret
  170.  
  171.  
  172.  
  173. cmd_ping:
  174.  
  175. ; Just change PING to PONG
  176.         mov     dword[esi], 'PONG'
  177.  
  178. ; Find the end of the command
  179.         lea     edi, [esi + 5]
  180.         xor     al, al
  181.         repne   scasb
  182.  
  183. ; Now send it back
  184.         mov     edx, esi
  185.         mov     esi, edi
  186.         mov     word [esi], 0x0d0a
  187.         inc     esi
  188.         inc     esi
  189.         sub     esi, edx
  190.         mcall   send, [socketnum], , , 0
  191.  
  192.         ret
  193.  
  194.  
  195.  
  196. cmd_privmsg:
  197.  
  198.         add     esi, 8  ; skip 'PRIVMSG '
  199.  
  200. ; Check if it was destined for me privately
  201.         mov     edi, servercommand+1
  202.         call    compare_to_nick
  203. ;;;        je      .private
  204.  
  205. ; If not, find the correct window ???
  206.  
  207. ; now find the end of nick
  208.         mov     edi, esi
  209.   .loop:
  210.         inc     edi
  211.         cmp     byte [edi], 0
  212.         je      .fail
  213.         cmp     byte [edi], ' '
  214.         jne     .loop
  215.  
  216.   .loop2:
  217.         inc     edi
  218.         cmp     byte [edi], 0
  219.         je      .fail
  220.         cmp     byte [edi], ' '
  221.         je      .loop2
  222.         cmp     byte [edi], ':'
  223.         je      .loop2
  224.         cmp     byte [edi], 1
  225.         je      cmd_ctcp
  226.  
  227. ; Action?
  228.         cmp     dword[edi+1], 'ACTI'
  229.         je      .action
  230.  
  231. ; nope, just plain old privmsg
  232. if TIMESTAMP
  233.         call    print_timestamp
  234. end if
  235.  
  236.         push    edi
  237.         mov     bl, '<'
  238.         call    print_character
  239.  
  240.         mov     eax, servercommand+1
  241.         mov     dl, '!'
  242.         call    print_text
  243.  
  244.         mov     bl, '>'
  245.         call    print_character
  246.  
  247.         mov     bl, ' '
  248.         call    print_character
  249.  
  250.         pop     esi
  251.         call    print_text2
  252.  
  253.         mov     bl, 10
  254.         call    print_character
  255.  
  256.   .fail:
  257.         ret
  258.  
  259.   .action:
  260.         push    edi
  261.         if TIMESTAMP
  262.         call    print_timestamp
  263.         end if
  264.  
  265.         mov     esi, action_header_short
  266.         call    print_text2
  267.  
  268.         mov     eax, servercommand+1
  269.         mov     dl, ' '
  270.         call    print_text
  271.  
  272.         mov     bl, ' '
  273.         call    print_character
  274.  
  275.         pop     esi
  276.         add     esi, 8
  277.         call    print_text2
  278.  
  279.         mov     bl, 10
  280.         call    print_character
  281.  
  282.         ret
  283.  
  284. cmd_ctcp:
  285.  
  286.         cmp     dword[edi+1], 'VERS'
  287.         je      .version
  288.  
  289.         cmp     dword[edi+1], 'TIME'
  290.         je      .time
  291.  
  292.         cmp     dword[edi+1], 'PING'
  293.         je      .ping
  294.  
  295.         ret
  296.  
  297.   .time:
  298.         lea     esi, [edi+1]
  299.         mov     byte [edi+5], ' '
  300.         add     edi, 6
  301.  
  302.         ; TODO: add system date (fn 29) in human readable format
  303.  
  304.         mcall   3                       ; get system time
  305.  
  306.         mov     ecx, 3
  307.   .timeloop:
  308.         mov     bl, al
  309.         shr     al, 4
  310.         add     al, '0'
  311.         stosb
  312.  
  313.         mov     al, bl
  314.         and     al, 0x0f
  315.         add     al, '0'
  316.         stosb
  317.  
  318.         dec     ecx
  319.         jz      .timedone
  320.  
  321.         mov     al, ':'
  322.         stosb
  323.         shr     eax, 8
  324.         jmp     .timeloop
  325.  
  326.   .timedone:
  327.         xor     al, al
  328.         stosb
  329.         call    ctcp_reply
  330.  
  331.         if TIMESTAMP
  332.         call    print_timestamp
  333.         end if
  334.  
  335.         mov     esi, ctcp_header
  336.         call    print_text2
  337.  
  338.         mov     esi, servercommand+1
  339.         call    print_text2
  340.  
  341.         mov     esi, ctcp_time
  342.         call    print_text2
  343.  
  344.         ret
  345.  
  346.   .version:
  347.         mov     esi, str_version
  348.         call    ctcp_reply
  349.  
  350.         if TIMESTAMP
  351.         call    print_timestamp
  352.         end if
  353.  
  354.         mov     esi, ctcp_header
  355.         call    print_text2
  356.  
  357.         mov     esi, servercommand+1
  358.         call    print_text2
  359.  
  360.         mov     esi, ctcp_version
  361.         call    print_text2
  362.  
  363.         ret
  364.  
  365.   .ping:
  366.         lea     esi, [edi+1]
  367.         call    ctcp_reply
  368.  
  369.         if TIMESTAMP
  370.         call    print_timestamp
  371.         end if
  372.  
  373.         mov     esi, ctcp_header
  374.         call    print_text2
  375.  
  376.         mov     esi, servercommand+1
  377.         call    print_text2
  378.  
  379.         mov     esi, ctcp_ping
  380.         call    print_text2
  381.  
  382.         ret
  383.  
  384.  
  385.  
  386. ctcp_reply:
  387.  
  388.         push    esi
  389.  
  390.         mov     dword [usercommand], 'NOTI'
  391.         mov     dword [usercommand+4], 'CE  '
  392.  
  393.         mov     esi, servercommand+1
  394.         mov     edi, usercommand+7
  395.   .nickloop:
  396.         lodsb
  397.         cmp     al, '!'
  398.         je      .done
  399.         cmp     al, ' '
  400.         je      .done
  401.         test    al, al
  402.         je      .fail
  403.         stosb
  404.         jmp     .nickloop
  405.   .done:
  406.         mov     byte [esi-1], 0
  407.         mov     ax, ' :'
  408.         stosw
  409.         mov     al, 1
  410.         stosb
  411.  
  412.         pop     esi
  413.   .replyloop:
  414.         lodsb
  415.         cmp     al, 1
  416.         jbe     .done2
  417.         stosb
  418.         jmp     .replyloop
  419.   .done2:
  420.  
  421.         mov     al, 1
  422.         stosb
  423.         mov     ax, 0x0a0d
  424.         stosw
  425.  
  426.         lea     esi, [edi - usercommand]
  427.         mcall   send, [socketnum], usercommand, , 0
  428.   .fail:
  429.         ret
  430.  
  431.  
  432.  
  433. cmd_part:
  434.         add     esi, 5  ; skip 'PART '
  435.  
  436. ; Is it me who parted?
  437.         mov     edi, servercommand+1
  438.         call    compare_to_nick
  439.         jne     .dont_close
  440.  
  441. ; yes, close the window
  442.         mov     edi, [window_print]
  443.         mov     [edi + window.flags], FLAG_UPDATED + FLAG_CLOSE
  444.  
  445.         ret
  446.  
  447. ; somebody else parted, just print message
  448.   .dont_close:
  449.         push    esi
  450.         mov     esi, action_header
  451.         call    print_text2
  452.  
  453.         mov     eax, servercommand+1
  454.         mov     dl, '!'
  455.         mov     cl, ' '
  456.         call    print_text
  457.  
  458.         mov     esi, has_left_channel
  459.         call    print_text2
  460.  
  461.         pop     esi
  462.         call    print_text2
  463.  
  464.         mov     esi, str_newline
  465.         call    print_text2
  466.  
  467. ;;; TODO: dec [window.users], remove username from the userlist
  468.  
  469.  
  470.         ret
  471.  
  472.  
  473.  
  474. cmd_join:
  475.         add     esi, 5  ; skip 'JOIN '
  476.  
  477. ; compare nick: did we join a channel?
  478.         mov     edi, servercommand+1
  479.         call    compare_to_nick
  480.         jne     .no_new_window
  481.  
  482. ; create channel window - search for empty slot
  483.         mov     ebx, windows
  484.         mov     ecx, MAX_WINDOWS
  485.   .loop:
  486.         cmp     [ebx + window.data_ptr], 0
  487.         je      .free_found
  488.         add     ebx, sizeof.window
  489.         dec     ecx
  490.         jnz     .loop
  491. ; Error: no more available windows!! ;;;;; TODO
  492.   .fail:
  493.         ret
  494.  
  495.   .free_found:
  496.         push    ebx
  497.         call    window_create
  498.         pop     ebx
  499.         test    eax, eax
  500.         jz      .fail
  501.         mov     [ebx + window.data_ptr], eax
  502.         mov     [ebx + window.type], WINDOWTYPE_CHANNEL
  503.         mov     [ebx + window.flags], 0
  504.  
  505.         call    window_set_name
  506.  
  507.         mov     [window_open], ebx
  508.         mov     [window_print], ebx
  509.         call    window_refresh
  510.  
  511.         push    esi
  512.         mov     esi, action_header
  513.         call    print_text2
  514.  
  515.         mov     esi, str_talking
  516.         call    print_text2
  517.  
  518.         pop     eax
  519.         mov     dl, ' '
  520.         call    print_text
  521.  
  522.         mov     esi, str_dotnewline
  523.         call    print_text2
  524.  
  525.         call    draw_window
  526.  
  527.         ret
  528.  
  529.   .no_new_window:
  530.         push    esi
  531.         call    window_set_name
  532.  
  533.         mov     esi, action_header
  534.         call    print_text2
  535.  
  536.         mov     eax, servercommand+1
  537.         mov     dl, ' '
  538.         call    print_text
  539.  
  540.         mov     esi, joins_channel
  541.         call    print_text2
  542.  
  543.         pop     esi
  544.         call    print_text2
  545.  
  546.         mov     esi, str_newline
  547.         call    print_text2
  548.  
  549. ;;; TODO: inc [window.users], add username to the userlist
  550.  
  551.         ret
  552.  
  553.  
  554.  
  555.  
  556. cmd_nick:       ; FIXME
  557.  
  558.         add     esi, 5  ; skip 'NICK '
  559.  
  560.         push    esi
  561. ; test for change of my nick
  562.         mov     esi, servercommand+1
  563.         mov     edi, user_nick
  564.         mov     ecx, MAX_NICK_LEN
  565.         rep     cmpsb
  566.         cmp     byte[edi-1], 0
  567.         jne     .notmy
  568.         cmp     byte[esi-1], '!'
  569.         jne     .notmy
  570.  
  571. ; yes, this is my nick, set to new
  572.         pop     esi
  573.         or      ecx, -1
  574.         mov     edi, esi
  575.         xor     eax, eax
  576.         repne   scasb
  577.         neg     ecx
  578.         cmp     ecx, MAX_NICK_LEN
  579.         jb      @f
  580.         mov     ecx, MAX_NICK_LEN
  581.       @@:
  582.         mov     edi, user_nick
  583.         rep     movsb
  584.   .notmy:
  585.  
  586. ; replace nick in all lists of users
  587.         mov     ebx, windows
  588.   .channels:
  589.         mov     esi, [ebx + window.data_ptr]
  590.         lea     esi, [esi + window_data.names]
  591. ;;;;;        mov     edx, [esi + window_data.nameslen]
  592.         add     edx, esi
  593.   .nicks:
  594.         mov     edi, servercommand+1
  595.         cmp     byte[esi], '@'
  596.         jne     @f
  597.         inc     esi
  598.  
  599.   @@:
  600.         cmp     esi, edx
  601.         jae     .srcdone
  602.         lodsb
  603.         cmp     al, ' '
  604.         je      .srcdone
  605.         scasb
  606.         je      @b
  607.  
  608.   @@:
  609.         cmp     esi, edx
  610.         jae     .nextchannel
  611.         lodsb
  612.         cmp     al, ' '
  613.         jne     @b
  614.  
  615.   .nextnick:
  616.         cmp     esi, edx
  617.         jae     .nextchannel
  618.         lodsb
  619.         cmp     al, ' '
  620.         jz      .nextnick
  621.         dec     esi
  622.         jmp     .nicks
  623.  
  624.  
  625.   .srcdone:
  626.         cmp     byte [edi], '!'
  627.         jne     .nextnick
  628.  
  629. ; here we have esi -> end of nick which must be replaced to [servercommand_position]+6
  630.         lea     edx, [edi-servercommand-1]
  631.         sub     esi, edx
  632.         or      ecx, -1
  633.         xor     eax, eax
  634. ;        mov     edi, [servercommand_position]        ;;;;; FIXME
  635.         repnz   scasb
  636.         not     ecx
  637.         dec     ecx
  638.         push    ecx
  639.         cmp     ecx, edx
  640.         jb      .decrease
  641.         jz      .copy
  642.   .increase:
  643.  
  644. ; new nick is longer than the old
  645.         push    esi
  646.         lea     edi, [ebx+120*10] ;;;;;;
  647.         lea     esi, [edi+edx]
  648.         sub     esi, ecx
  649.         mov     ecx, esi
  650.         sub     ecx, [esp]
  651.         dec     esi
  652.         dec     edi
  653.         std
  654.         rep     movsb
  655.         cld
  656.         pop     esi
  657.         jmp     .copy
  658.   .decrease:
  659. ; new nick is shorter than the old
  660.         push    esi
  661.         lea     edi, [esi+ecx]
  662.         add     esi, edx
  663.         lea     ecx, [ebx+120*10]
  664.         sub     ecx, edi
  665.         rep     movsb
  666.         pop     esi
  667.   .copy:
  668. ; copy nick
  669.         mov     edi, esi
  670.         dec     edi
  671. ;        mov     esi, [servercommand_position]        ;;;;; FIXME
  672.         pop     ecx
  673.         sub     edx, ecx
  674.         sub     [ebx-4], edx
  675.         rep     movsb
  676.         mov     al, ' '
  677.         stosb
  678.  
  679.   .nextchannel:
  680.         add     ebx, sizeof.window
  681.         cmp     ebx, windows + sizeof.window*MAX_WINDOWS
  682.         jb      .channels
  683.  
  684. ;        mov  [text_start], window_text + 120*80
  685.  new_all_channels3:
  686.  
  687.         mov     esi, action_header_short
  688.         call    print_text2
  689.  
  690.         mov     eax, servercommand+1
  691.         mov     dl,'!'
  692.         call    print_text
  693.  
  694.         mov     esi,is_now_known_as
  695.         call    print_text2
  696.  
  697. ;       mov     esi,[servercommand_position]        ;;;;; FIXME
  698.         call    print_text2
  699.  
  700. ;;;        call    notify_channel_thread
  701.  
  702. ; go to next window (and check if its a channel!)
  703.  
  704. ;        add     [text_start], 120*80
  705. ;        cmp     [text_start], I_END+120*80*20
  706. ;        jb      new_all_channels3
  707.  
  708.         ret
  709.  
  710.  
  711.  
  712.  
  713. cmd_kick:
  714.         add     esi, 5  ; skip 'KICK '
  715. ; Is it me who got kicked?
  716.         mov     edi, servercommand+1
  717.         call    compare_to_nick
  718.         jne     .not_me
  719.  
  720. ; TODO: mark channel as disconnected
  721.  
  722.   .not_me:
  723. ; find the channel user has been kicked from
  724.         push    esi
  725.         mov     esi, action_header_short
  726.         call    print_text2
  727.  
  728.         mov     eax, servercommand+1
  729.         mov     dl,'!'
  730.         call    print_text
  731.  
  732.         mov     esi, kicked
  733.         call    print_text2
  734.  
  735.         pop     esi
  736.         call    print_text2
  737.  
  738. ;;; TODO: dec [window.users], remove username from the userlist
  739.  
  740.         ret
  741.  
  742.  
  743.  
  744. cmd_quit:
  745.  
  746.         mov     esi, action_header
  747.         call    print_text2
  748.  
  749.         mov     eax, servercommand+1
  750.         mov     dl, '!'
  751.         call    print_text
  752.  
  753.         mov     esi, has_quit_irc
  754.         call    print_text2
  755.  
  756. ;;; TODO: dec [window.users], remove username from the userlist
  757.  
  758.         ret
  759.  
  760.  
  761.  
  762. cmd_mode:
  763.  
  764.         add     esi, 5  ; skip 'MODE '
  765.  
  766.         push    esi
  767.         mov     esi, action_header_short
  768.         call    print_text2
  769.  
  770.         mov     eax, servercommand+1
  771.         mov     dl, ' '
  772.         call    print_text
  773.  
  774.         mov     esi, sets_mode
  775.         call    print_text2
  776.  
  777.         pop     esi
  778.         call    print_text2
  779.  
  780.         mov     esi, str_newline
  781.         call    print_text2
  782.  
  783. ;;; TODO: change username if needed
  784.  
  785.         ret
  786.  
  787.  
  788. cmd_353:        ; channel usernames reply
  789.  
  790.         add     esi, 4  ; skip '353 '
  791.  
  792. ; TODO: mark a bit that we are receiving names
  793.  
  794. ; first, find the channel name
  795.   .loop1:
  796.         lodsb
  797.         cmp     al, '#'
  798.         je      .got_channel
  799.         test    al, al
  800.         jnz     .loop1
  801.  
  802.         ret
  803.  
  804.   .got_channel:
  805. ;        call    find_channel   ;;;; ASSUME current channel for now
  806.         mov     ebx, [window_print]
  807.         mov     [ebx + window.users], 0              ;;; FIXME: Only if we have just set the receiving names bit
  808.         mov     eax, [ebx + window.data_ptr]
  809.         lea     edi, [eax + window_data.names]
  810.         mov     edx, edi
  811.  
  812. ; now find the semicolon separating channelname and usernames
  813.   .loop2:
  814.         lodsb
  815.         cmp     al, ':'
  816.         je      .newname
  817.         test    al, al
  818.         jnz     .loop2
  819.  
  820.         ret
  821.  
  822.   .next:
  823.         add     edx, MAX_NICK_LEN
  824.         mov     edi, edx
  825. ;;;        cmp     edi, ..              ; TODO: Check for buffer overflow
  826.  
  827.   .newname:
  828.         inc     [ebx + window.users]
  829.   .namesloop:
  830. ; now the names list begins, separated with spaces
  831.         lodsb
  832.         test    al, al
  833.         jz      .done
  834.         cmp     al, ' '
  835.         jz      .next
  836.         stosb
  837.         jmp     .namesloop
  838.  
  839.   .done:
  840.  
  841.         call    redraw_channel_list
  842.  
  843.         ret
  844.  
  845.  
  846.  
  847.  
  848.  
  849. cmd_366:        ; channel usernames end
  850.  
  851. ; TODO: clear the bit that we are receiving names
  852.  
  853.  
  854.         ret
  855.  
  856.  
  857. cmd_topic:
  858.  
  859.         add     esi, 4  ; skip '332 '
  860.  
  861.   .loop:
  862.         lodsb
  863.         test    al, al
  864.         je      .fail
  865.         cmp     al, ':'
  866.         jne     .loop
  867.  
  868.         push    esi
  869.         mov     esi, action_header
  870.         call    print_text2
  871.  
  872.         mov     esi, str_topic
  873.         call    print_text2
  874.  
  875.         pop     esi
  876.         call    print_text2
  877.  
  878.         mov     esi, str_newline
  879.         call    print_text2
  880.  
  881.   .fail:
  882.         ret
  883.  
  884.  
  885. cmd_333:
  886.  
  887.         add     esi, 4  ; skip '333 '
  888.  
  889. ; TODO: check channelname and change pointer accordingly
  890.  
  891.         mov     ecx, 3  ; number of spaces to find
  892.   .loop:
  893.         lodsb
  894.         test    al, al
  895.         je      .fail
  896.         cmp     al, ' '
  897.         jne     .loop
  898.         dec     ecx
  899.         jnz     .loop   ; find some more spaces
  900.  
  901.         push    esi
  902.         mov     esi, action_header
  903.         call    print_text2
  904.  
  905.         mov     esi, str_setby
  906.         call    print_text2
  907.  
  908.         pop     esi
  909.         call    print_text2
  910.  
  911.         mov     esi, str_newline
  912.         call    print_text2
  913.  
  914.   .fail:
  915.         ret
  916.  
  917.