Subversion Repositories Kolibri OS

Rev

Rev 1302 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
481 diamond 1
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2
;
3
;    FTPS
4
;    FTP Server
5
;
6
;    Compile with FASM for Menuet
7
;
8
 
9
; note: telnet == 23, ftp cmd == 21, data on 20
10
 
11
use32
12
 
13
    org     0x0
14
 
15
    db      'MENUET01'              ; 8 byte id
16
    dd      1                       ; header version
17
    dd      START                   ; program start
18
    dd      I_END                   ; program image size
19
    dd      0x170000                ; required amount of memory
20
    dd      0x7FFF0                 ; esp = 0x7FFF0
21
    dd      0, 0                    ; no params, no path
22
 
661 ataualpa 23
include 'macros.inc'
481 diamond 24
; Various states of client connection
25
USER_NONE       equ 0   ; Awaiting a connection
26
USER_CONNECTED  equ 1   ; User just connected, prompt given
27
USER_USERNAME   equ 2   ; User given username
28
USER_LOGGED_IN  equ 3   ; User given password
29
 
30
 
31
 
32
 
33
 
34
START:                          ; start of execution
35
    ; Clear the screen memory
36
    mov     eax, '    '
37
    mov     edi,text
38
    mov     ecx,80*30 /4
39
    cld
40
    rep     stosd
41
 
42
    call    draw_window
43
 
44
    ; init the receive buffer pointer
45
    mov     [buffptr], buff
46
 
47
    ; Init FTP server state machine
48
    mov     [state], USER_NONE
49
 
50
    ; Open the listening socket
51
    call    connect
52
 
53
still:
54
    ; check connection status
55
    mov     eax,53
56
    mov     ebx,6               ; Get socket status
57
    mov     ecx,[CmdSocket]
485 heavyiron 58
    mcall
481 diamond 59
 
60
    mov     ebx, [CmdSocketStatus]
61
    mov     [CmdSocketStatus], eax
62
 
63
    cmp     eax, ebx
64
    je      waitev
65
 
66
    ; If the socket closed by remote host, open it again.
67
    cmp     eax, 7
68
    je      con
661 ataualpa 69
 
481 diamond 70
    ; If socket closed by Reset, open it again
71
    cmp     eax, 11
72
    je      con
73
 
74
    ; If a user has just connected, start by outputting welcome msg
75
    cmp     eax, 4
76
    jne     noc
77
 
78
    mov     esi, loginStr0
79
    mov     edx, loginStr0_end - loginStr0
80
    call    outputStr
81
 
82
    mov     [state], USER_CONNECTED
83
    jmp     noc
84
 
85
 
86
con:
87
    ; Need to call disconnect, since a remote close does not fully
88
    ; close the socket
89
    call    disconnect
1297 tsdima 90
    mov     eax,5
91
    mov     ebx,10          ; Delay for 100ms
92
    mcall
481 diamond 93
    call    connect
94
    jmp     noc
95
 
96
noc:
97
    ; Display the changed connected status
98
    call    draw_window
99
 
100
waitev:
101
    mov     eax,23                 ; wait here for event
102
    mov     ebx,1                 ; Delay for up to 1s
485 heavyiron 103
    mcall
481 diamond 104
 
105
    cmp     eax,1                  ; redraw request ?
106
    je      red
107
    cmp     eax,2                  ; key in buffer ?
108
    je      key
109
    cmp     eax,3                  ; button in buffer ?
110
    je      button
111
 
112
    ; any data from the socket?
113
 
114
    mov     eax, 53
115
    mov     ebx, 2                  ; Get # of bytes in input queue
116
    mov     ecx, [CmdSocket]
485 heavyiron 117
    mcall
481 diamond 118
    test    eax, eax
119
    jz      still
120
 
121
read_input:
122
    mov     eax, 53
123
    mov     ebx, 3                  ; Get a byte from socket in bl
124
    mov     ecx, [CmdSocket]
485 heavyiron 125
    mcall
481 diamond 126
 
127
    call    ftpRxCmdData            ; process incoming ftp command
128
 
129
    ; Keep processing data until there is no more to process
130
    mov     eax, 53
131
    mov     ebx, 2                  ; Get # of bytes in input queue
132
    mov     ecx, [CmdSocket]
485 heavyiron 133
    mcall
481 diamond 134
    cmp     eax, 0
135
    jne     read_input
136
 
137
    ; Now redraw the text text field.
138
    ; Probably not required, since ftp requires no
139
    ; console i/o.
140
    ; Leave in for now, for debugging.
141
; (fall through to "red:")
142
;    call    draw_text
143
;    jmp     still
144
 
145
red:                          ; REDRAW WINDOW
146
    call    draw_window
147
    jmp     still
148
 
149
key:                          ; KEY
150
    mov     eax,2                  ; get but ignore
485 heavyiron 151
    mcall
481 diamond 152
    jmp     still
153
 
154
button:
155
    mov     eax,17
485 heavyiron 156
    mcall
481 diamond 157
    cmp     ah,1
158
    jne     still
159
 
160
    ; Exit button pressed, so close socket and quit
161
    mov     eax,53
162
    mov     ebx,8
163
    mov     ecx,[CmdSocket]
485 heavyiron 164
    mcall
481 diamond 165
 
166
    ; ... terminate program
485 heavyiron 167
    or     eax,-1
168
    mcall
481 diamond 169
    jmp     still
170
 
171
 
172
 
173
;   *********************************************
174
;   *******  WINDOW DEFINITIONS AND DRAW ********
175
;   *********************************************
176
draw_window:
177
    pusha
178
 
179
    mov  eax,12
180
    mov  ebx,1
485 heavyiron 181
    mcall
481 diamond 182
 
183
    xor  eax,eax                   ; DRAW WINDOW
184
    mov  ebx,100*65536+491 + 8 +15
185
    mov  ecx,100*65536+270 + 20     ; 20 for status bar
661 ataualpa 186
    mov  edx,0x14000000
481 diamond 187
    mov  edi,labelt
485 heavyiron 188
    mcall
481 diamond 189
 
190
    ; draw status bar
191
    mov     eax, 13
192
    mov     ebx, 4*65536+484 + 8 +15
193
    mov     ecx, 270*65536 + 3
