Subversion Repositories Kolibri OS

Rev

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