lvmsoglia

Servidor FTP - Luiz Vinicius Soglia

Sep 30th, 2012
1,483
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 80.82 KB | None | 0 0
  1. //Servidor FTP - desenvolvido em ambiente windows
  2. //Luiz Vinicius Soglia
  3.  
  4. /* Glossario:
  5. DTP = data transfer port*/
  6.  
  7. /* linkar as seguintes bibliotecas:
  8. libws2_32
  9. */
  10.  
  11. /*==============================================================================
  12.  
  13. Para criar uma lista de clientes que podem acessar o servidor FTP siga os seguintes passos:
  14.  
  15. 1) No mesmo diretório onde se encontra o executável do programa crie um arquivo de texto
  16. do tipo .txt, chamado Clientes.txt (com C maiúsculo no início)
  17.  
  18. 2) No arquivo Clientes.txt adicione os clientes, da seguinte forma:
  19.  
  20. Nome do cliente
  21. Senha do cliente
  22. permissão para escrita (digite 0 para não ou 1 para sim)*
  23.  
  24. *permissão para escrita consiste em permitir a um cliente:
  25.  
  26. - Fazer upload de arquivos para o servidor
  27. - Renomear e Deletar arquivos
  28. - Criar, Renomear e Deletar Diretórios
  29.  
  30.  
  31. Exemplo:
  32.  
  33. Cadastro dos clientes Maria (senha 1234abcd) e Gabriel (senha xyz4321),
  34. sendo que Maria tem permissão para escrita e Gabriel não tem permissão para escrita:
  35.  
  36. ====== Início do arquivo Clientes.txt ======
  37. Maria
  38. 1234abc
  39. 1
  40. Gabriel
  41. xyz4321
  42. 0
  43. ====== Fim do arquivo Clientes.txt =========
  44.  
  45.  
  46. ==============================================================================*/
  47.  
  48.  
  49. #ifdef _WIN32 //windows
  50. #ifndef WIN32_LEAN_AND_MEAN //evita conflitos entre a biblioteca winsock, incluida em windows, e winsock2
  51. #define WIN32_LEAN_AND_MEAN
  52. #endif
  53. #include <winsock2.h>
  54. #include <iostream>
  55. #include <dir.h> // classe para manipular diretórios
  56. #include <dirent.h> // classe para manipular diretórios
  57. #include <sys/stat.h>
  58. #include <sys/types.h>
  59. #include <time.h>
  60. #endif
  61.  
  62. #define MAX_MSG 2048 //tamanho máximo da msg
  63. #define MAX_CLIENTES 64 //maximo de clientes que podem se conectar ao servidor
  64. #define MAX_TRANSF 64 //Suporta MAX_TRANSF transferencias simultaneamente
  65.  
  66. using namespace std;
  67.  
  68. HANDLE Hmutex; // Um mutex é basicamente é um objeto que pode ser utilizado para sincronizar threads,
  69.               //evitando acessos a um ponto de memoria ao mesmo tempo, como variaveis globais
  70.  
  71. int thread [MAX_CLIENTES]; //identificadores das Threads
  72. HANDLE Hthread [MAX_CLIENTES]; //Handles das Threads
  73.  
  74. int thread_transf [MAX_TRANSF]; //identificadores das Threads
  75. HANDLE Hthread_transf [MAX_TRANSF]; //numero de Handles dimensionado para Suportar MAX_TRANSF transferencias ao mesmo tempo
  76.  
  77. int n_clientes_conectados=0; //numero de clientes conectados
  78.  
  79. //estrutura utilizada para guardar dados de cliente
  80. struct cliente_estrutura {
  81.     char ID[64]; //guarda ID de cliente com ate 64 caracteres
  82.     char Senha[64]; //guarda a senha do cliente
  83.     char IP[64]; //guarda o IP do cliente
  84.     int Socket; //guarda Socket de cliente
  85.     int pos; //guarda a posicao do cliente nas matrizes de handles e identificadores de Threads
  86. };
  87. typedef cliente_estrutura cliente_tipo;
  88.  
  89. struct struct_dados_transferencia //estrutura que guarda os dados que serão passados para as funções de transferencia de arquivos
  90. {
  91.     int data_Socket;
  92.     int controle_Socket;
  93.     int pos; //guarda a posicao da transferencia atual nas matrizes de handles e identificadores de Threads
  94.     char endereco_arq[260];
  95. };  
  96. typedef struct_dados_transferencia dados_transferencia;
  97.  
  98. char dir_fisico[260], IP_server[64], host_server[260], padrao_listagem;
  99. int porta_pasv, server_DTSocket, anonymous_enable = 0;
  100.  
  101.  
  102. //callback de funcoes
  103. int Aceita_Conexoes (int serverSocket, int max_clientes, char *ID_servidor);
  104. int Aceita_msgs (cliente_tipo *Cli);
  105. int Listen_Socket (int porta, int n_conexoes);
  106. int Connect_Socket (int porta, char *host);
  107. void Desconecta_Cliente (cliente_tipo *Cli, bool msg_on, int info_type);
  108. void Finaliza_Conexao (int serversocket);
  109. void formata_IP (char *IP_server, char *IP_formatado);
  110. void obtem_ip_porta (char *host_port, char *IP_Cliente, int *user_DTP);
  111. int arquivo_existe (const char *filename);
  112. int envia_listadir (char padrao_listagem, char *gpath, int user_DTSocket);
  113. int tamanho_dir (char *dir, unsigned long *tamanho);
  114. int envia_arquivo(dados_transferencia *dados);
  115. int recebe_arquivo(dados_transferencia *dados);
  116. int deleta_arquivo(dados_transferencia *dados);
  117. int deleta_diretorio(char *gdir);
  118. int carrega_cliente (char *ID, char *Senha, int *permissao_escrita);
  119.  
  120. //===============================================================================
  121.  
  122. //FUNCAO PRINCIPAL DO SERVIDOR
  123.  
  124. int main()
  125. {  
  126.     char ID_servidor[64], op;
  127.     int serverSocket, porta, max_clientes, n;
  128.     bool config_load = false; //se torna true se configuracoes anteriores sao carregadas
  129.    
  130.     for (n=0; n<MAX_CLIENTES; n++) //inicializa identificadores de Threads com um valor nulo
  131.     {thread[n]=-1;}
  132.     for (n=0; n<MAX_TRANSF; n++)
  133.     {thread_transf[n]=-1;}
  134.    
  135.     if (arquivo_existe ("CONFIG_SERVIDOR.txt") == 1) //existe uma configuracao salva
  136.     {  
  137.             FILE *config;
  138.            
  139.             if ((config = fopen ("CONFIG_SERVIDOR.txt", "r")) != NULL)
  140.             {
  141.                 int teste=0;
  142.                
  143.                 //faz a leitura de dados do arquivo CONFIG_SERVIDOR.txt
  144.                 host_server[0]='\0';
  145.                 fscanf (config, "%259[^\n]\n", host_server);
  146.                 ID_servidor[0]='\0';
  147.                 fscanf (config, "%63[^\n]\n", ID_servidor);
  148.                 dir_fisico[0]='\0';
  149.                 fscanf (config, "%259[^\n]\n", dir_fisico);
  150.                 fscanf (config, "%d %d %d", &porta, &porta_pasv, &max_clientes);
  151.                 fclose (config);
  152.                
  153.                 //faz testes para saber se os dados lidos estão corretos
  154.                 if (strlen(host_server) < 1) {teste=1;}
  155.                 if (strlen(ID_servidor) < 1) {teste=1;}
  156.                
  157.                 DIR *pdir;
  158.                 if (strlen(dir_fisico) < 1 || strlen(dir_fisico) > PATH_MAX)
  159.                 {teste=1;}
  160.                 else
  161.                 {    
  162.                      pdir = opendir (dir_fisico);
  163.                      if (pdir == NULL) //diretorio nao existe
  164.                      {teste=1;}
  165.                      else //caso exista
  166.                      {closedir (pdir);}
  167.                 }
  168.                
  169.                 if (porta < 1 || porta > 1023) {teste = 1;}
  170.                 if (porta_pasv < 1024) {teste = 1;}
  171.                 if (max_clientes < 1 || max_clientes > MAX_CLIENTES) {teste = 1;}
  172.                
  173.                 //se os testes apontarem que os dados estão corretos
  174.                 if (teste == 0)
  175.                 {
  176.                    cout << "Existe uma configuracao salva:\n" << endl;
  177.                    cout << "Host do servidor: " << host_server << endl;
  178.                    cout << "Porta para conexao de controle: " << porta << endl;
  179.                    cout << "Porta inicial para conexao de dados no modo passivo: " << porta_pasv << endl;
  180.                    cout << "ID de Boas Vindas do servidor: " << ID_servidor << endl;
  181.                    cout << "Diretorio fisico compartilhado:\n" << dir_fisico << endl;
  182.                    cout << "Maximo de clientes conectados ao servidor: " << max_clientes << endl;
  183.                    cout << "\nDeseja carrega-la? ([s] para SIM e [n] para NAO): ";
  184.                    op = getchar(); fflush(stdin);
  185.                    if (op == 's' || op == 'S')
  186.                    {config_load = true; cout << "Configuracao carregada!" << endl;}
  187.                 }
  188.             }
  189.     }  
  190.    
  191.     if (!config_load) //se nao foi carregada uma configuracao entra no modo manual
  192.     {
  193.         system ("CLS");
  194.         cout << "Deseja utilizar Dynamic DNS - URL Passiva - para acesso externo?" << endl;
  195.         cout << "[s] para SIM ou [n] para NAO): ";
  196.         op = getchar(); fflush (stdin);
  197.         if (op == 's' || op == 'S')
  198.         {
  199.             cout << "Host do Servidor (URL passivo):" << endl;
  200.             host_server[0]='\0';
  201.             scanf("%259[^\n]", host_server); fflush (stdin);
  202.             //tratamento contra erros de digitacao
  203.             if (strlen(host_server)<1) {strcpy(host_server, "localhost");}
  204.         }
  205.         else
  206.         {
  207.             cout << "O Servidor utiliza o IP local" << endl;
  208.             strcpy(host_server, "localhost");
  209.         }
  210.        
  211.         cout << "Digite a porta para conexao de controle do servidor (Padrao: 21): ";
  212.         scanf ("%d", &porta); fflush (stdin);
  213.         if (porta < 1 || porta > 1023) {porta=21;} //tratamento contra erros de digitacao - até a porta 1023 elas são
  214.                                                    //consideradas reservadas (alta prioridade) - usadas em FTP para conexão de controle
  215.         cout << "Digite a porta inicial para conexao de dados no modo passivo (Ex: 7700): ";
  216.         scanf ("%d", &porta_pasv); fflush (stdin);
  217.         if (porta_pasv < 1024) {porta_pasv=1024;} //tratamento contra erros de digitacao - a partir de 1024 as portas
  218.                                                   //são consideradas de baixa prioridade - usadas em FTP para conexão de dados no modo passivo
  219.         cout << "Crie uma ID de Boas Vindas para o Servidor: ";
  220.         ID_servidor[0]='\0';
  221.         scanf("%63[^\n]", ID_servidor); fflush (stdin);
  222.         //tratamento contra erros de digitacao
  223.         if (strlen(ID_servidor)<1) {strcpy(ID_servidor, "Servidor FTP"); cout << "ID de Boas Vindas do servidor: " << ID_servidor << endl;}
  224.        
  225.         bool teste;
  226.         do
  227.         {
  228.             teste=false;
  229.             DIR *pdir;
  230.             cout << "Diretorio fisico que sera compartilhado (Ex: C:/Arquivos/Textos):" << endl;
  231.             dir_fisico[0]='\0';
  232.             scanf("%259[^\n]", dir_fisico); fflush (stdin);
  233.             if (strlen(dir_fisico) > PATH_MAX)
  234.             {teste=true;}
  235.             else
  236.             {    
  237.                 pdir = opendir (dir_fisico);
  238.                 if (pdir == NULL)
  239.                 {teste=true;}
  240.             }
  241.             if (teste)
  242.             {cout << "Erro! diretorio nao existe!" << endl;}
  243.             else {closedir (pdir);}
  244.         }
  245.         while (teste);
  246.        
  247.         cout << "Numero de clientes que podem se conectar ao servidor (maximo de " << MAX_CLIENTES << "): ";
  248.         scanf ("%d", &max_clientes); fflush (stdin);
  249.         if (max_clientes<1 || max_clientes>MAX_CLIENTES) {max_clientes=MAX_CLIENTES;} //se digitado errado assume o valor maximo de MAX_CLIENTES
  250.         cout << " " << endl;
  251.    
  252.         //salva configuracoes
  253.         cout << "Deseja salvar esta configuracao? ([s] para SIM e [n] para NAO): ";
  254.         char op = getchar(); fflush (stdin);
  255.         if (op == 's' || op == 'S') //salvar
  256.         {
  257.             FILE *config;
  258.             if ((config = fopen ("CONFIG_SERVIDOR.txt", "w")) != NULL)
  259.             {
  260.                 fprintf (config, "%s\n%s\n%s\n%d %d %d", host_server, ID_servidor, dir_fisico, porta, porta_pasv, max_clientes);
  261.                 fclose (config);
  262.                 cout << "Configuracao salva!" << endl;
  263.             }
  264.             else
  265.             {cout << "Erro ao salvar configuracao!" << endl;}
  266.         }
  267.     }
  268.    
  269.     //pergunta sobre login como anonymous
  270.     cout << "\nPermitir login no servidor como anonymous?\n";
  271.     cout << "Cliente anonymous tem permissao somente para navegacao entre diretorios\ne uso da funcao download. Digite [0] para Nao ou [1] para Sim: ";
  272.     scanf ("%d", &anonymous_enable); fflush (stdin);
  273.     if (anonymous_enable != 1) {anonymous_enable=0;} //se digitado um valor diferente de 1, assume o valor "desativado" para o uso de login anonymous
  274.    
  275.     //pergunta sobre o padrão de envio de informações (listagem de diretórios no padrão UNIX ou MS-DOS)
  276.     cout << "\nQual o padrao de envio da listagem de diretorios?\nDigite [0] para UNIX ou [1] para MS-DOS: ";
  277.     padrao_listagem = getchar(); fflush (stdin);
  278.     if (padrao_listagem != '0') {padrao_listagem = '1';}
  279.    
  280.     //cria o Socket do servidor e o coloca em modo de escuta
  281.     serverSocket = Listen_Socket (porta, MAX_CLIENTES);
  282.  
  283.     if (serverSocket == -1)
  284.     {
  285.         cout << "\nErro: erro na criacao do socket para escuta do servidor!\n" << endl;
  286.         Finaliza_Conexao (serverSocket);
  287.         cout << "Pressione uma tecla para sair...\n" << endl;
  288.         fflush(stdin); getchar();
  289.         return 0;
  290.     }
  291.    
  292.       //cria um socket inicial para conexao de dados
  293.       int DTP_padrao=porta-1; //porta para transferencia de dados - se a porta de controle é a 21, logo porta de dados será 21-1=20
  294.       do{
  295.             server_DTSocket = Listen_Socket (DTP_padrao, 10);
  296.             DTP_padrao += 2; //se a porta 20 nao for possivel vai incremetando a porta de 2 em 2 ate obter um socket válido
  297.         }
  298.         while (server_DTSocket == -1);
  299.    
  300.     Hmutex = CreateMutex(NULL, false, NULL);// Create the mutex
  301.  
  302.     if (Hmutex == NULL)
  303.     {
  304.         cout << "\nErro: problemas ao criar o Mutex!\n" << endl;
  305.         Finaliza_Conexao (serverSocket);
  306.         cout << "Pressione uma tecla para sair...\n" << endl;
  307.         fflush(stdin); getchar();
  308.         return 0;
  309.     }
  310.    
  311.     //obtem o IP e host do servidor e coloca na tela
  312.     char hostname[260];
  313.     gethostname(hostname,260);
  314.     struct in_addr addr;
  315.     struct hostent *remoteHost = NULL;
  316.     if (stricmp (host_server, "localhost") != 0) //se o host não for o localhost, uma URL passiva esta sendo utilizada
  317.     {strcpy(hostname, host_server);}
  318.     remoteHost = gethostbyname(hostname);
  319.    
  320.     if (remoteHost != NULL && remoteHost->h_addrtype == AF_INET /*IPv4*/ )
  321.     {
  322.         cout << "\nServidor: Online!" << endl;
  323.         cout << "Host do Servidor: " << hostname << endl;
  324.        
  325.         n=0;
  326.            
  327.         while (remoteHost->h_addr_list[n] != 0)
  328.         {
  329.             addr.s_addr = *(u_long *) remoteHost->h_addr_list[n];
  330.             strcpy (IP_server, inet_ntoa(addr));
  331.             printf("\nIP do Servidor: %s\n", IP_server);
  332.                    
  333.             if (stricmp (host_server, "localhost") == 0) //se o host for o localhost, assume como host o IP local
  334.             {
  335.                 if (anonymous_enable == 1)
  336.                 {printf("Acesso anonymous: ftp://anonymous:anonymous@%s:porta\n", IP_server);}
  337.                 printf("Acesso login: ftp://username:senha@%s:porta\n", IP_server);
  338.             }
  339.             else //se não for localhost assume a URL passiva como host
  340.             {
  341.                 if (anonymous_enable == 1)
  342.                 {printf("Acesso anonymous: ftp://anonymous:anonymous@%s:porta\n", host_server);}
  343.                 printf("Acesso login: ftp://username:senha@%s:porta\n", host_server);
  344.             }
  345.             n++;
  346.         }
  347.        
  348.         cout << "\nO Servidor criado pode receber conexoes de ate " << max_clientes << " clientes simultaneamente\n" << endl;
  349.         Aceita_Conexoes(serverSocket, max_clientes, ID_servidor); //funcao em loop que recebe uma conexao e cria uma Thread
  350.     }                                                             //exclusiva para cada cliente, que receberá as msgs de comando
  351.    
  352.     cout << "\nOcorreu um erro ou uma solicitacao de encerramento do servidor\n\nPressione uma tecla para sair...\n" << endl;
  353.     fflush(stdin); getchar();
  354.     return 0;
  355. }  
  356.  
  357. //===============================================================================
  358.  
  359. // Aceita_Conexoes() - aceita conexões dos clientes e guarda seus dados, como socket e ID
  360.  
  361. int Aceita_Conexoes (int serverSocket, int max_clientes, char *ID_servidor)
  362. {    
  363.     struct sockaddr_in client;
  364.     int size_client = sizeof(struct sockaddr), nbytes, n;
  365.     char buffer[MAX_MSG];
  366.     cliente_tipo Cliente; //variavel que guarda ID e socket de cliente
  367.    
  368.     for (;;)// loop infinito
  369.     {  
  370.         Cliente.Socket = accept (serverSocket, (struct sockaddr*)&client, &size_client); //aceita conexao
  371.            
  372.         if (Cliente.Socket != SOCKET_ERROR)
  373.         {
  374.             if (n_clientes_conectados >= max_clientes) //servidor lotado
  375.             {
  376.                 strcpy (buffer, "421 Service not available, closing control connection - Servidor Lotado.\r\n");
  377.                 nbytes = send(Cliente.Socket,buffer,strlen(buffer),0);
  378.                 if (nbytes <= 0 || nbytes == SOCKET_ERROR)
  379.                 {cout << "Erro no envio de msg - 421 - Servidor Lotado" << endl;}
  380.                 closesocket(Cliente.Socket); continue;
  381.             }
  382.             else //conexao estabelecida
  383.             {  
  384.                 //envia informações sobre o servidor
  385.                 snprintf (buffer, MAX_MSG, "220 Service ready - Servidor ID: %s.\r\n", ID_servidor);
  386.                 nbytes = send(Cliente.Socket,buffer,strlen(buffer),0);
  387.                 if (nbytes <= 0 || nbytes == SOCKET_ERROR)
  388.                 {cout << "Erro no envio de msg 220 - Service ready" << endl; closesocket(Cliente.Socket); continue;}
  389.                  
  390.                 WaitForSingleObject(Hmutex, INFINITE); //obtem mutex - isso faz com que somente esse "processo" esteja ativo no programa
  391.                 //isso é necessario pq sera acessada variaveis globais, isso evita que outros processos acessem essas variaveis ao mesmo tempo
  392.                
  393.                 strcpy (Cliente.IP, inet_ntoa (client.sin_addr)); //guarda o ip do cliente        
  394.                
  395.                 for (n=0; n<MAX_CLIENTES; n++)
  396.                 {if (thread[n]==-1) {break;}} //busca uma posicao vazia para guardar a handle e identificador da Thread que será criada
  397.                        
  398.                 Cliente.pos=n; //guarda essa posicao, para passar para a Thread
  399.                 strcpy (Cliente.ID, "Cliente Desconhecido"); //usuario desconhecido enquanto nao faz login
  400.                
  401.                 //cria a Thread que receberá as msgs de comando vindas do cliente FTP        
  402.                 Hthread[n] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)Aceita_msgs, &Cliente, 0, (LPDWORD)&thread[n]);
  403.                        
  404.                 if (Hthread[n] == NULL) //erro ao criar a Thread
  405.                 {thread[n]=-1; closesocket (Cliente.Socket);}
  406.                 else {n_clientes_conectados++;}
  407.                
  408.                 ReleaseMutex(Hmutex);// libera o mutex - os outros "processos" voltam a rodar  
  409.                 Sleep (100); //aguarda a Thread se estabelecer para retornar ao inicio do loop
  410.             }
  411.         }
  412.     } //fim do loop infinito
  413.     Finaliza_Conexao (serverSocket);
  414.     return 0;
  415. }
  416.  
  417. //==============================================================================
  418.  
  419. int Aceita_msgs (cliente_tipo *Cli) //receberá as msgs de comando vindas do cliente FTP
  420. {  
  421.     int nbytes, result, p1, p2, user_DTSocket;
  422.     char buffer [MAX_MSG], senha_rec[64], arq_rename[260];
  423.     char type_char='A', sec_type_char='N', transfer_mode='S', structure_code='F'; //parâmetros - seta inicialmente com valores padrão
  424.     cliente_tipo Cliente;
  425.     FD_SET clientSet;
  426.     bool nao_implem=true, login=false;
  427.     int permissao_escrita=0, ID_Ok=1;
  428.     char dir_atual[260], dir_virtual[260], dir_fis[260];
  429.     strcpy (dir_fis, dir_fisico); //cópia local do diretorio fisico compartilhado
  430.     strcpy (dir_virtual, "/"); //inicializa o diretorio virtual como o padrão
  431.     strcpy (dir_atual, dir_fis); //inicializa o diretorio fisico atual com o inicial escolhido pelo usuario
  432.     struct stat stStat;
  433.    
  434.     WaitForSingleObject(Hmutex, INFINITE); //obtem mutex - ja que vamos acessar uma variavel global, queremos exclusividade!
  435.     Cliente = *Cli; //cópia local
  436.     ReleaseMutex(Hmutex);
  437.    
  438.     timeval waitTime; //estrutura que guarda o tempo de espera por atividade no socket, sera usada na funcao select
  439.     waitTime.tv_sec = 10; //segundos - fará a funcao select esperar 10 segundos por atividade nos Sockets
  440.     waitTime.tv_usec = 0; //microsegundos
  441.    
  442.     for (;;) // loop infinito
  443.     {  
  444.         FD_ZERO(&clientSet); //zera lista
  445.         FD_SET(Cliente.Socket, &clientSet); //guarda na lista o socket récem conectado
  446.        
  447.         //funcao select - espera que o socket que foi passado como parametro esteja pronto para ser lido
  448.         result = select (Cliente.Socket+1, &clientSet, NULL, NULL, &waitTime);
  449.        
  450.         if (result == 0) //se nenhum socket mostrou atividade, nao esta pronto para ser lido
  451.         {continue;} //volta o loop
  452.  
  453.         if (result == SOCKET_ERROR) //se houve erro na funcao select
  454.         {Desconecta_Cliente(&Cliente, false, 0); break;} //termina o loop
  455.        
  456.             nbytes = recv(Cliente.Socket, buffer, MAX_MSG, 0); //Recebe a msg de comando vinda do cliente FTP
  457.            
  458.             if (nbytes == 0 || nbytes == SOCKET_ERROR) //se houve desconexao inesperada do cliente ou erro no envio do comando
  459.             {Desconecta_Cliente(&Cliente, false, 0); return 1;}
  460.            
  461.             buffer[nbytes] = '\0'; //define o fim da msg recebida
  462.            
  463.             nao_implem=true; //define se uma funcao foi implementada ou nao
  464.            
  465.             cout << Cliente.ID << " diz: " <<  buffer << endl; //coloca na tela o conteudo da msg enviada pelo cliente
  466.            
  467.            
  468. //========================== LISTA DE COMANDOS FTP =============================
  469.            
  470.             if (strncasecmp(buffer,"USER",4) == 0) //Recebe ID do usuario - USER <SP> <usuario> <CRLF>
  471.             {
  472.                 nao_implem=false;
  473.                 int desconecta=0;
  474.                 //extrai o nome do usuario
  475.                 int n=5; int k=0;
  476.                 while (buffer[n] != '\r' && n<nbytes)
  477.                 {Cliente.ID[k] = buffer[n]; n++; k++;}
  478.                 Cliente.ID[k] = '\0';
  479.                 if (stricmp (Cliente.ID, "anonymous") == 0 && anonymous_enable == 1) //login como anônimo
  480.                 {
  481.                    snprintf (buffer, MAX_MSG, "230 anonymous logged in, proceed.\r\n");
  482.                    strcpy (Cliente.Senha, "anonymous"); login=true; permissao_escrita=0;
  483.                 }
  484.                 else
  485.                 {
  486.                     login=false;
  487.                     ID_Ok = carrega_cliente (Cliente.ID, Cliente.Senha, &permissao_escrita);
  488.                     if (ID_Ok == 0) //retorna 0 se a ID existe na lista
  489.                     {snprintf (buffer, MAX_MSG, "331 User: %s - name okay, need password.\r\n", Cliente.ID);}
  490.                     else
  491.                     {snprintf (buffer, MAX_MSG, "530 Not logged in.\r\n"); desconecta=1;}
  492.                 }
  493.                
  494.                 nbytes = send(Cliente.Socket,buffer,strlen(buffer),0);
  495.                 if (nbytes <= 0 || nbytes == SOCKET_ERROR)
  496.                 {Desconecta_Cliente(&Cliente, true, 2); return 1;}
  497.                
  498.                 if (desconecta == 1) //User name incorreto
  499.                 {Desconecta_Cliente(&Cliente, false, 0); return 1;}
  500.                
  501.                 if (login == true)
  502.                 {
  503.                    //coloca na tela um aviso de que um cliente anônimo se conectou
  504.                    WaitForSingleObject(Hmutex, INFINITE);
  505.                    cout << Cliente.ID << " [Socket " << Cliente.Socket << " - IP: " << Cliente.IP << "] conectado." << endl;
  506.                    cout << "Agora sao " << n_clientes_conectados << " clientes conectados.\n" << endl;
  507.                    ReleaseMutex(Hmutex);
  508.                 }
  509.                 continue;
  510.             }
  511.                
  512.             if (strncasecmp(buffer,"PASS",4) == 0) //Recebe a senha de acesso - PASS <SP> <senha> <CRLF>
  513.             {    
  514.                 nao_implem=false;
  515.                 //extrai a senha de acesso recebida e guarda em senha_rec
  516.                 int n=5; int k=0;
  517.                 while (buffer[n] != '\r' && n<nbytes)
  518.                 {senha_rec[k] = buffer[n]; n++; k++;}
  519.                 senha_rec[k] = '\0';
  520.                 if (strcmp (senha_rec, Cliente.Senha) == 0 && ID_Ok == 0) //se a senha recebida confere com a da lista de clientes e a ID esta Ok
  521.                 {
  522.                     strcpy (buffer, "230 User logged in, proceed.\r\n");
  523.                     nbytes = send(Cliente.Socket,buffer,strlen(buffer),0);
  524.                     if (nbytes <= 0 || nbytes == SOCKET_ERROR)
  525.                     {Desconecta_Cliente(&Cliente, true, 2); return 1;}
  526.                     login=true; //logado!
  527.                     WaitForSingleObject(Hmutex, INFINITE);
  528.                     cout << Cliente.ID << " [Socket " << Cliente.Socket << " - IP: " << Cliente.IP << "] conectado." << endl;
  529.                     cout << "Agora sao " << n_clientes_conectados << " clientes conectados.\n" << endl;
  530.                     ReleaseMutex(Hmutex);
  531.                 }
  532.                 else //senha incorreta
  533.                 {
  534.                     strcpy (buffer, "530 Not logged in.\r\n");
  535.                     send(Cliente.Socket,buffer,strlen(buffer),0);
  536.                     Desconecta_Cliente(&Cliente, false, 0);
  537.                     return 1;
  538.                 }
  539.                 continue;
  540.             }
  541.            
  542.             if (login == false) //se não estiver logado não passa daqui!
  543.             {
  544.                 snprintf (buffer, MAX_MSG, "530 Not logged in.\r\n");
  545.                 nbytes = send(Cliente.Socket,buffer,strlen(buffer),0);
  546.                 if (nbytes <= 0 || nbytes == SOCKET_ERROR)
  547.                 {Desconecta_Cliente(&Cliente, true, 2); return 1;}
  548.                 continue;
  549.             }
  550.            
  551.             if (strncasecmp(buffer,"SIZE",4) == 0) //SIZE <SP> <pathname> <CRLF> - tamanho total dos arquivos no diretorio especificado
  552.             {
  553.                 nao_implem=false;
  554.                 //extrai pathname
  555.                 char pathname[260], dir[260];
  556.                 int n=5; int k=0;
  557.                 if (buffer[5] != '/' && buffer[5] != '\\') //se pathname não está em formato de diretorio
  558.                 {pathname[0]= '/'; k=1;}
  559.                 while (buffer[n] != '\r' && n<nbytes)
  560.                 {pathname[k] = buffer[n]; n++; k++;}
  561.                 pathname[k] = '\0';
  562.  
  563.                 if (pathname[1] == '.') //evita o uso de /../ para chamar diretórios anteriores ao definido como inicial
  564.                 {strcpy (pathname,"/");}
  565.                
  566.                 if (strlen (pathname) > 1 && pathname[k-1] == '/') //se não é o diretorio inicial e existe uma barra '/' indevida no fim do pathname
  567.                 {pathname[k-1] = '\0';}
  568.                
  569.                 strcpy (dir, dir_fis); //copia o diretorio fisico
  570.                 if (strlen (pathname) > 1) //se pathname nao for o diretorio inicial
  571.                 {strcat (dir, pathname);} //adiciona pathname
  572.                
  573.                 //Verifica se o diretorio existe
  574.                 if (stat (dir_atual, &stStat) == 0) //existe
  575.                 {
  576.                     unsigned long size=0;
  577.                     int r = tamanho_dir(dir, &size); //chama a funcao que calcula o tamanho de arquivos em um diretorio
  578.                     if (r < 0)
  579.                     {snprintf (buffer, MAX_MSG, "501 Syntax error in parameters or arguments.\r\n");}
  580.                     else
  581.                     {snprintf (buffer, MAX_MSG, "213 %lu\r\n", size);}
  582.                 }
  583.                 else //nao existe
  584.                 {snprintf (buffer, MAX_MSG, "501 Syntax error in parameters or arguments.\r\n");}
  585.                
  586.                 nbytes = send(Cliente.Socket,buffer,strlen(buffer),0);
  587.                 if (nbytes <= 0 || nbytes == SOCKET_ERROR)
  588.                 {Desconecta_Cliente(&Cliente, true, 2); return 1;}
  589.                 continue;
  590.             }
  591.            
  592.             if (strncasecmp(buffer,"CWD",3) == 0)
  593.             {
  594.                 //Makes the given directory be the current directory on the remote host
  595.                 //CWD  <SP> <pathname> <CRLF>
  596.                 nao_implem=false;
  597.                 char pathname [260], dir_virt_teste[260], dir_atual_teste[260];
  598.                
  599.                 //cópias locais
  600.                 strcpy (dir_virt_teste, dir_virtual);
  601.                 strcpy (dir_atual_teste, dir_atual);
  602.                
  603.                 //extrai pathname
  604.                 int n=4; int k=0;
  605.                 if (buffer[4] != '/' && buffer[4] != '\\') //se pathname não está em formato de diretorio
  606.                 {pathname[0]= '/'; k=1;}
  607.                 while (buffer[n] != '\r' && n<nbytes)
  608.                 {pathname[k] = buffer[n]; n++; k++;}
  609.                 pathname[k] = '\0';
  610.  
  611.                 if (pathname[1] == '.') //evita o uso de /../ para chamar diretórios anteriores ao definido como inicial
  612.                 {strcpy (pathname,"/");}
  613.                
  614.                 if (strlen (pathname) > 1 && pathname[k-1] == '/') //se não é o diretorio inicial e existe uma barra '/' indevida no fim do pathname
  615.                 {pathname[k-1] = '\0';}
  616.                
  617.                 if (buffer[4] != '/' && buffer[4] != '\\') //se pathname não está em formato de diretorio
  618.                 {
  619.                     if (strlen (dir_virt_teste) > 1) //se nao for o diretorio virtual inicial
  620.                     {strcat (dir_virt_teste, pathname);} //adiciona pathname ao diretorio virtual atual
  621.                     else //se for o inicial
  622.                     {strcpy (dir_virt_teste, pathname);}
  623.                    
  624.                     strcat(dir_atual_teste, pathname); //adiciona pathname ao diretorio fisico atual
  625.                 }
  626.                 else //se pathname está em formato de diretorio
  627.                 {
  628.                     strcpy (dir_virt_teste, pathname); //copia pathname para o diretorio virtual atual
  629.                     strcpy (dir_atual_teste, dir_fis); //copia o diretorio fisico inicial para o diretorio fisico atual
  630.                     if (strlen (pathname) > 1) //se nao for o diretorio virtual inicial
  631.                     {strcat(dir_atual_teste, dir_virt_teste);} //adiciona pathname ao diretorio fisico atual
  632.                 }
  633.                
  634.                 if (stat (dir_atual_teste, &stStat) == 0) //Verifica se o diretorio existe
  635.                 {
  636.                     if(S_ISDIR(stStat.st_mode)) //É um diretório
  637.                     {
  638.                         snprintf (buffer, MAX_MSG, "250 CWD Command okay.\r\n");
  639.                         //passa para as variaveis globais
  640.                         strcpy (dir_virtual, dir_virt_teste);
  641.                         strcpy (dir_atual, dir_atual_teste);
  642.                     }
  643.                     else //Não é um diretório
  644.                     {snprintf (buffer, MAX_MSG, "550 That is not a directory.\r\n");}
  645.                 }
  646.                 else
  647.                 {snprintf (buffer, MAX_MSG, "550 That is not a directory.\r\n");} //nao existe
  648.                
  649.                 nbytes = send(Cliente.Socket,buffer,strlen(buffer),0);
  650.                 if (nbytes <= 0 || nbytes == SOCKET_ERROR)
  651.                 {Desconecta_Cliente(&Cliente, true, 2); return 1;}
  652.                 continue;
  653.             }
  654.            
  655.             if (strncasecmp(buffer,"CDUP",4) == 0)
  656.             {
  657.                 //Up directory - CDUP <CRLF>
  658.                 nao_implem=false;
  659.                 int n;
  660.                 if (strlen(dir_virtual) > 1) //se nao for o diretorio inicial
  661.                 {
  662.                     n=strlen(dir_virtual)-1;
  663.                     for (n; n>=0; n--)
  664.                     {if (dir_virtual[n] == '/') {break;}}                  
  665.                     dir_virtual[n]='\0';
  666.                     strcpy (dir_atual, dir_fis);
  667.                     if (strlen (dir_virtual) <= 1) //voltou para o diretorio inicial
  668.                     {strcpy (dir_virtual, "/");}
  669.                     else
  670.                     {strcat(dir_atual, dir_virtual);}
  671.                 }
  672.                 //Verifica se o diretorio existe
  673.                 if (stat (dir_atual, &stStat) == 0)
  674.                 {snprintf (buffer, MAX_MSG, "200 CDUP Command okay.\r\n");} //existe
  675.                 else
  676.                 {snprintf (buffer, MAX_MSG, "550 Requested action not taken.\r\n");} //nao existe
  677.                 nbytes = send(Cliente.Socket,buffer,strlen(buffer),0);
  678.                 if (nbytes <= 0 || nbytes == SOCKET_ERROR)
  679.                 {Desconecta_Cliente(&Cliente, true, 2); return 1;}
  680.                 continue;  
  681.             }
  682.            
  683.             if (strncasecmp(buffer,"PWD",3) == 0) //Print the current working directory name - PWD <CRLF>
  684.             {  
  685.                 nao_implem=false;
  686.                 snprintf (buffer, MAX_MSG, "257 \"%s\" is current directory.\r\n", dir_virtual);
  687.                 nbytes = send(Cliente.Socket,buffer,strlen(buffer),0);
  688.                 if (nbytes <= 0 || nbytes == SOCKET_ERROR)
  689.                 {Desconecta_Cliente(&Cliente, true, 2); return 1;}
  690.                 continue;
  691.             }
  692.            
  693.             if (strncasecmp(buffer,"TYPE",4) == 0)
  694.             {  
  695.                 /*
  696.                   TYPE <SP> <type-code> ::= | A [<sp> <form-code>] <CRLF>
  697.                                             | E [<sp> <form-code>] <CRLF>
  698.                                             | I <CRLF>
  699.                                             | L <sp> <byte-size> <CRLF>
  700.                
  701.                 The following codes are assigned for type:
  702.  
  703.                 A - ASCII |    | N - Non-print
  704.                           |-><-| T - Telnet format effectors
  705.                 E - EBCDIC|    | C - Carriage Control (ASA)
  706.                 I - Image
  707.                 L <byte size> - Local byte Byte size
  708.                 */
  709.                
  710.                 nao_implem=false;
  711.                 type_char = buffer[5]; //A, E, I ou L
  712.                 sec_type_char = '-';   //N, T, C ou <byte size>
  713.                 if (type_char == 'A')
  714.                 {sec_type_char = buffer[8];}
  715.                
  716.                 if (type_char == 'E' || type_char == 'L')
  717.                 {snprintf (buffer, MAX_MSG, "504 Command not implemented for that parameter.\r\n");}
  718.                 else
  719.                 {snprintf (buffer, MAX_MSG, "200 Type set to %c.\r\n", type_char);}
  720.                 nbytes = send(Cliente.Socket,buffer,strlen(buffer),0);
  721.                 if (nbytes <= 0 || nbytes == SOCKET_ERROR)
  722.                 {Desconecta_Cliente(&Cliente, true, 2); return 1;}
  723.                 continue;
  724.             }
  725.            
  726.             if (strncasecmp(buffer,"MODE",4) == 0) //MODE <SP> <mode-code> <CRLF>
  727.             {
  728.                 /* Modos de transferência
  729.                 S - Stream - padrão
  730.                 B - Block
  731.                 C - Compressed
  732.                 */
  733.                 transfer_mode = buffer[5]; //S, B, ou C
  734.                 snprintf (buffer, MAX_MSG, "200 transfer mode set to %c.\r\n", transfer_mode);
  735.                 nbytes = send(Cliente.Socket,buffer,strlen(buffer),0);
  736.                 if (nbytes <= 0 || nbytes == SOCKET_ERROR)
  737.                 {Desconecta_Cliente(&Cliente, true, 2); return 1;}
  738.                 continue;
  739.             }
  740.            
  741.             if (strncasecmp(buffer,"STRU",4) == 0) //STRU <SP> <structure-code> <CRLF>
  742.             {
  743.                 /* Estruturas
  744.                 F - File (no record structure) - padrão
  745.                 R - Record structure
  746.                 P - Page structure
  747.                 */
  748.                 structure_code = buffer[5]; //F, R, ou P
  749.                 snprintf (buffer, MAX_MSG, "200 structure code set to %c.\r\n", structure_code);
  750.                 nbytes = send(Cliente.Socket,buffer,strlen(buffer),0);
  751.                 if (nbytes <= 0 || nbytes == SOCKET_ERROR)
  752.                 {Desconecta_Cliente(&Cliente, true, 2); return 1;}
  753.                 continue;
  754.             }
  755.            
  756.             if (strncasecmp(buffer,"PORT",4) == 0) //PORT <SP> <host-port> <CRLF>
  757.             {  
  758.                 nao_implem=false;
  759.                 char host_port[64], IP_Cliente[48];
  760.                 int user_DTP;
  761.                
  762.                 //extrai parametro <host-port>
  763.                 int n=5; int k=0;
  764.                 while (buffer[n] != '\r' && n<nbytes)
  765.                 {host_port[k] = buffer[n]; n++; k++;}
  766.                 host_port[k] = '\0';
  767.                
  768.                 obtem_ip_porta (host_port, IP_Cliente, &user_DTP); //obtem IP e porta a partir de <host-port>
  769.                
  770.                 snprintf (buffer, MAX_MSG, "200 PORT Command okay.\r\n");
  771.                 nbytes = send(Cliente.Socket,buffer,strlen(buffer),0);
  772.                 if (nbytes <= 0 || nbytes == SOCKET_ERROR)
  773.                 {Desconecta_Cliente(&Cliente, true, 2); return 1;}
  774.                
  775.                 user_DTSocket = Connect_Socket (user_DTP, IP_Cliente); //se conecta ao IP e porta enviados pelo cliente, criando o Socket
  776.                 continue;
  777.             }
  778.            
  779.             if (strncasecmp(buffer,"PASV",4) == 0) //ENTRA NO MODO PASSIVO - PASV <CRLF>
  780.             {  
  781.                 nao_implem=false;
  782.                 char IP_formatado[64];
  783.                 formata_IP (IP_server, IP_formatado); //coloca o IP formato h1,h2,h3,h4
  784.                 int port_pasv = porta_pasv; //port_pasv é uma cópia local da variavel global porta_pasv
  785.                 do {
  786.                     p1=port_pasv/256; p2=port_pasv%256;
  787.                     server_DTSocket = Listen_Socket (port_pasv,10); //cria o socket para DT e o coloca em modo de escuta
  788.                     port_pasv += 1; //vai incrementando a porta de 1 em 1 até encontrar uma porta disponível
  789.                 }
  790.                 while (server_DTSocket == -1);
  791.                
  792.                 snprintf (buffer, MAX_MSG, "227 Entering Passive Mode (%s,%d,%d).\r\n", IP_formatado,p1,p2); //envia h1,h2,h3,h4,p1,p2
  793.                 nbytes = send(Cliente.Socket,buffer,strlen(buffer),0);
  794.                 if (nbytes <= 0 || nbytes == SOCKET_ERROR)
  795.                 {Desconecta_Cliente(&Cliente, true, 2); return 1;}
  796.                
  797.                 user_DTSocket = accept (server_DTSocket,0,0); //aceita conexao de dados
  798.                 continue;
  799.             }
  800.            
  801.             if (strncasecmp(buffer,"LIST",4) == 0) //lista arquivos e diretorios -  LIST [<SP> <pathname>] <CRLF>
  802.             {  
  803.                 nao_implem=false;
  804.                 //obs: se nao for enviado o argumento pathname entao usar diretorio virtual corrente ou diretorio default
  805.                 if (buffer[4] == '[') //ha o argumento pathname
  806.                 {   //extrai pathname
  807.                     char pathname[260];
  808.                     int n=6; int k=0;
  809.                     if (buffer[n] != '/' && buffer[n] != '\\') //se nao vier formatado como diretorio
  810.                     {pathname[0]= '/'; k=1;}
  811.                     while (buffer[n] != ']' && n<nbytes)
  812.                     {pathname[k] = buffer[n]; n++; k++;}
  813.                     pathname[k] = '\0';
  814.                     strcpy (dir_atual, dir_fis); //copia diretorio inicial
  815.                     if (strlen(pathname) > 1)
  816.                     {strcat (dir_atual, pathname);} //adiciona pathname
  817.                 }
  818.                
  819.                 if (user_DTSocket > 0 && user_DTSocket != INVALID_SOCKET ) //se nao houve erro na criacao da conexão de dados
  820.                 {snprintf (buffer, MAX_MSG, "150 Data connection ready.\r\n");}
  821.                 else
  822.                 {snprintf (buffer, MAX_MSG, "425 Can't open data connection.\r\n"); closesocket (user_DTSocket); continue;}
  823.                 nbytes = send(Cliente.Socket,buffer,strlen(buffer),0);
  824.                 if (nbytes <= 0 || nbytes == SOCKET_ERROR)
  825.                 {closesocket (user_DTSocket); Desconecta_Cliente(&Cliente, true, 2); return 1;}
  826.                      
  827.                 if (envia_listadir (padrao_listagem, dir_atual, user_DTSocket) == 0) //chama a funcao que envia a lista de pastas e arquivos do diretorio requistado
  828.                 {snprintf (buffer, MAX_MSG, "226 Transfer complete - Closing data connection.\r\n");} //se o envio foi bem sucedido
  829.                 else
  830.                 {snprintf (buffer, MAX_MSG, "426 Connection closed; transfer aborted.\r\n");}
  831.                
  832.                 nbytes = send(Cliente.Socket,buffer,strlen(buffer),0); //envia msg
  833.                 if (nbytes <= 0 || nbytes == SOCKET_ERROR) //erro ao enviar mensagem
  834.                 {closesocket (user_DTSocket); Desconecta_Cliente(&Cliente, true, 2); return 1;}
  835.                
  836.                 closesocket (user_DTSocket); //fecha conexao de transferencia de dados
  837.                 continue;
  838.             }
  839.            
  840.             if (strncasecmp(buffer,"RETR",4) == 0) //envia arquivo para o cliente - RETR <SP> <pathname> <CRLF>
  841.             {
  842.                 char pathname[260];
  843.                 bool cancela=false;
  844.                 //extrai parametro <pathname>
  845.                 int n=5; int k=0;
  846.                 if (buffer[n] != '/' && buffer[n] != '\\') //se nao vier formatado como diretorio
  847.                 {pathname[0]= '/'; k=1;}
  848.                 while (buffer[n] != '\r' && n<nbytes)
  849.                 {pathname[k] = buffer[n]; n++; k++;}
  850.                 pathname[k] = '\0';
  851.                
  852.                 if (user_DTSocket > 0 && user_DTSocket != INVALID_SOCKET ) //se nao houve erro na criacao da conexão de dados
  853.                 {snprintf (buffer, MAX_MSG, "150 Data connection ready.\r\n");}
  854.                 else
  855.                 {snprintf (buffer, MAX_MSG, "425 Can't open data connection.\r\n"); closesocket (user_DTSocket); continue;}
  856.                 nbytes = send(Cliente.Socket,buffer,strlen(buffer),0);
  857.                 if (nbytes <= 0 || nbytes == SOCKET_ERROR)
  858.                 {closesocket (user_DTSocket); Desconecta_Cliente(&Cliente, true, 2); return 1;}
  859.                
  860.                 dados_transferencia dados; //guarda os dados para a transferencia do arquivo e passa para a Thread
  861.                
  862.                 WaitForSingleObject(Hmutex, INFINITE);
  863.                        
  864.                 for (n=0; n<MAX_TRANSF; n++)
  865.                 {if (thread_transf[n]==-1) {break;}} //busca uma posicao vazia para guardar a handle e identificador da Thread que será criada
  866.                        
  867.                 dados.pos=n; //guarda a posicao na matriz de handles, para passar para a Thread
  868.                 dados.data_Socket = user_DTSocket; //Socket conexao transf. dados
  869.                 dados.controle_Socket = Cliente.Socket;//Socket conexao de controle
  870.                 //endereco do arquivo a enviar
  871.                 strcpy (dados.endereco_arq, dir_atual);
  872.                 strcat (dados.endereco_arq, pathname);
  873.                
  874.                 if (arquivo_existe (dados.endereco_arq) != 1) //o arquivo não existe, tenta outro modo de construir o endereço do arquivo
  875.                 {
  876.                     strcpy (dados.endereco_arq, dir_fis);
  877.                     strcat (dados.endereco_arq, pathname);
  878.                    
  879.                     if (arquivo_existe (dados.endereco_arq) != 1) //o arquivo não existe
  880.                     {cancela=true;}
  881.                 }
  882.                
  883.                 if (cancela==true) //cancela envio de arquivo
  884.                 {  
  885.                     snprintf (buffer, MAX_MSG, "426 Connection closed; transfer aborted.\r\n");
  886.                     nbytes = send(Cliente.Socket,buffer,strlen(buffer),0);
  887.                     closesocket (user_DTSocket);
  888.                     if (nbytes <= 0 || nbytes == SOCKET_ERROR)
  889.                     {Desconecta_Cliente(&Cliente, true, 2); return 1;}
  890.                     continue;
  891.                 }
  892.                
  893.                 //Cria a Thread com a funcao de envio de arquivo    
  894.                 Hthread_transf[n] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)envia_arquivo, &dados, 0, (LPDWORD)&thread_transf[n]);
  895.                
  896.                 if (Hthread_transf[n] == NULL) //erro ao cria a Thread
  897.                 {
  898.                     thread_transf[n]=-1;
  899.                     snprintf (buffer, MAX_MSG, "426 Connection closed; transfer aborted.\r\n");
  900.                     nbytes = send(Cliente.Socket,buffer,strlen(buffer),0);
  901.                     closesocket (user_DTSocket);
  902.                 }
  903.                 ReleaseMutex(Hmutex);// libera o mutex - os outros "processos" voltam a rodar
  904.                
  905.                 if (nbytes <= 0 || nbytes == SOCKET_ERROR)
  906.                 {Desconecta_Cliente(&Cliente, true, 2); return 1;}
  907.                 continue;  
  908.             }
  909.            
  910.             if (strncasecmp(buffer,"SYST",4) == 0) //retorna um identificador do sistema e uma word type
  911.             {
  912.                 //Returns a word identifying the system, the word "Type:", and the default transfer type (as would be set by the TYPE command).  
  913.                 nao_implem=false;
  914.                 snprintf (buffer, MAX_MSG, "215 UNIX Type: L8\r\n"); //um padrao usado por muitos servidores
  915.                 nbytes = send (Cliente.Socket, buffer, strlen(buffer), 0);
  916.                 if (nbytes <= 0 || nbytes == SOCKET_ERROR)
  917.                 {Desconecta_Cliente(&Cliente, true, 2); return 1;}
  918.                 continue;
  919.             }
  920.            
  921.             if (strncasecmp(buffer,"FEAT",4) == 0) //FEAT <CRLF>
  922.             {
  923.                 nao_implem=false;
  924.                 snprintf (buffer, MAX_MSG, "211-Extensions supported:\r\n");
  925.                 nbytes = send (Cliente.Socket, buffer, strlen(buffer), 0);
  926.                 if (nbytes <= 0 || nbytes == SOCKET_ERROR)
  927.                 {Desconecta_Cliente(&Cliente, true, 2); return 1;}
  928.                
  929.                 snprintf (buffer, MAX_MSG, "SIZE\r\n");
  930.                 nbytes = send (Cliente.Socket, buffer, strlen(buffer), 0);
  931.                 if (nbytes <= 0 || nbytes == SOCKET_ERROR)
  932.                 {Desconecta_Cliente(&Cliente, true, 2); return 1;}
  933.                
  934.                 snprintf (buffer, MAX_MSG, "PASV\r\n");
  935.                 nbytes = send (Cliente.Socket, buffer, strlen(buffer), 0);
  936.                 if (nbytes <= 0 || nbytes == SOCKET_ERROR)
  937.                 {Desconecta_Cliente(&Cliente, true, 2); return 1;}
  938.                
  939.                 snprintf (buffer, MAX_MSG, "211 End.\r\n");
  940.                 nbytes = send (Cliente.Socket, buffer, strlen(buffer), 0);
  941.                 if (nbytes <= 0 || nbytes == SOCKET_ERROR)
  942.                 {Desconecta_Cliente(&Cliente, true, 2); return 1;}
  943.                 continue;
  944.             }
  945.            
  946.             if (strncasecmp(buffer,"SITE",4) == 0) //SITE <SP> <string> <CRLF>
  947.             {
  948.                 nao_implem=false;
  949.                 snprintf (buffer, MAX_MSG, "202 Command not implemented, superfluous at this site.\r\n");
  950.                 nbytes = send (Cliente.Socket, buffer, strlen(buffer), 0);
  951.                 if (nbytes <= 0 || nbytes == SOCKET_ERROR)
  952.                 {Desconecta_Cliente(&Cliente, true, 2); return 1;}
  953.                 continue;
  954.             }
  955.            
  956.             if (strncasecmp(buffer,"HELP",4) == 0) //HELP [<SP> <string>] <CRLF>
  957.             {
  958.                 nao_implem=false;
  959.                 snprintf (buffer, MAX_MSG, "211 System help reply.\r\n");
  960.                 nbytes = send (Cliente.Socket, buffer, strlen(buffer), 0);
  961.                 if (nbytes <= 0 || nbytes == SOCKET_ERROR)
  962.                 {Desconecta_Cliente(&Cliente, true, 2); return 1;}
  963.                 continue;
  964.             }
  965.            
  966.             if (strncasecmp(buffer,"NOOP",4) == 0) //Somente retorna um OK - NOOP <CRLF>
  967.             {
  968.                 nao_implem=false;
  969.                 nbytes = send(Cliente.Socket,"250 okay.\r\n",11,0);
  970.                 if (nbytes <= 0 || nbytes == SOCKET_ERROR)
  971.                 {Desconecta_Cliente(&Cliente, true, 2); return 1;}
  972.                 continue;  
  973.             }
  974.            
  975.             if (strncasecmp(buffer,"QUIT",4) == 0) //Termina conexao com o cliente - QUIT <CRLF>
  976.             {
  977.                 nao_implem=false;
  978.                 Desconecta_Cliente(&Cliente, true, 1);
  979.                 return 1;
  980.             }
  981.            
  982.             if (permissao_escrita == 0) //se não tiver permissão para escrita não passa daqui!
  983.             {
  984.                 snprintf (buffer, MAX_MSG, "530 Not logged in.\r\n");
  985.                 nbytes = send(Cliente.Socket,buffer,strlen(buffer),0);
  986.                 if (nbytes <= 0 || nbytes == SOCKET_ERROR)
  987.                 {Desconecta_Cliente(&Cliente, true, 2); return 1;}
  988.                 continue;
  989.             }
  990.            
  991.             if (strncasecmp(buffer,"STOR",4) == 0) //recebe arquivo do cliente - STOR <SP> <pathname> <CRLF>
  992.             {
  993.                 char pathname[260];
  994.                 //extrai parametro <pathname>
  995.                 int n=5; int k=0;
  996.                 if (buffer[n] != '/' && buffer[n] != '\\') //se nao vier formatado como diretorio
  997.                 {pathname[0]= '/'; k=1;}
  998.                 while (buffer[n] != '\r' && n<nbytes)
  999.                 {pathname[k] = buffer[n]; n++; k++;}
  1000.                 pathname[k] = '\0';
  1001.                
  1002.                 if (user_DTSocket > 0 && user_DTSocket != INVALID_SOCKET ) //se nao houve erro na criacao da conexão de dados
  1003.                 {snprintf (buffer, MAX_MSG, "150 Data connection ready.\r\n");}
  1004.                 else
  1005.                 {snprintf (buffer, MAX_MSG, "425 Can't open data connection.\r\n"); closesocket (user_DTSocket); continue;}
  1006.                 nbytes = send(Cliente.Socket,buffer,strlen(buffer),0);
  1007.                 if (nbytes <= 0 || nbytes == SOCKET_ERROR)
  1008.                 {closesocket (user_DTSocket); Desconecta_Cliente(&Cliente, true, 2); return 1;}
  1009.                
  1010.                 dados_transferencia dados; //guarda os dados para a transferencia do arquivo e passa para a Thread
  1011.                
  1012.                 WaitForSingleObject(Hmutex, INFINITE);
  1013.                        
  1014.                 for (n=0; n<MAX_TRANSF; n++)
  1015.                 {if (thread_transf[n]==-1) {break;}} //busca uma posicao vazia para guardar a handle e identificador da Thread que será criada
  1016.                        
  1017.                 dados.pos=n; //guarda a posicao na matriz de handles, para passar para a Thread
  1018.                 dados.data_Socket = user_DTSocket; //Socket conexao transf. dados
  1019.                 dados.controle_Socket = Cliente.Socket;//Socket conexao de controle
  1020.                 //endereco do novo arquivo que será recebido
  1021.                 strcpy (dados.endereco_arq, dir_atual);
  1022.                 strcat (dados.endereco_arq, pathname);
  1023.                
  1024.                 //Cria a Thread com a funcao de recebimento de arquivo    
  1025.                 Hthread_transf[n] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)recebe_arquivo, &dados, 0, (LPDWORD)&thread_transf[n]);
  1026.                
  1027.                 if (Hthread_transf[n] == NULL) //erro ao cria a Thread
  1028.                 {
  1029.                     thread_transf[n]=-1;
  1030.                     snprintf (buffer, MAX_MSG, "426 Connection closed; transfer aborted.\r\n");
  1031.                     nbytes = send(Cliente.Socket,buffer,strlen(buffer),0);
  1032.                     closesocket (user_DTSocket);
  1033.                 }
  1034.                 ReleaseMutex(Hmutex);// libera o mutex - os outros "processos" voltam a rodar
  1035.                
  1036.                 if (nbytes <= 0 || nbytes == SOCKET_ERROR)
  1037.                 {Desconecta_Cliente(&Cliente, true, 2); return 1;}
  1038.                 continue;  
  1039.             }
  1040.            
  1041.             if (strncasecmp(buffer,"DELE",4) == 0) //deleta arquivo - DELE <SP> <pathname> <CRLF>
  1042.             {
  1043.                 char pathname[260];
  1044.                 //extrai parametro <pathname>
  1045.                 int n=5; int k=0;
  1046.                 if (buffer[n] != '/' && buffer[n] != '\\') //se nao vier formatado como diretorio
  1047.                 {pathname[0]= '/'; k=1;}
  1048.                 while (buffer[n] != '\r' && n<nbytes)
  1049.                 {pathname[k] = buffer[n]; n++; k++;}
  1050.                 pathname[k] = '\0';
  1051.                
  1052.                 dados_transferencia dados; //guarda os dados que serão passados para a Thread que deletará o arquivo
  1053.                
  1054.                 WaitForSingleObject(Hmutex, INFINITE);
  1055.                        
  1056.                 for (n=0; n<MAX_TRANSF; n++)
  1057.                 {if (thread_transf[n]==-1) {break;}} //busca uma posicao vazia para guardar a handle e identificador da Thread que será criada
  1058.                        
  1059.                 dados.pos=n; //guarda a posicao na matriz de handles, para passar para a Thread
  1060.                 dados.controle_Socket = Cliente.Socket;//Socket conexao de controle
  1061.                 //endereco do arquivo a deletar
  1062.                 strcpy (dados.endereco_arq, dir_atual);
  1063.                 strcat (dados.endereco_arq, pathname);
  1064.                
  1065.                 //Cria a Thread com a funcao para deletar arquivos    
  1066.                 Hthread_transf[n] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)deleta_arquivo, &dados, 0, (LPDWORD)&thread_transf[n]);
  1067.                
  1068.                 if (Hthread_transf[n] == NULL) //erro ao cria a Thread
  1069.                 {
  1070.                     thread_transf[n]=-1;
  1071.                     snprintf (buffer, MAX_MSG, "450 Erro ao deletar arquivo.\r\n");
  1072.                     nbytes = send(Cliente.Socket,buffer,strlen(buffer),0);
  1073.                 }
  1074.                 ReleaseMutex(Hmutex);// libera o mutex - os outros "processos" voltam a rodar
  1075.                
  1076.                 if (nbytes <= 0 || nbytes == SOCKET_ERROR)
  1077.                 {Desconecta_Cliente(&Cliente, true, 2); return 1;}
  1078.                 continue;  
  1079.             }
  1080.            
  1081.             if (strncasecmp(buffer,"RNFR",4) == 0) //define arquivo a ser renomeado -  RNFR <SP> <pathname> <CRLF>
  1082.             {
  1083.                 char pathname[260];
  1084.                 //extrai parametro <pathname>
  1085.                 int n=5; int k=0;
  1086.                 if (buffer[n] != '/' && buffer[n] != '\\') //se nao vier formatado como diretorio
  1087.                 {pathname[0]= '/'; k=1;}
  1088.                 while (buffer[n] != '\r' && n<nbytes)
  1089.                 {pathname[k] = buffer[n]; n++; k++;}
  1090.                 pathname[k] = '\0';
  1091.                 //endereco do arquivo a renomear
  1092.                 strcpy (arq_rename, dir_atual);
  1093.                 strcat (arq_rename, pathname);
  1094.                
  1095.                 if (strlen (pathname) > 1) //se pathname é um nome de arquivo válido
  1096.                 {snprintf (buffer, MAX_MSG, "350 Comando RNFR Ok! Aguardando comando RNTO.\r\n");}
  1097.                 else
  1098.                 {snprintf (buffer, MAX_MSG, "450 Requested file action not taken.\r\n");}
  1099.                
  1100.                 nbytes = send(Cliente.Socket,buffer,strlen(buffer),0); //envia msg
  1101.                 if (nbytes <= 0 || nbytes == SOCKET_ERROR) //erro ao enviar mensagem
  1102.                 {Desconecta_Cliente(&Cliente, true, 2); return 1;}
  1103.                 continue;  
  1104.             }
  1105.            
  1106.             if (strncasecmp(buffer,"RNTO",4) == 0) //define o novo nome do arquivo a ser renomeado (o arquivo foi definido pelo comando RNFR)
  1107.             {   //RNTO <SP> <pathname> <CRLF>
  1108.                
  1109.                 char pathname[260], arq_new_name[260];
  1110.                 //extrai parametro <pathname>
  1111.                 int n=5; int k=0;
  1112.                 if (buffer[n] != '/' && buffer[n] != '\\') //se nao vier formatado como diretorio
  1113.                 {pathname[0]= '/'; k=1;}
  1114.                 while (buffer[n] != '\r' && n<nbytes)
  1115.                 {pathname[k] = buffer[n]; n++; k++;}
  1116.                 pathname[k] = '\0'; //pathname guarda o novo nome do arquivo que foi definido para ser renomeado pelo comando RNFR
  1117.                
  1118.                 //endereco do arquivo que será renomeado
  1119.                 strcpy (arq_new_name, dir_atual);
  1120.                 strcat (arq_new_name, pathname);
  1121.                
  1122.                 if (rename (arq_rename, arq_new_name) == 0) //se igual a 0 o arquivo foi renomeado de arq_rename para arq_new_name
  1123.                 {snprintf (buffer, MAX_MSG, "250 Comando RNTO Ok! Renomeado.\r\n");}
  1124.                 else
  1125.                 {snprintf (buffer, MAX_MSG, "553 Requested action not taken.\r\n");}
  1126.                
  1127.                 nbytes = send(Cliente.Socket,buffer,strlen(buffer),0); //envia msg
  1128.                 if (nbytes <= 0 || nbytes == SOCKET_ERROR) //erro ao enviar mensagem
  1129.                 {Desconecta_Cliente(&Cliente, true, 2); return 1;}
  1130.                 continue;  
  1131.             }
  1132.            
  1133.             if (strncasecmp(buffer,"MKD",3) == 0) //Cria um novo diretório - MKD <SP> <pathname> <CRLF>
  1134.             {
  1135.                 char pathname[260], dir_new[260];
  1136.                 //extrai parametro <pathname>
  1137.                 int n=4; int k=0;
  1138.                 if (buffer[n] != '/' && buffer[n] != '\\') //se nao vier formatado como diretorio
  1139.                 {pathname[0]= '/'; k=1;}
  1140.                 while (buffer[n] != '\r' && n<nbytes)
  1141.                 {pathname[k] = buffer[n]; n++; k++;}
  1142.                 pathname[k] = '\0'; //pathname guarda o nome do novo diretório
  1143.                
  1144.                 //endereco do novo diretório
  1145.                 strcpy (dir_new, dir_atual);
  1146.                 strcat (dir_new, pathname);
  1147.                
  1148.                 if ( _mkdir(dir_new) == 0 ) //se igual a 0 o novo diretório foi criado
  1149.                 {snprintf (buffer, MAX_MSG, "257 \"%s\" created.\r\n", pathname);}
  1150.                 else
  1151.                 {snprintf (buffer, MAX_MSG, "550 Requested action not taken.\r\n");}
  1152.                
  1153.                 nbytes = send(Cliente.Socket,buffer,strlen(buffer),0); //envia msg
  1154.                 if (nbytes <= 0 || nbytes == SOCKET_ERROR) //erro ao enviar mensagem
  1155.                 {Desconecta_Cliente(&Cliente, true, 2); return 1;}
  1156.                 continue;  
  1157.             }
  1158.            
  1159.             if (strncasecmp(buffer,"RMD",3) == 0) //Remove um diretório - RMD <SP> <pathname> <CRLF>
  1160.             {
  1161.                 char pathname[260], dir_delete[260];
  1162.                 //extrai parametro <pathname>
  1163.                 int n=4; int k=0;
  1164.                 if (buffer[n] != '/' && buffer[n] != '\\') //se nao vier formatado como diretorio
  1165.                 {pathname[0]= '/'; k=1;}
  1166.                 while (buffer[n] != '\r' && n<nbytes)
  1167.                 {pathname[k] = buffer[n]; n++; k++;}
  1168.                 pathname[k] = '\0';
  1169.                
  1170.                 strcpy (dir_delete, dir_atual);
  1171.                 strcat (dir_delete, pathname);
  1172.                
  1173.                 int retorno = deleta_diretorio (dir_delete); //varre o diretorio e sub diretorios e os deleta    
  1174.                
  1175.                 if (retorno == 0) //o diretorio foi deletado corretamente
  1176.                 {snprintf (buffer, MAX_MSG, "250 Deletado.\r\n");}
  1177.                 else //erro ao deletar
  1178.                 {snprintf (buffer, MAX_MSG, "550 Requested action not taken.\r\n");}
  1179.                
  1180.                 nbytes = send(Cliente.Socket,buffer,strlen(buffer),0);
  1181.                 if (nbytes <= 0 || nbytes == SOCKET_ERROR)
  1182.                 {Desconecta_Cliente(&Cliente, true, 2); return 1;}
  1183.                 continue;  
  1184.             }
  1185.            
  1186.             if (nao_implem) //se for true o comando recebido nao foi implementado
  1187.             {
  1188.                 //comando nao implementado
  1189.                 strcpy (buffer, "502 Command not implemented.\r\n");
  1190.                 nbytes = send(Cliente.Socket,buffer,strlen(buffer),0);
  1191.                 if (nbytes <= 0 || nbytes == SOCKET_ERROR)
  1192.                 {Desconecta_Cliente(&Cliente, true, 2); return 1;}
  1193.             }
  1194.    
  1195.     } //fim do loop  
  1196.     Desconecta_Cliente(&Cliente, false, 0);
  1197.     return 1;
  1198. }
  1199.  
  1200. //==============================================================================
  1201.  
  1202. int Listen_Socket (int porta, int n_conexoes) //Cria um socket e o coloca em modo de escuta
  1203. {
  1204.     int error;
  1205.     WSAData wsaData;
  1206.    
  1207.     if ((error = WSAStartup(MAKEWORD(2, 2), &wsaData)) == SOCKET_ERROR) //versao 2.2 do Winsock DLL
  1208.     {return -1;}
  1209.    
  1210.     int serverSocket = socket(AF_INET, SOCK_STREAM, 0); //cria o socket
  1211.     if (serverSocket == SOCKET_ERROR)
  1212.     {return -1;}
  1213.    
  1214.     struct sockaddr_in server;
  1215.     server.sin_family = AF_INET;
  1216.     server.sin_port = htons(porta);
  1217.     server.sin_addr.s_addr = INADDR_ANY; //aceita conexoes em qualquer endereco
  1218.     if (bind(serverSocket, (sockaddr*)&server, sizeof(server)) == SOCKET_ERROR)
  1219.     {
  1220.         closesocket(serverSocket);
  1221.         return -1;
  1222.     }
  1223.     if (listen(serverSocket, n_conexoes) == SOCKET_ERROR) //coloca o servidor em escuta
  1224.     {
  1225.         closesocket(serverSocket);
  1226.         return -1;
  1227.     }
  1228.    
  1229.     return serverSocket; //caso tudo ocorra corretamente a funcao retorna o socket criado
  1230. }
  1231.  
  1232. //==============================================================================
  1233.  
  1234. int Connect_Socket (int porta, char *host) //Cria um socket faz a conexao cliente-servidor
  1235. {
  1236.     int error;
  1237.     WSAData wsaData;
  1238.    
  1239.     if ((error = WSAStartup(MAKEWORD(2, 2), &wsaData)) == SOCKET_ERROR) //versao 2.2 do Winsock DLL
  1240.     {return -1;}
  1241.    
  1242.     int Socket = socket(AF_INET, SOCK_STREAM, 0); //cria o socket
  1243.     if (Socket == SOCKET_ERROR)
  1244.     {return -1;}
  1245.    
  1246.     struct hostent *host_entry;
  1247.     if ((host_entry = gethostbyname(host)) == NULL || host_entry->h_addrtype != AF_INET /*IPv4*/) //obtem o host a partir do nome passado pelo usuario
  1248.     {return -1;}
  1249.    
  1250.     struct sockaddr_in server;
  1251.     server.sin_family = AF_INET;
  1252.     server.sin_port = htons(porta);
  1253.     server.sin_addr.s_addr = *(unsigned long*) host_entry->h_addr;
  1254.     if (connect(Socket, (sockaddr*)&server, sizeof(server)) == SOCKET_ERROR) //conecta ao servidor
  1255.     {return -1;}
  1256.  
  1257.     return Socket; //caso tudo ocorra corretamente a funcao retorna o socket criado
  1258. }
  1259.  
  1260. //==============================================================================
  1261.  
  1262. void Desconecta_Cliente (cliente_tipo *Cli, bool msg_on, int info_type)
  1263. {  
  1264.     if (msg_on) //se desejar enviar msg, msg_on é true
  1265.     {
  1266.         char buffer [64];
  1267.         switch (info_type)
  1268.         {
  1269.             case 1: //caso seja uma desconexao apropriada, o parametro info_type é true
  1270.             strcpy (buffer, "221 Service closing control connection.\r\n"); break;
  1271.        
  1272.             case 2: //caso seja uma desconexao inesperada, o parametro info é false
  1273.             strcpy (buffer, "421 Service not available, closing control connection.\r\n"); break;
  1274.         }
  1275.         send(Cli->Socket,buffer,strlen(buffer),0);
  1276.     }
  1277.     closesocket(Cli->Socket);  //fecha o socket do cliente
  1278.     WaitForSingleObject(Hmutex, INFINITE);    //obtem mutex        
  1279.     cout << Cli->ID << " [Socket " << Cli->Socket << "] desconectado." << endl;              
  1280.     n_clientes_conectados--;
  1281.     thread[Cli->pos] = -1; //seta a posicao com um valor nulo
  1282.     CloseHandle (Hthread[Cli->pos]);              
  1283.     cout << "Agora sao " << n_clientes_conectados << " clientes conectados.\n" << endl;
  1284.     ReleaseMutex(Hmutex); // libera o mutex
  1285. }
  1286.  
  1287. //==============================================================================
  1288.  
  1289. void Finaliza_Conexao (int serversocket)
  1290. {
  1291.     for (int n=0; n<MAX_CLIENTES; n++)
  1292.     {if (thread[n] != -1) {CloseHandle(Hthread[n]);}} //fecha Handles das Threads ativas
  1293.     CloseHandle(Hmutex); //fecha o mutex utilizado
  1294.     closesocket(serversocket); //fecha Socket de escuta que aceita conexoes ao servidor
  1295.     WSACleanup();
  1296.     cout << "Servidor: desconectado!\n" << endl;
  1297. }
  1298.  
  1299. //==============================================================================
  1300.  
  1301. void formata_IP (char *IP_server, char *IP_formatado) //Troca ponto por virgula no endereco IP
  1302. {                                                     // ex: 127.0.0.1 torna-se 127,0,0,1
  1303.     int size=strlen(IP_server), n;
  1304.     for (n=0; n<size; n++)
  1305.     {
  1306.         if (IP_server[n] == '.')
  1307.         {IP_formatado[n] = ',';}
  1308.         else
  1309.         {IP_formatado[n] = IP_server[n];}
  1310.     }
  1311.     IP_formatado[n]='\0';
  1312. }
  1313.  
  1314. //==============================================================================
  1315.  
  1316. void obtem_ip_porta (char *host_port, char *IP, int *porta) //obtem IP e porta a partir do formato h1,h2,h3,h4,p1,p2
  1317. {
  1318.     int n, k=0;
  1319.     for (n=0; k<4; n++)
  1320.     {
  1321.         if (host_port[n] == ',')
  1322.         {IP[n] = '.'; k++;}
  1323.         else
  1324.         {IP[n] = host_port[n];}
  1325.     }
  1326.     IP[n-1] ='\0';
  1327.    
  1328.     char aux[5];
  1329.     k=0;
  1330.     for (n; host_port[n]!=','; n++)
  1331.     {
  1332.         aux[k] = host_port[n]; k++;
  1333.     }
  1334.     aux[k] = '\0'; *porta = atoi(aux)*256;
  1335.     k=0;
  1336.     n++;
  1337.     int size = strlen(host_port);
  1338.     for (n; n<size; n++)
  1339.     {
  1340.         aux[k] = host_port[n]; k++;
  1341.     }
  1342.     aux[k] = '\0'; *porta = *porta + atoi(aux);
  1343. }
  1344.  
  1345. //==============================================================================
  1346.  
  1347. //funcao que verifica se um arquivo existe
  1348. int arquivo_existe (const char *filename)
  1349. {
  1350.     FILE *arquivo;
  1351.  
  1352.     if (strlen(filename) > PATH_MAX)
  1353.     {return 0;} //nao existe, ultrapassa PATH_MAX
  1354.  
  1355.     if(arquivo = fopen(filename, "rb"))
  1356.     {
  1357.         fclose(arquivo);
  1358.         return 1; //existe
  1359.     }
  1360.     return 0; //nao existe
  1361. }
  1362.  
  1363. //==============================================================================
  1364.  
  1365. int envia_listadir (char padrao_listagem, char *gpath, int user_DTSocket)
  1366. {
  1367.     //padrao_envio = '0': Padrao UNIX de listagem de arquivos e diretorios
  1368.     //padrao_envio = '1': Padrao MS-DOS de listagem de arquivos e diretorios
  1369.    
  1370.     char path[260], pathname[260];
  1371.     char datamod[24], permissao[16], tipo_path[16], tamanho_str[128];
  1372.     struct stat statbuf;
  1373.     struct tm *tm;
  1374.     char *accesses[] = {"---", "--x", "-w-", "-wx", "r--", "r-x", "rw-", "rwx"};
  1375.     unsigned short link;
  1376.     unsigned long tamanho;
  1377.     int i=0, nbytes=0;
  1378.    
  1379.     if (strlen(gpath) > PATH_MAX)
  1380.     {return 1;}
  1381.    
  1382.     strcpy (path, gpath); //copia local da variavel global path
  1383.        
  1384.     // ponteiro para entrada do arquivo na pasta
  1385.     struct dirent *pent = NULL;
  1386.     // Ponteiros para os diretórios:
  1387.     DIR *pdir;    
  1388.     // Tentando inicializar o ponteiro para o diretório
  1389.     pdir = opendir (path);
  1390.  
  1391.     // caso o pdir não seja inicializado corretamente, aborta a função
  1392.     if (pdir == NULL)
  1393.     {return 1;}
  1394.  
  1395.     while (pent = readdir (pdir)) // enquanto houver um diretorio ou arquivo para listar
  1396.     {  
  1397.         if (pent == NULL) // se o pent (ponteiro entrada) não retornar nada
  1398.         {closedir (pdir); return 1;}    
  1399.        
  1400.         strcpy (pathname, path);
  1401.         strcat (pathname, "/");
  1402.         strcat (pathname, pent->d_name);
  1403.        
  1404.         if (strlen(pathname) > PATH_MAX)
  1405.         {return 1;}
  1406.        
  1407.         /* Obter informacoes de entrada */
  1408.         if (stat(pathname, &statbuf) != 0)
  1409.         {return 1;}
  1410.        
  1411.         if (pent->d_name[0] != '.') //evita envio de hierarquia de pastas fora da compartilhada
  1412.         {      
  1413.          /* tipo de arquivo */
  1414.         strcpy(permissao,"-"); //por default
  1415.         if(S_ISREG(statbuf.st_mode)) { strcpy(permissao,"-"); strcpy (tipo_path, " ");} //Arquivo regular
  1416.         if(S_ISDIR(statbuf.st_mode)) { strcpy(permissao,"d"); strcpy (tipo_path, " <DIR>");} //Diretorio
  1417.         if(S_ISCHR(statbuf.st_mode)) { strcpy(permissao,"c"); strcpy (tipo_path, " ");} //Dispositivo de caracter
  1418.        
  1419.         /* permissão.*/
  1420.         for(i = 6; i >= 0; i -=3)
  1421.         {strcat(permissao, accesses[(statbuf.st_mode >> i) & 7]);}
  1422.         fflush(stdin);
  1423.        
  1424.         /* numero de link */
  1425.         link = statbuf.st_nlink;
  1426.        
  1427.         /* tamanho do arquivo.*/
  1428.         tamanho = (intmax_t)statbuf.st_size;
  1429.        
  1430.         tm = localtime(&statbuf.st_mtime); //obtem hora local
  1431.  
  1432.         /* monta as informações no formato de envio */
  1433.        
  1434.         if (padrao_listagem == '0') //Padrao UNIX de listagem de arquivos e diretorios
  1435.         {
  1436.             /* Obter data em string. */
  1437.             strftime(datamod, 24, "%b %d %H:%M", tm);
  1438.             /*Monta informações no formato UNIX*/
  1439.             snprintf (pathname, 260, "%s %u user group %lu %s %s\r\n", permissao, link, tamanho, datamod, pent->d_name);
  1440.         }
  1441.        
  1442.         else //Padrao MS-DOS de listagem de arquivos e diretorios
  1443.         {
  1444.             /* Obter data em string. */
  1445.             strftime(datamod, 24, "%m-%d-%y %I:%M%p", tm);
  1446.            
  1447.             /*testa o tipo de path*/
  1448.             if (strcmp (tipo_path, " <DIR>") == 0) //é um diretório - não possui um tamanho associado a ele
  1449.             {strcpy (tamanho_str," ");}
  1450.             else //não é um diretório - logo possui um tamanho em bytes
  1451.             {snprintf (tamanho_str, 128, "%lu ", tamanho);}
  1452.                        
  1453.             /*Monta informações no formato MS-DOS*/
  1454.             snprintf (pathname, 260, "%s%s%s%s\r\n", datamod, tipo_path, tamanho_str, pent->d_name);
  1455.         }
  1456.        
  1457.         /*envia os dados da listagem*/
  1458.         nbytes = send(user_DTSocket, pathname, strlen(pathname), 0);
  1459.         if (nbytes <= 0 || nbytes == SOCKET_ERROR)
  1460.         {return 1;}
  1461.         }
  1462.     }
  1463.     // Encerra o ponteiro para o diretório
  1464.     closedir (pdir);
  1465.    
  1466.     return 0;
  1467. }
  1468.  
  1469. //==============================================================================
  1470.  
  1471. //funcao que guarda em uma variavel o tamanho em bytes dos arquivos em um diretorio
  1472.  
  1473. int tamanho_dir (char *dir, unsigned long *tamanho)
  1474. {
  1475.     struct stat statbuf;
  1476.     *tamanho = 0;
  1477.     char pathname[260];
  1478.    
  1479.     if (strlen(dir) > PATH_MAX)
  1480.     {return -1;}
  1481.        
  1482.     // ponteiro para entrada do arquivo na pasta
  1483.     struct dirent *pent = NULL;
  1484.     // Ponteiros para os diretórios:
  1485.     DIR *pdir;    
  1486.     // Tentando inicializar o ponteiro para o diretório
  1487.     pdir = opendir (dir);
  1488.  
  1489.     // caso o pdir não seja inicializado corretamente, dir guarda o caminho para um arquivo
  1490.     if (pdir == NULL)
  1491.     {
  1492.         if (stat(dir, &statbuf) != 0)
  1493.         {return -1;}
  1494.         /* tamanho do arquivo.*/
  1495.         *tamanho = (intmax_t)statbuf.st_size;
  1496.         return 0;
  1497.     }
  1498.     //se dir guarda o caminho para um diretorio
  1499.     while (pent = readdir (pdir)) // enquanto houver um diretorio ou arquivo para listar
  1500.     {  
  1501.         if (pent == NULL) // se o pent (ponteiro entrada) não retornar nada
  1502.         {closedir (pdir); return -1;}  
  1503.        
  1504.         strcpy (pathname, dir);
  1505.         strcat (pathname, "/");
  1506.         strcat (pathname, pent->d_name);
  1507.        
  1508.         if (strlen(pathname) > PATH_MAX)
  1509.         {return -1;}
  1510.        
  1511.         /* Obter informacoes de entrada */
  1512.         if (stat(pathname, &statbuf) != 0)
  1513.         {return -1;}
  1514.         /* tamanho do arquivo.*/
  1515.         *tamanho = *tamanho + (intmax_t)statbuf.st_size;
  1516.     }
  1517.     closedir (pdir);
  1518.     return 0;
  1519. }
  1520. //==============================================================================
  1521.  
  1522. //funcao para enviar arquivos binarios (como .mp3, .txt, .bmp, .pdf, etc) para um Socket
  1523. //retorna 0 se o arquivo foi enviado com sucesso ou 1 se não foi
  1524.  
  1525. int envia_arquivo(dados_transferencia *dados)
  1526. {  
  1527.     FILE* arquivo;
  1528.     char msg[64];
  1529.     int nBytes, Bytes_lidos, retorno=0;
  1530.     unsigned long file_size=1, size_check=0; //atribui 1 e 0 só para iniciarem com valores diferentes
  1531.     const int TAMANHO_PACOTE = 1024; //1 kbyte
  1532.     dados_transferencia d;
  1533.    
  1534.     WaitForSingleObject(Hmutex, INFINITE);    //obtem mutex
  1535.     d = *dados; //cópia local dos dados para a transferencia de arquivo
  1536.     ReleaseMutex(Hmutex);
  1537.    
  1538.     if (d.data_Socket < 0 || d.data_Socket == SOCKET_ERROR) //verifica se o Socket de dados passado no parametro da funcao é válido
  1539.     {retorno=1;} //erro
  1540.    
  1541.     if (d.controle_Socket < 0 || d.controle_Socket == SOCKET_ERROR) //verifica se o Socket de controle passado no parametro da funcao é válido
  1542.     {retorno=1;} //erro
  1543.    
  1544.     if (strlen(d.endereco_arq) > PATH_MAX)
  1545.     {retorno=1;} //ultrapassa PATH_MAX
  1546.    
  1547.     if ((arquivo = fopen (d.endereco_arq, "rb"))!=NULL && retorno!=1)
  1548.     {
  1549.         retorno = 1; //retorno assume 1, só mudará para 0 caso a transferência seja bem sucedida
  1550.        
  1551.         //obtém o tamanho do arquivo
  1552.         fseek (arquivo, 0, SEEK_END);
  1553.         file_size=ftell(arquivo);
  1554.         rewind(arquivo);
  1555.        
  1556.         if (file_size != -1L) //se não houve erro no cálculo do tamanho do arquivo
  1557.         {
  1558.             //n = 2 vezes o número de pacotes necessarios, segurança para garantir uma parada ao while abaixo, responsavel pelo loop de envio
  1559.             unsigned int n = ((file_size/TAMANHO_PACOTE) + 1)*2;
  1560.             unsigned int k=0, i;
  1561.            
  1562.             char* buffer;
  1563.             buffer = (char*)malloc(TAMANHO_PACOTE + 128); //aloca memoria para guardar os dados que serão enviados
  1564.            
  1565.             if (buffer != NULL) //se a memoria foi alocada
  1566.             {
  1567.                 size_check=0;
  1568.                
  1569.                 while(size_check < file_size && k<n)
  1570.                 {                            
  1571.                     Bytes_lidos = fread (buffer, sizeof(char), TAMANHO_PACOTE, arquivo);
  1572.                     nBytes = send(d.data_Socket, buffer, Bytes_lidos, 0);
  1573.                
  1574.                     if (nBytes == SOCKET_ERROR) //se houve erro no envio, tenta reenvio ate 10 vezes
  1575.                     {
  1576.                         i=0;
  1577.                         while (i<10 && nBytes == SOCKET_ERROR)
  1578.                         {nBytes = send(d.data_Socket, buffer, Bytes_lidos, 0); i++;}
  1579.                     }
  1580.                
  1581.                     size_check += nBytes;
  1582.                     if (nBytes == SOCKET_ERROR || feof(arquivo)!=0)
  1583.                     {break;}
  1584.                     k++;
  1585.                 }
  1586.                 free(buffer);
  1587.             }
  1588.         }
  1589.     }
  1590.     fclose (arquivo);
  1591.    
  1592.     if (size_check == file_size) //o arquivo foi enviado corretamente
  1593.     {snprintf (msg, 64, "226 Download complete - Closing data connection.\r\n"); retorno=0;}
  1594.     else //erro no envio
  1595.     {snprintf (msg, 64, "426 Connection closed - Download aborted.\r\n"); retorno=1;}
  1596.    
  1597.     send(d.controle_Socket,msg,strlen(msg),0);
  1598.                
  1599.     closesocket (d.data_Socket); //fecha conexao de transferencia de dados
  1600.     WaitForSingleObject(Hmutex, INFINITE);    //obtem mutex
  1601.     thread_transf[d.pos] = -1; //seta com um valor nulo a posicao identificadora da thread de transferencia
  1602.     CloseHandle (Hthread_transf[d.pos]); //fecha handle de transferencia
  1603.     ReleaseMutex(Hmutex); // libera o mutex            
  1604.    
  1605.     return retorno;
  1606. }
  1607.  
  1608. //==============================================================================
  1609.  
  1610. //funcao para receber arquivos binarios (como .mp3, .txt, .bmp, .pdf, etc) de um Socket
  1611. //retorna 0 se o arquivo foi recebido com sucesso ou 1 se não foi
  1612.  
  1613. int recebe_arquivo(dados_transferencia *dados)
  1614. {  
  1615.     FILE* arquivo;
  1616.     char msg[64];
  1617.     int nBytes = SOCKET_ERROR, size_buffer, Bytes_escritos, retorno=0;
  1618.     const int TAMANHO_PACOTE = 4096; //4 kbytes
  1619.     dados_transferencia d;
  1620.    
  1621.     WaitForSingleObject(Hmutex, INFINITE);    //obtem mutex
  1622.     d = *dados; //cópia local dos dados para a transferencia de arquivo
  1623.     ReleaseMutex(Hmutex);
  1624.    
  1625.     if (d.data_Socket < 0 || d.data_Socket == SOCKET_ERROR) //verifica se o Socket de dados passado no parametro da funcao é válido
  1626.     {retorno=1;} //erro
  1627.    
  1628.     if (d.controle_Socket < 0 || d.controle_Socket == SOCKET_ERROR) //verifica se o Socket de controle passado no parametro da funcao é válido
  1629.     {retorno=1;} //erro
  1630.    
  1631.     if (strlen(d.endereco_arq) > PATH_MAX)
  1632.     {retorno=1;} //ultrapassa PATH_MAX
  1633.    
  1634.     if ((arquivo = fopen (d.endereco_arq, "wb"))!=NULL && retorno!=1)
  1635.     {      
  1636.         retorno = 1; //retorno assume 1, só mudará para 0 caso a transferência seja bem sucedida
  1637.        
  1638.         char* buffer;
  1639.         size_buffer = TAMANHO_PACOTE + 128;
  1640.         buffer = (char*)malloc(size_buffer); //aloca memoria para guardar os dados que serão enviados
  1641.         int i;
  1642.        
  1643.         if (buffer != NULL) //se a memoria foi alocada
  1644.         {        
  1645.         while(true)
  1646.         {                            
  1647.             nBytes = recv(d.data_Socket, buffer, size_buffer, 0);
  1648.            
  1649.             if (nBytes == SOCKET_ERROR) //se houve erro no recebimento, tenta receber de novo ate 10 vezes
  1650.             {
  1651.                 i=0;
  1652.                 while (i<10 && nBytes == SOCKET_ERROR)
  1653.                 {nBytes = recv(d.data_Socket, buffer, size_buffer, 0); i++;}
  1654.             }
  1655.            
  1656.             if (nBytes == 0 || nBytes == SOCKET_ERROR)
  1657.             {break;}
  1658.            
  1659.             Bytes_escritos = fwrite (buffer, sizeof(char), nBytes, arquivo);    
  1660.         }
  1661.         free(buffer);
  1662.         }
  1663.     }
  1664.     fclose (arquivo);
  1665.    
  1666.     if (nBytes != SOCKET_ERROR) //o arquivo foi recebido corretamente
  1667.     {snprintf (msg, 64, "226 Upload complete - Closing data connection.\r\n"); retorno=0;}
  1668.     else //erro no recebimento
  1669.     {snprintf (msg, 64, "426 Connection closed - Upload aborted.\r\n"); retorno=1;}
  1670.    
  1671.     send(d.controle_Socket,msg,strlen(msg),0);
  1672.                
  1673.     closesocket (d.data_Socket); //fecha conexao de transferencia de dados
  1674.     WaitForSingleObject(Hmutex, INFINITE);    //obtem mutex
  1675.     thread_transf[d.pos] = -1; //seta com um valor nulo a posicao identificadora da thread de transferencia
  1676.     CloseHandle (Hthread_transf[d.pos]); //fecha handle de transferencia
  1677.     ReleaseMutex(Hmutex); // libera o mutex            
  1678.    
  1679.     return retorno;
  1680. }
  1681.  
  1682. //==============================================================================
  1683.  
  1684. //funcao para deletar arquivos
  1685.  
  1686. int deleta_arquivo(dados_transferencia *dados)
  1687. {  
  1688.     char msg[64];
  1689.     int retorno=2;
  1690.     dados_transferencia d;
  1691.    
  1692.     WaitForSingleObject(Hmutex, INFINITE);    //obtem mutex
  1693.     d = *dados; //cópia local dos dados para deletar arquivo
  1694.     ReleaseMutex(Hmutex);
  1695.    
  1696.     if (d.controle_Socket < 0 || d.controle_Socket == SOCKET_ERROR) //verifica se o Socket de controle passado no parametro da funcao é válido
  1697.     {retorno=1;} //erro
  1698.    
  1699.     if (strlen(d.endereco_arq) > PATH_MAX)
  1700.     {retorno=1;} //ultrapassa PATH_MAX
  1701.    
  1702.     if (retorno == 2)
  1703.     {
  1704.         retorno = remove(d.endereco_arq); //deleta arquivo, retorna 0 se deletou ou um valor diferente de 0 se nao deletou
  1705.    
  1706.         if (retorno == 0) //o arquivo foi deletado corretamente
  1707.         {snprintf (msg, 64, "250 Arquivo deletado.\r\n");}
  1708.         else //erro ao deletar
  1709.         {snprintf (msg, 64, "450 Erro ao deletar arquivo.\r\n"); retorno=1;}
  1710.    
  1711.         send(d.controle_Socket,msg,strlen(msg),0);
  1712.     }
  1713.    
  1714.     WaitForSingleObject(Hmutex, INFINITE);    //obtem mutex
  1715.     thread_transf[d.pos] = -1; //seta com um valor nulo a posicao identificadora da thread
  1716.     CloseHandle (Hthread_transf[d.pos]); //fecha handle
  1717.     ReleaseMutex(Hmutex); // libera o mutex
  1718.                
  1719.     return retorno;
  1720. }
  1721.  
  1722. //==============================================================================
  1723.  
  1724. //função que varre um diretorio com seus sub diretorios e os deleta
  1725.  
  1726. int deleta_diretorio(char *gdir)
  1727. {      
  1728.         if (strlen(gdir) > PATH_MAX)
  1729.         {return 1;} //ultrapassa PATH_MAX
  1730.        
  1731.         char dir[260], pathname[260];
  1732.         struct stat statbuf;
  1733.         struct dirent *pent = NULL;
  1734.        
  1735.         strcpy (dir, gdir); //cópia local do endereço do diretório
  1736.        
  1737.         // Ponteiros para os diretórios:
  1738.         DIR *pdir;    
  1739.         // Tentando inicializar o ponteiro para o diretório
  1740.         pdir = opendir (dir);
  1741.         // caso o pdir não seja inicializado corretamente
  1742.         if (pdir == NULL)
  1743.         {return 1;}
  1744.        
  1745.         while (pent = readdir (pdir)) // enquanto houver um diretorio a ser lido
  1746.         {  
  1747.             if (pent == NULL) // se o pent (ponteiro entrada) não retornar nada, a pasta esta vazia
  1748.             {break;}
  1749.            
  1750.             strcpy (pathname, dir);
  1751.             strcat (pathname, "/");
  1752.             strcat (pathname, pent->d_name);
  1753.            
  1754.             if (strlen(pathname) > PATH_MAX)
  1755.             {break;}
  1756.            
  1757.             // Obter informacoes de entrada
  1758.             if (stat(pathname, &statbuf) != 0)
  1759.             {break;}
  1760.            
  1761.             if (pent->d_name[0] != '.') //evita hierarquia de pastas fora da compartilhada
  1762.             {
  1763.                 if(S_ISREG(statbuf.st_mode)) {remove(pathname);} //Arquivo
  1764.                 if(S_ISDIR(statbuf.st_mode)) {deleta_diretorio (pathname);} //Diretorio - faz chamada recursiva da funcão
  1765.             }
  1766.         }
  1767.         closedir (pdir);
  1768.         if ( _rmdir (dir) == 0 ) {return 0;} else {return 1;}
  1769. }
  1770.  
  1771. //==============================================================================
  1772.  
  1773. //função que carrega dados de clientes cadastrados a partir de um arquivo-lista - retorna 0 caso ID seja encontrada
  1774.  
  1775. int carrega_cliente (char *ID, char *Senha, int *permissao_escrita)
  1776. {
  1777.     FILE *clientes;
  1778.    
  1779.     if ((clientes = fopen ("Clientes.txt", "r")) != NULL)
  1780.     {
  1781.         char senha_teste[64], id_teste[64];
  1782.         int p_escrita, teste;
  1783.        
  1784.         while (feof(clientes)==0)
  1785.         {  
  1786.             teste=0;
  1787.             id_teste[0]='\0';
  1788.             fscanf (clientes, "%63[^\n]\n", id_teste);
  1789.             if (strlen(id_teste) < 1) {teste=1;}  
  1790.             senha_teste[0]='\0';
  1791.             fscanf (clientes, "%63[^\n]\n", senha_teste);
  1792.             if (strlen(senha_teste) < 1) {teste=1;}
  1793.             fscanf (clientes, "%d\n", &p_escrita);
  1794.             if (p_escrita != 1) {p_escrita = 0;}
  1795.            
  1796.             if (teste == 0)
  1797.             {
  1798.                 if (strcmp (ID, id_teste) == 0) //se a ID passada no parametro confere com uma do arquivo
  1799.                 {
  1800.                     strcpy (Senha, senha_teste);
  1801.                     *permissao_escrita = p_escrita;
  1802.                     fclose (clientes);
  1803.                     return 0;
  1804.                 }
  1805.             }
  1806.         }
  1807.         fclose (clientes);
  1808.     }  
  1809.     return 1;
  1810. }
  1811.  
  1812. //==============================================================================
Advertisement
Add Comment
Please, Sign In to add comment