194
    mov     edx, 0x00557799
485 heavyiron 195
    mcall
481 diamond 196
 
197
 
198
    mov  esi,contlen-contt          ; display connected status
199
    mov     edx, contt
200
    cmp     [CmdSocketStatus], 4    ; 4 is connected
201
    je      pcon
202
    mov     esi,discontlen-discontt
203
    mov     edx, discontt
204
pcon:
205
 
206
    mov  eax,4                      ; status text
207
    mov  ebx,380*65536+276
208
    mov  ecx,0x00ffffff
485 heavyiron 209
    mcall
481 diamond 210
 
211
    ; Draw the text on the screen, clearing it first
212
    ; This can go when we loose debuggin info.
213
    xor  eax,eax
214
    mov  edi,text+80*30
215
    mov  ecx,80*30 /4
216
    cld
217
    rep  stosd
218
 
219
    call draw_text
220
 
221
    mov  eax,12
222
    mov  ebx,2
485 heavyiron 223
    mcall
481 diamond 224
 
225
    popa
226
 
227
    ret
228
 
229
 
230
;***************************************************************************
231
;   Function
232
;      draw_text
233
;
234
;   Description
235
;       Updates the text on the screen. This is part of the debugging code
236
;
237
;   Inputs
238
;       Character to add in bl
239
;
240
;***************************************************************************
241
draw_text:
242
 
243
    pusha
244
 
245
    mov  esi,text
246
    mov  eax,0
247
    mov  ebx,0
248
  newletter:
249
    mov  cl,[esi]
250
    cmp  cl,[esi+30*80]
251
    jz   noletter
252
  yesletter:
253
    mov  [esi+30*80],cl
254
 
255
    ; erase character
256
 
257
    pusha
258
    mov     edx, 0                  ; bg colour
259
    mov     ecx, ebx
260
    add     ecx, 26
261
    shl     ecx, 16
262
    mov     cx, 9
263
    mov     ebx, eax
264
    add     ebx, 6
265
    shl     ebx, 16
266
    mov     bx, 6
267
    mov     eax, 13
485 heavyiron 268
    mcall
481 diamond 269
    popa
270
 
271
    ; draw character
272
 
273
    pusha
274
    mov     ecx, 0x00ffffff
275
    push bx
276
    mov  ebx,eax
277
    add  ebx,6
278
    shl  ebx,16
279
    pop  bx
280
    add  bx,26
281
    mov  eax,4
282
    mov  edx,esi
283
    mov  esi,1
485 heavyiron 284
    mcall
481 diamond 285
    popa
286
 
287
  noletter:
288
 
289
    add  esi,1
290
    add  eax,6
291
    cmp  eax,80*6
292
    jb   newletter
293
    mov  eax,0
294
    add  ebx,10
295
    cmp  ebx,24*10
296
    jb   newletter
297
 
298
    popa
299
    ret
300
 
301
 
302
 
303
;***************************************************************************
304
;   Function
305
;      ftpRxCmdData
306
;
307
;   Description
308
;       Prcoesses incoming command data, calling a handler for each command.
309
;       Commands are built up in buff before being processed.
310
;
311
;   Inputs
312
;       Character to add in bl
313
;
314
;***************************************************************************
315
ftpRxCmdData:
316
    ; Quit if we are not connected
317
    ;( This case shouldn't be necessary, but be safe )
318
    mov     al, [state]
319
    cmp     al, USER_NONE
320
    je      frcd_exit
321
 
322
    ; Store the incoming character
323
    mov     esi, [buffptr]
324
    mov     [esi], bl
325
    inc     esi
326
    mov     [buffptr], esi
327
 
328
    ; For debugging, show the data coming in
329
    pusha
330
    call    printChar
331
    popa
332
 
333
    ; Do we have an end of line? (LF)
334
    ; if not, just exit
335
    cmp     bl, 0x0a
336
    jne     frcd_exit
337
 
338
    ; OK we have a complete command.
339
    ; Process, and send response
340
 
341
    ; There are a number of states involved in ftp,
342
    ; to do with logging in.
343
 
344
    mov     al, [state]
345
    cmp     al, USER_CONNECTED
346
    jne     fs001
347
 
348
    ; This should be the username
349
 
350
    ; TODO validate username
351
 
352
    ; OK, username accepted - ask for password
353
    mov     esi, loginStr1
354
    mov     edx, loginStr1_end - loginStr1
355
    call    outputStr
356
 
357
    mov     [state], USER_USERNAME
358
 
359
    ; init the receive buffer pointer
360
    mov     [buffptr], buff
361
 
362
    jmp     frcd_exit
363
 
364
fs001:
365
    cmp     al, USER_USERNAME
366
    jne     fs002
367
 
368
    ; This should be the password
369
 
370
    ; TODO validate password
371
 
372
    ; OK, password accepted - show they are logged in
373
    mov     esi, loginStr2
374
    mov     edx, loginStr2_end - loginStr2
375
    call    outputStr
376
 
377
    mov     [state], USER_LOGGED_IN
378
 
379
    ; init the receive buffer pointer
380
    mov     [buffptr], buff
381
 
382
    jmp     frcd_exit
383
 
384
fs002:
385
    cmp     al, USER_LOGGED_IN
386
    jne     fs003
387
 
388
    ; This should be a cmd
389
    call    findCmd
390
    mov     eax, [cmdPtr]
391
    cmp     eax, 0
392
 
393
    je      fs002b
394
 
395
    call    [cmdPtr]
396
 
397
fs002a:
398
    ; init the receive buffer pointer
399
    mov     [buffptr], buff
400
 
401
    jmp     frcd_exit
402
 
403
fs002b:
404
    ; an unsupported command was entered.
405
    ; Tell user that the command is not supported
406
 
407
    mov     esi, unsupStr
408
    mov     edx, unsupStr_end - unsupStr
409
    call    outputStr
410
 
411
    jmp     fs002a
412
 
413
fs003:
414
frcd_exit:
415
    ret
416
 
417
 
418
 
419
;***************************************************************************
420
;   Function
421
;      outputStr
422
;
423
;   Description
424
;       Sends a string over the 'Command' socket
425
;
426
;   Inputs
427
;       String in esi
428
;       Length in edx
429
;
430
;***************************************************************************
431
outputStr:
432
    push    esi
433
    push    edx
434
    mov     eax,53
435
    mov     ebx,7
436
    mov     ecx,[CmdSocket]
485 heavyiron 437
    mcall
481 diamond 438
    pop     edx
439
    pop     esi
661 ataualpa 440
 
481 diamond 441
    cmp     eax, 0
442
    je      os_exit
661 ataualpa 443
 
444
    ; The TCP/IP transmit queue is full; Wait a bit, then retry
481 diamond 445
    pusha
446
    mov     eax,5
1301 tsdima 447
    mov     ebx,1                 ; Delay for up 10ms
485 heavyiron 448
    mcall
481 diamond 449
    popa
661 ataualpa 450
    jmp     outputStr
481 diamond 451
os_exit:
452
    ret
453
 
454
 
455
 
456
;***************************************************************************
457
;   Function
458
;      outputDataStr
459
;
460
;   Description
461
;       Sends a string over the 'Data' socket
462
;
463
;   Inputs
464
;       String in esi
465
;       Length in edx
466
;
467
;***************************************************************************
468
outputDataStr:
469
    push    esi
470
    push    edx
471
    mov     eax,53
472
    mov     ebx,7
473
    mov     ecx,[DataSocket]
485 heavyiron 474
    mcall
481 diamond 475
    pop     edx
476
    pop     esi
477
 
478
    cmp     eax, 0
479
    je      ods_exit
480
 
661 ataualpa 481
    ; The TCP/IP transmit queue is full; Wait a bit, then retry
481 diamond 482
    pusha
483
    mov     eax,5
1301 tsdima 484
    mov     ebx,1                 ; Delay for up 10ms
485 heavyiron 485
    mcall
481 diamond 486
    popa
661 ataualpa 487
    jmp     outputDataStr
481 diamond 488
ods_exit:
489
    ret
490
 
491
 
492
 
493
;***************************************************************************
494
;   Function
495
;      printChar
496
;
497
;   Description
498
;       Writes a character to the screen; Used to display the data coming
499
;       in from the user. Really only useful for debugging.
500
;
501
;   Inputs
502
;       Character in bl
503
;
504
;***************************************************************************
505
printChar:
506
    cmp     bl,13                          ; BEGINNING OF LINE
507
    jne     nobol
508
    mov     ecx,[pos]
509
    add     ecx,1
510
boll1:
511
    sub     ecx,1
512
    mov     eax,ecx
513
    xor     edx,edx
514
    mov     ebx,80
515
    div     ebx
516
    cmp     edx,0
517
    jne     boll1
518
    mov     [pos],ecx
519
    jmp     newdata
520
nobol:
521
 
522
    cmp     bl,10                            ; LINE DOWN
523
    jne     nolf
524
addx1:
525
    add     [pos],dword 1
526
    mov     eax,[pos]
527
    xor     edx,edx
528
    mov     ecx,80
529
    div     ecx
530
    cmp     edx,0
531
    jnz     addx1
532
    mov     eax,[pos]
533
    jmp     cm1
534
nolf:
535
 
536
    cmp     bl,8                            ; BACKSPACE
537
    jne     nobasp
538
    mov     eax,[pos]
539
    dec     eax
540
    mov     [pos],eax
541
    mov     [eax+text],byte 32
542
    mov     [eax+text+60*80],byte 0
543
    jmp     newdata
544
nobasp:
545
 
546
    cmp     bl,15                           ; CHARACTER
547
    jbe     newdata
548
putcha:
549
    mov     eax,[pos]
550
    mov     [eax+text],bl
551
    mov     eax,[pos]
552
    add     eax,1
553
cm1:
554
    mov     ebx,[scroll+4]
555
    imul    ebx,80
556
    cmp     eax,ebx
557
    jb      noeaxz
558
    mov     esi,text+80
559
    mov     edi,text
560
    mov     ecx,ebx
561
    cld
562
    rep     movsb
563
    mov     eax,ebx
564
    sub     eax,80
565
noeaxz:
566
    mov     [pos],eax
567
newdata:
568
    ret
569
 
570
 
571
;***************************************************************************
572
;   Function
573
;      disconnect
574
;
575
;   Description
576
;       Closes the command socket
577
;
578
;   Inputs
579
;       None
580
;
581
;***************************************************************************
582
disconnect:
583
    mov     eax, 53         ; Stack Interface
584
    mov     ebx,8           ; Close TCP socket
585
    mov     ecx,[CmdSocket]
485 heavyiron 586
    mcall
481 diamond 587
    ret
588
 
589
 
661 ataualpa 590
 
481 diamond 591
;***************************************************************************
592
;   Function
593
;      disconnectData
594
;
595
;   Description
596
;       Closes the data socket
597
;
598
;   Inputs
599
;       None
600
;
601
;***************************************************************************
602
disconnectData:
603
    ; This delay would be better done by allowing the socket code
604
    ; to wait for all data to pass through the stack before closing
605
    pusha
606
    mov     eax,5
1287 tsdima 607
    mov     ebx,10          ; Delay for 100ms
485 heavyiron 608
    mcall
481 diamond 609
    popa
610
 
611
    mov     eax, 53         ; Stack Interface
612
    mov     ebx,8           ; Close TCP socket
613
    mov     ecx,[DataSocket]
485 heavyiron 614
    mcall
481 diamond 615
    ret
616
 
617
 
618
 
619
 
620
;***************************************************************************
621
;   Function
622
;      connect
623
;
624
;   Description
625
;       Opens the command socket
626
;
627
;   Inputs
628
;       None
629
;
630
;***************************************************************************
631
connect:
632
    pusha
633
 
634
    mov     eax, 53     ; Stack Interface
635
    mov     ebx, 5      ; Open TCP socket
636
    mov     esi, 0      ; No remote IP address
637
    mov     edx, 0      ; No remote port
638
    mov     ecx, 21     ; ftp command port id
639
    mov     edi, 0      ; passive open
485 heavyiron 640
    mcall
481 diamond 641
    mov     [CmdSocket], eax
642
 
643
    popa
644
 
645
    ret
646
 
647
 
648
 
649
;***************************************************************************
650
;   Function
651
;      connectData
652
;
653
;   Description
654
;       Opens the data socket
655
;
656
;   Inputs
657
;       None
658
;
659
;***************************************************************************
660
connectData:
661
    pusha
662
 
663
    mov     eax, 53     ; Stack Interface
664
    mov     ebx, 5      ; Open TCP socket
665
    mov     esi, [DataIP]      ; remote IP address
666
    mov     edx, [DataPort]    ; remote port
1287 tsdima 667
    mov     ecx, 0      ; ftp data port id
481 diamond 668
    mov     edi, 1      ; active open
485 heavyiron 669
    mcall
481 diamond 670
    mov     [DataSocket], eax
671
 
672
    popa
673
 
674
    ret
675
 
676
 
677
 
678
 
679
;***************************************************************************
680
;   Function
681
;      findCmd
682
;
683
;   Description
684
;       Scans the command string for a valid command. The command string
685
;       is in the global variable buff.
686
;
687
;       Returns result in cmdPtr. This will be zero if none found
688
;
689
;   Inputs
690
;       None
691
;
692
;***************************************************************************
693
findCmd:
694
    ; Setup to return 'none' in cmdPtr, if we find no cmd
695
    mov     eax, 0
696
    mov     [cmdPtr], eax
697
    cld
698
    mov     esi, buff
699
    mov     edi, CMDList
700
 
701
fc000:
702
    cmp     [edi], byte 0   ; Are we at the end of the CMDList?
703
    je      fc_exit
704
 
705
fc000a:
706
    cmpsb
707
 
708
    je      fc_nextbyte
709
 
710
    ; Command is different - move to the next entry in cmd table
711
    mov     esi, buff
712
 
713
fc001:
714
    ; skip to the next command in the list
715
    cmp     [edi], byte 0
716
    je      fc002
717
    inc     edi
718
    jmp     fc001
719
fc002:
720
    add     edi, 5
721
    jmp     fc000
722
 
723
fc_nextbyte:
724
    ; Have we reached the end of the CMD text?
725
    cmp     [edi], byte 0
726
    je      fc_got      ; Yes - so we have a match
727
    jmp     fc000a      ; No - loop back
728
 
729
fc_got:
730
    ; Copy the function pointer for the selected command
731
    inc     edi
732
    mov     eax, [edi]
733
    mov     [cmdPtr], eax
734
 
735
fc_exit:
736
    ret
737
 
738
 
739
 
740
;***************************************************************************
741
;   Function
742
;      decStr2Byte
743
;
744
;   Description
745
;       Converts the decimal string pointed to by esi to a byte
746
;
747
;   Inputs
748
;       string ptr in esi
749
;
750
;   Outputs
751
;       esi points to next character not in string
752
;       eax holds result ( 0..255)
753
;
754
;***************************************************************************
755
decStr2Byte:
756
    xor     eax, eax
757
    xor     ebx, ebx
758
    mov     ecx, 3
759
 
760
dsb001:
761
    mov     bl, [esi]
762
 
763
    cmp     bl, '0'
764
    jb      dsb_exit
765
    cmp     bl, '9'
766
    ja      dsb_exit
767
 
768
    imul    eax, 10
769
    add     eax, ebx
770
    sub     eax, '0'
771
    inc     esi
772
    loop    dsb001
773
 
774
dsb_exit:
775
    ret
776
 
777
 
778
 
779
;***************************************************************************
780
;   Function
781
;      parsePortStr
782
;
783
;   Description
784
;       Converts the parameters of the PORT command, and stores them in the
785
;       appropriate variables.
786
;
787
;   Inputs
788
;       None ( string in global variable buff )
789
;
790
;   Outputs
791
;       None
792
;
793
;***************************************************************************
794
parsePortStr:
795
    ; skip past the PORT text to get the the parameters. The command format
796
    ; is
797
    ; PORT i,i,i,i,p,p,0x0d,0x0a
798
    ; where i and p are decimal byte values, high byte first.
799
    xor     eax, eax
800
    mov     [DataIP], eax
801
    mov     [DataPort], eax
802
    mov     esi, buff + 4       ; Start at first space character
803
 
804
pps001:
805
    cmp     [esi], byte ' '     ; Look for first non space character
806
    jne     pps002
807
    inc     esi
808
    jmp     pps001
809
 
810
pps002:
811
    call    decStr2Byte
812
    add     [DataIP], eax
813
    ror     dword [DataIP], 8
814
    inc     esi
815
    call    decStr2Byte
816
    add     [DataIP], eax
817
    ror     dword [DataIP], 8
818
    inc     esi
819
    call    decStr2Byte
820
    add     [DataIP], eax
821
    ror     dword [DataIP], 8
822
    inc     esi
823
    call    decStr2Byte
824
    add     [DataIP], eax
825
    ror     dword [DataIP], 8
826
    inc     esi
827
    call    decStr2Byte
828
    add     [DataPort], eax
829
    shl     [DataPort], 8
830
    inc     esi
831
    call    decStr2Byte
832
    add     [DataPort], eax
833
 
834
    ret
835
 
836
 
837
 
838
;***************************************************************************
839
;   Function
840
;      sendDir
841
;
842
;   Description
843
;       Transmits the directory listing over the data connection.
844
;       The data connection is already open.
845
;
846
;   Inputs
661 ataualpa 847
;       None
481 diamond 848
;
849
;   Outputs
850
;       None
851
;
852
;***************************************************************************
853
sendDir:
1323 tsdima 854
        mov     eax, text+0x4000
855
        mov     [fsize], eax
481 diamond 856
        mov     ebx, dirinfoblock
857
        and     dword [ebx+4], 0        ; start from zero block
858
sd001:
859
; Read the next DirBlocksPerCall (=16) blocks
860
        mov     eax, 70
485 heavyiron 861
        mcall
481 diamond 862
; Did we read anything?
863
        test    eax, eax
864
        jz      @f
865
        cmp     eax, 6
866
        jnz     sd_exit
867
@@:
868
        test    ebx, ebx
869
        jz      sd_exit
870
; Parse these blocks. There could be up to 16 files specified
871
        mov     esi, text + 0x1300 + 0x20
872
sd002:
873
        dec     ebx
874
        js      sd004
875
        push    ebx
876
; OK, lets parse the entry. Ignore volume entries
877
        test    byte [esi], 8
878
        jnz     sd003
879
; Valid file or directory. Start to compose the string we will send
880
        mov     edi, dirStr
881
; If we have been called as a result of an NLST command, we only display
882
; the filename
883
        cmp     [buff], byte 'N'
884
        jz      sd006
885
 
886
        mov     [edi], byte '-'
887
        test    byte [esi], 10h
888
        jz      @f
889
        mov     [edi], byte 'd'
890
@@:
891
; Ok, now copy across the directory listing text that will be constant
892
; ( I dont bother looking at the read only or archive bits )
893
 
894
        mov     ebx, tmplStr
895
@@:
896
        inc     edi
897
        mov     al, [ebx]
898
        test    al, al
899
        jz      @f
900
        mov     [edi], al
901
        inc     ebx
902
        jmp     @b
903
@@:
904
; point to the last character of the string;
905
; We will write the file size here, backwards
906
        push    edi             ; Remember where the string ends
907
 
908
        dec     edi
909
; eax holds the number
910
        mov     eax, [esi+32]
911
        mov     ebx, 10
912
@@:
913
        xor     edx, edx
914
        div     ebx
915
        add     dl, '0'
916
        mov     [edi], dl
917
        dec     edi
918
        test    eax, eax
919
        jnz     @b
920
 
921
        pop     edi
922
; now create the time & date fields
923
;timeStr:            db ' Jan 1    2000 ',0
924
        mov     al, ' '
925
        stosb
926
        movzx   eax, byte [esi+28+1]
927
        mov     eax, dword [months + (eax-1)*4]
928
        stosd
929
        mov     al, byte [esi+28]
930
        aam
931
        test    ah, ah
932
        jz      sd005a
933
        xchg    al, ah
934
        add     ax, '00'
935
        jmp     sd005b
936
sd005a:
937
        add     al, '0'
938
        mov     ah, ' '
939
sd005b:
940
        stosw
941
        mov     al, ' '
942
        mov     ecx, 6
943
        rep     stosb
944
        push    edi
945
        movzx   eax, word [esi+28+2]
946
@@:
947
        xor     edx, edx
948
        div     ebx
949
        add     dl, '0'
950
        mov     [edi], dl
951
        dec     edi
952
        test    eax, eax
953
        jnz     @b
954
        pop     edi
955
        inc     edi
956
        mov     al, ' '
957
        stosb
958
sd006:
959
; ** End of copying
960
 
961
; now copy the filename across
962
        lea     ebx, [esi+40]
963
@@:
964
        mov     al, [ebx]
965
        inc     ebx
966
        test    al, al
967
        jz      @f
968
        stosb
969
        jmp     @b
970
@@:
971
terminate:
972
; Now terminate the line by putting CRLF sequence in
973
        mov     al, 0x0D
974
        stosb
975
        mov     al, 0x0A
976
        stosb
977
; Send the completed line to the user over data socket
978
        push    esi
1323 tsdima 979
        push    edi
481 diamond 980
        mov     esi, dirStr
1323 tsdima 981
        mov     ecx, edi
982
        sub     ecx, esi
983
        mov     edi, [fsize]
984
        cld
985
        rep     movsb
986
        mov     [fsize], edi
987
        cmp     edi, text+0x4400
988
        jb      @f
989
        mov     esi, text+0x4000
990
        mov     edx, [fsize]
481 diamond 991
        sub     edx, esi
1323 tsdima 992
        mov     [fsize], esi
481 diamond 993
        call    outputDataStr
1323 tsdima 994
 
995
@@:
996
        pop     edi
481 diamond 997
        pop     esi
998
 
999
sd003:                  ; Move to next entry in the block
1000
        pop     ebx
1001
        add     esi, 304
1002
        jmp     sd002
1003
sd004:
1004
        mov     ebx, dirinfoblock
1005
        add     dword [ebx+4], DirBlocksPerCall
1006
        jmp     sd001
1007
 
1008
sd_exit:
1323 tsdima 1009
        mov     esi, text+0x4000
1010
        mov     edx, [fsize]
1011
        sub     edx, esi
1012
        call    outputDataStr
481 diamond 1013
        ret
1014
 
1015
 
1016
 
1017
 
1018
 
1019
;***************************************************************************
1020
;   Function
1021
;      setupFilePath
1022
;
1023
;   Description
1024
;       Copies the file name from the input request string into the
1025
;       file descriptor
1026
;
1027
;   Inputs
661 ataualpa 1028
;       None
481 diamond 1029
;
1030
;   Outputs
1031
;       None
1032
;
1033
;***************************************************************************
1034
setupFilePath:
1035
    mov     esi, buff + 4       ; Point to (1 before) first character of file
661 ataualpa 1036
 
481 diamond 1037
    ; Skip any trailing spaces or / character
661 ataualpa 1038
sfp001:
481 diamond 1039
    inc     esi
1040
    cmp     [esi], byte ' '
1041
    je      sfp001
1042
    cmp     [esi], byte '/'
1043
    je      sfp001
661 ataualpa 1044
 
481 diamond 1045
    ; esi points to start of filename.
661 ataualpa 1046
 
1047
 
481 diamond 1048
    ; Copy across the directory path '/'
1049
    ; into the fileinfoblock
1050
    mov     edi, filename
1051
    mov     dword [edi], '/RD/'
1052
    mov     word [edi+4], '1/'
1053
    add     edi, 6
661 ataualpa 1054
 
481 diamond 1055
    ; Copy across the filename
1056
sfp002:
1057
    cld
1058
    movsb
1059
    cmp     [esi], byte 0x0d
1060
    jne     sfp002
661 ataualpa 1061
    mov     [edi], byte 0
481 diamond 1062
    ret
1063
 
1064
 
1065
 
1066
 
1067
;***************************************************************************
1068
;   Function
1069
;      sendFile
1070
;
1071
;   Description
1072
;       Transmits the requested file over the open data socket
1073
;       The file to send is named in the buff string
1074
;
1075
;   Inputs
661 ataualpa 1076
;       None
481 diamond 1077
;
1078
;   Outputs
1079
;       None
1080
;
1081
;***************************************************************************
1082
sendFile:
1083
    call    setupFilePath
1084
 
1085
    ; init fileblock descriptor, for file read
1086
    mov     ebx, fileinfoblock
1087
    and     dword [ebx], 0 ; read cmd
1088
    and     dword [ebx+4], 0 ; first block
1301 tsdima 1089
    mov     dword [ebx+12], 0x400 ; block size
481 diamond 1090
 
1091
sf002a:
661 ataualpa 1092
    ; now read the file..
481 diamond 1093
    mov     eax,70
485 heavyiron 1094
    mcall
481 diamond 1095
    test    eax, eax
1096
    jz      @f
1097
    cmp     eax, 6
1098
    jnz     sf_exit
1099
@@:
1100
    push    eax
1101
    mov     esi, text + 0x1300
1102
    mov     edx, ebx
1103
    call    outputDataStr
1104
    pop     eax
1105
    test    eax, eax
1106
    jnz     sf_exit
1107
; wait a bit
1108
    mov     eax, 5
1301 tsdima 1109
    mov     ebx, 1
485 heavyiron 1110
    mcall
481 diamond 1111
    mov     ebx, fileinfoblock
1112
    add     dword [ebx+4], edx
1113
    jmp     sf002a
1114
 
661 ataualpa 1115
sf_exit:
481 diamond 1116
    ret
1117
 
661 ataualpa 1118
 
481 diamond 1119
;***************************************************************************
1120
;   Function
1121
;      getFile
1122
;
1123
;   Description
1124
;       Receives the specified file over the open data socket
1125
;       The file to receive is named in the buff string
1126
;
1127
;   Inputs
661 ataualpa 1128
;       None
481 diamond 1129
;
1130
;   Outputs
1131
;       None
1132
;
1133
;***************************************************************************
1134
getFile:
1135
    call    setupFilePath
661 ataualpa 1136
 
481 diamond 1137
    ; init fileblock descriptor, for file write
1138
    xor     eax, eax
1139
    mov     [fsize], eax            ; Start filelength at 0
1140
    mov     [fileinfoblock+4], eax    ; set to 0
1141
    inc     eax
1142
    inc     eax
1143
    mov     [fileinfoblock], eax    ; write cmd
661 ataualpa 1144
 
481 diamond 1145
    ; Read data from the socket until the socket closes
1146
    ; loop
1147
    ;   loop
1148
    ;     read byte from socket
1149
    ;     write byte to file buffer
1150
    ;   until no more bytes in socket
1151
    ;   sleep 100ms
1152
    ; until socket no longer connected
1153
    ; write file to ram
661 ataualpa 1154
 
481 diamond 1155
gf000:
1156
    mov     eax, 53
1157
    mov     ebx, 2                  ; Get # of bytes in input queue
1158
    mov     ecx, [DataSocket]
485 heavyiron 1159
    mcall
481 diamond 1160
    test    eax, eax
1161
    je      gf_sleep
661 ataualpa 1162
 
481 diamond 1163
    mov     eax, 53
1301 tsdima 1164
    mov     ebx, 11                 ; Get a bytes from socket
481 diamond 1165
    mov     ecx, [DataSocket]
1301 tsdima 1166
    mov     edx, text + 0x1300
1167
    add     edx, dword [fsize]
1323 tsdima 1168
    xor     esi, esi
1301 tsdima 1169
    mcall                           ; returned data len in eax
1170
    add     dword [fsize], eax
661 ataualpa 1171
 
481 diamond 1172
    jmp     gf000
1173
 
1174
gf_sleep:
1175
    ; Check to see if socket closed...
1176
    mov     eax,53
1177
    mov     ebx,6               ; Get socket status
1178
    mov     ecx,[DataSocket]
485 heavyiron 1179
    mcall
481 diamond 1180
 
1181
    cmp     eax, 7
1182
    jne     gf001               ; still open, so just sleep a bit
1183
 
1184
    ; Finished, so write the file
1185
    mov     eax, [fsize]
1186
    mov     [fileinfoblock+12], eax
1187
    mov     eax,70
1188
    mov     ebx,fileinfoblock
485 heavyiron 1189
    mcall
481 diamond 1190
 
1191
    ret                         ; Finished
1192
 
1193
gf001:
1194
    ; wait a bit
1195
    mov     eax,5
1301 tsdima 1196
    mov     ebx,1               ; Delay for up 10ms
485 heavyiron 1197
    mcall
481 diamond 1198
    jmp     gf000               ; try for more data
1199
 
1200
 
1201
 
661 ataualpa 1202
 
1203
 
481 diamond 1204
;***************************************************************************
1205
;   COMMAND HANDLERS FOLLOW
1206
;
1207
;   These handlers implement the functionality of each supported FTP Command
1208
;
1209
;***************************************************************************
1210
 
1211
cmdPWD:
1212
    ; OK, show the directory name text
1213
    mov     esi, ramdir
1214
    mov     edx, ramdir_end - ramdir
1215
    call    outputStr
1216
 
1217
    ; TODO give real directory
1218
 
1219
    ret
1220
 
1221
 
1222
cmdCWD:
1223
    ; Only / is valid for the ramdisk
1224
    cmp     [buff+5], byte 0x0d
1225
    jne     ccwd_000
661 ataualpa 1226
 
481 diamond 1227
    ; OK, show the directory name text
1228
    mov     esi, chdir
1229
    mov     edx, chdir_end - chdir
1230
    jmp     ccwd_001
661 ataualpa 1231
 
481 diamond 1232
ccwd_000:
1233
    ; Tell user there is no such directory
1234
    mov     esi, noFileStr
1235
    mov     edx, noFileStr_end - noFileStr
1236
 
1237
ccwd_001:
1238
    call    outputStr
1239
 
1240
    ret
1241
 
1242
 
1243
cmdQUIT:
1244
    ; The remote end will do the close; We just
1245
    ; say goodbye.
1246
    mov     esi, byeStr
1247
    mov     edx, byeStr_end - byeStr
1248
    call    outputStr
1249
    ret
1250
 
1251
 
1252
cmdABOR:
1253
 
1254
    ; Close port
1255
    call    disconnectData
1256
 
1257
    mov     esi, abortStr
1258
    mov     edx, abortStr_end - abortStr
1259
    call    outputStr
1260
 
1261
    ret
1262
 
1263
cmdPORT:
1264
    ; TODO
1265
    ; Copy the IP and port values to DataIP and DataPort
1266
 
1267
    call    parsePortStr
1268
 
1269
    ; Indicate the command was accepted
1270
    mov     esi, cmdOKStr
1271
    mov     edx, cmdOKStr_end - cmdOKStr
1272
    call    outputStr
1273
    ret
1274
 
1275
cmdnoop:
1276
    ; Indicate the command was accepted
1277
    mov     esi, cmdOKStr
1278
    mov     edx, cmdOKStr_end - cmdOKStr
1279
    call    outputStr
1280
    ret
1281
 
1282
 
1283
cmdTYPE:
1284
    ; TODO
1285
    ; Note the type field selected - reject if needed.
1286
 
1287
    ; Indicate the command was accepted
1288
    mov     esi, cmdOKStr
1289
    mov     edx, cmdOKStr_end - cmdOKStr
1290
    call    outputStr
1291
    ret
1292
 
1293
cmdsyst:
1294
    ; Indicate the system type
1295
    mov     esi, systStr
1296
    mov     edx, systStr_end - systStr
1297
    call    outputStr
1298
    ret
1299
 
1300
 
1301
cmdDELE:
1302
    call    setupFilePath
1303
 
1304
    mov     ebx, fileinfoblock
1305
    mov     dword [ebx], 8
1306
    and     dword [ebx+4], 0
1307
    push    dword [ebx+12]
1308
    push    dword [ebx+16]
1309
    and     dword [ebx+12], 0
1310
    and     dword [ebx+16], 0
1311
    mov     eax, 70
485 heavyiron 1312
    mcall
1302 tsdima 1313
    mov     ebx, fileinfoblock
481 diamond 1314
    pop     dword [ebx+16]
1315
    pop     dword [ebx+12]
661 ataualpa 1316
 
481 diamond 1317
    test    eax, eax
1318
    jne     cmdDele_err
1319
 
1320
    mov     esi, delokStr
1321
    mov     edx, delokStr_end - delokStr
1322
    call    outputStr
661 ataualpa 1323
 
481 diamond 1324
    jmp     cmdDele_exit
661 ataualpa 1325
 
1326
cmdDele_err:
481 diamond 1327
    mov     esi, noFileStr
1328
    mov     edx, noFileStr_end - noFileStr
1329
    call    outputStr
661 ataualpa 1330
 
1331
 
481 diamond 1332
cmdDele_exit:
1333
    ret
1334
 
1335
 
1336
cmdNLST:
1337
cmdLIST:
1338
    ; Indicate the command was accepted
1339
    mov     esi, startStr
1340
    mov     edx, startStr_end - startStr
1341
    call    outputStr
1342
 
1343
    call    connectData
1344
 
1345
    ; Wait for socket to establish
1346
 
1347
cl001:
1348
    ; wait a bit
1349
    mov     eax,5
1350
    mov     ebx,10                ; Delay for up 100ms
485 heavyiron 1351
    mcall
481 diamond 1352
 
1353
    ; check connection status
1354
    mov     eax,53
1355
    mov     ebx,6               ; Get socket status
1356
    mov     ecx,[DataSocket]
485 heavyiron 1357
    mcall
481 diamond 1358
 
1359
    cmp     eax, 4
1360
    jne     cl001
1361
 
1362
    ; send directory listing
1363
    call    sendDir
661 ataualpa 1364
 
481 diamond 1365
    ; Close port
1366
    call    disconnectData
1367
 
1368
    mov     esi, endStr
1369
    mov     edx, endStr_end - endStr
1370
    call    outputStr
1371
    ret
1372
 
1373
cmdRETR:
1374
    ; Indicate the command was accepted
1375
    mov     esi, startStr
1376
    mov     edx, startStr_end - startStr
1377
    call    outputStr
1378
 
1379
    call    connectData
1380
 
1381
    ; Wait for socket to establish
1382
 
1383
cr001:
1384
    ; wait a bit
1385
    mov     eax,5
1386
    mov     ebx,10                ; Delay for up 100ms
485 heavyiron 1387
    mcall
481 diamond 1388
 
1389
    ; check connection status
1390
    mov     eax,53
1391
    mov     ebx,6               ; Get socket status
1392
    mov     ecx,[DataSocket]
485 heavyiron 1393
    mcall
481 diamond 1394
 
1395
    cmp     eax, 4
1396
    jne     cr001
1397
 
1398
    ; send data to remote user
1399
    call    sendFile
661 ataualpa 1400
 
481 diamond 1401
    ; Close port
1402
    call    disconnectData
1403
 
1404
    mov     esi, endStr
1405
    mov     edx, endStr_end - endStr
1406
    call    outputStr
1407
 
1408
 
1409
    ret
1410
 
1411
 
1412
cmdSTOR:
1413
    ; Indicate the command was accepted
1414
    mov     esi, storStr
1415
    mov     edx, storStr_end - storStr
1416
    call    outputStr
1417
 
1418
    call    connectData
1419
 
1420
    ; Wait for socket to establish
1421
 
1422
cs001:
1423
    ; wait a bit
1424
    mov     eax,5
1425
    mov     ebx,10                ; Delay for up 100ms
485 heavyiron 1426
    mcall
481 diamond 1427
 
1428
    ; check connection status
1429
    mov     eax,53
1430
    mov     ebx,6               ; Get socket status
1431
    mov     ecx,[DataSocket]
485 heavyiron 1432
    mcall
481 diamond 1433
 
1434
    cmp     eax, 4
1435
    je      @f
1436
    cmp     eax, 7
1437
    jne     cs001
1438
@@:
1439
 
1440
    ; get data file from remote user
1441
    call    getFile
661 ataualpa 1442
 
481 diamond 1443
    mov     esi, endStr
1444
    mov     edx, endStr_end - endStr
1445
    call    outputStr
1446
 
1447
    ; Close port
1448
    call    disconnectData
1449
 
1450
    ret
1451
 
1452
 
1453
 
1454
; DATA AREA
1455
 
1456
; This is the list of supported commands, and the function to call
1457
; The list end with a NULL.
1458
CMDList:
1459
                    db  'pwd',0
1460
                    dd  cmdPWD
1461
 
1462
                    db  'PWD',0
1463
                    dd  cmdPWD
1464
 
1465
                    db  'XPWD',0
1466
                    dd  cmdPWD
1467
 
1468
                    db  'xpwd',0
1469
                    dd  cmdPWD
1470
 
1471
                    db  'QUIT',0
1472
                    dd  cmdQUIT
1473
 
1474
                    db  'quit',0
1475
                    dd  cmdQUIT
1476
 
1477
                    db  'PORT',0
1478
                    dd  cmdPORT
1479
 
1480
                    db  'port',0
1481
                    dd  cmdPORT
1482
 
1483
                    db  'LIST',0
1484
                    dd  cmdLIST
1485
 
1486
                    db  'list',0
1487
                    dd  cmdLIST
1488
 
1489
                    db  'NLST',0
1490
                    dd  cmdNLST
1491
 
1492
                    db  'nlst',0
1493
                    dd  cmdNLST
1494
 
1495
                    db  'TYPE',0
1496
                    dd  cmdTYPE
1497
 
1498
                    db  'type',0
1499
                    dd  cmdTYPE
1500
 
1501
                    db  'syst',0
1502
                    dd  cmdsyst
1503
 
1504
                    db  'noop',0
1505
                    dd  cmdnoop
1506
 
1507
                    db  'CWD',0
1508
                    dd  cmdCWD
1509
 
1510
                    db  'cwd',0
1511
                    dd  cmdCWD
1512
 
1513
                    db  'RETR',0
1514
                    dd  cmdRETR
1515
 
1516
                    db  'retr',0
1517
                    dd  cmdRETR
1518
 
1519
                    db  'DELE',0
1520
                    dd  cmdDELE
1521
 
1522
                    db  'dele',0
1523
                    dd  cmdDELE
1524
 
1525
                    db  'stor',0
1526
                    dd  cmdSTOR
1527
 
1528
                    db  'STOR',0
1529
                    dd  cmdSTOR
1530
 
1531
                    db  'ABOR',0
1532
                    dd  cmdABOR
1533
 
1534
                    db  'abor',0
1535
                    dd  cmdABOR
1536
 
1537
                    db  0xff,0xf4,0xff,0xf2,'ABOR',0
1538
                    dd  cmdABOR
1539
 
1540
                    db  0
1541
 
1542
 
1543
cmdPtr              dd  0
1544
CmdSocket           dd  0x0
1545
CmdSocketStatus     dd  0x0
1546
DataSocket          dd  0x0
1547
DataSocketStatus    dd  0x0
1548
DataPort            dd  0x00
1549
DataIP              dd  0x00
1550
pos                 dd  80 * 1
1551
scroll              dd  1
1552
                    dd  24
1553
 
1554
labelt              db  'FTP Server v0.1',0
1555
contt               db  'Connected'
1556
contlen:
1557
discontt            db  'Disconnected'
1558
discontlen:
1559
 
1560
cmdOKStr:           db  '200 Command OK',0x0d,0x0a
1561
cmdOKStr_end:
1562
 
1563
loginStr0:          db  '220-  Menuet FTP Server v0.1',0x0d,0x0a
1564
                    db  '220 Username and Password required',0x0d,0x0a
1565
loginStr0_end:
1566
 
1567
loginStr1:          db  '331 Password now required',0x0d,0x0a
1568
loginStr1_end:
1569
 
1570
loginStr2:          db  '230 You are now logged in.',0x0d,0x0a
1571
loginStr2_end:
1572
 
1573
byeStr:             db  '221 Bye bye!',0x0d,0x0a
1574
byeStr_end:
1575
 
1576
systStr:            db  '215 UNIX system type',0x0d,0x0a
1577
systStr_end:
1578
 
1579
ramdir:             db  '257 "/"',0x0d,0x0a
1580
ramdir_end:
1581
 
1582
chdir:              db  '200 directory changed to /',0x0d,0x0a
1583
chdir_end:
1584
 
1585
unsupStr:           db  '500 Unsupported command',0x0d,0x0a
1586
unsupStr_end:
1587
 
1588
noFileStr:          db  '550 No such file',0x0d,0x0a
1589
noFileStr_end:
1590
 
1591
delokStr:           db  '250 DELE command successful',0x0d,0x0a
1592
delokStr_end:
1593
 
1594
startStr:           db  '150 Here it comes...',0x0d,0x0a
1595
startStr_end:
1596
 
1597
storStr:            db  '150 Connecting for STOR',0x0d,0x0a
1598
storStr_end:
1599
 
1600
endStr:             db  '226 Transfer OK, Closing connection',0x0d,0x0a
1601
endStr_end:
1602
 
1603
abortStr:           db  '225 Abort successful',0x0d,0x0a
1604
abortStr_end:
1605
 
1606
 ; This is the buffer used for building up a directory listing line
1607
dirStr:             times 128 db 0
1608
 
1609
; This is template string used in building up a directory listing line
1610
tmplStr:            db 'rw-rw-rw-    1 0        0                ',0
1611
 
1612
months:
1613
        dd     'Jan ','Feb ','Mar ','Apr ','May ','Jun '
1614
        dd     'Jul ','Aug ','Sep ','Oct ','Nov ','Dec '
1615
 
1616
fileinfoblock:
1617
                    dd      0x00
1618
                    dd      0x00
1619
                    dd      0x00
1620
                    dd      0x200         ; bytes to read
1621
                    dd      text + 0x1300 ; data area
1622
filename:           times 256 db 0
1623
 
1624
; The following lines define data for reading a directory block
1625
DirBlocksPerCall = 16
1626
dirinfoblock:
1627
                    dd      1
1628
                    dd      0x00
1629
                    dd      0x00
1630
                    dd      DirBlocksPerCall
1631
                    dd      text + 0x1300   ; data area
1632
; The 'filename' for a directory listing
539 spraid 1633
dirpath             db      '/sys',0
481 diamond 1634
 
1635
fsize:              dd      0
661 ataualpa 1636
 
481 diamond 1637
state               db  0
1638
buffptr             dd  0
1639
buff:               times 256 db 0  ; Could put this after iend
1640
 
1641
; Ram use at the end of the application:
1642
; text                  : 2400 bytes for screen memory
1643
; text + 0x1300          : file data area
1644
text:
1645
I_END: