Club Delphi  
    FTP   CCD     Buscar   Trucos   Trabajo   Foros

Retroceder   Foros Club Delphi > Principal > Internet
Registrarse FAQ Miembros Calendario Guía de estilo Temas de Hoy

Colaboración Paypal con ClubDelphi

Respuesta
 
Herramientas Buscar en Tema Desplegado
  #1  
Antiguo 26-08-2007
Avatar de seoane
[seoane] seoane is offline
Miembro Premium
 
Registrado: feb 2004
Ubicación: A Coruña, España
Posts: 3.717
Poder: 24
seoane Va por buen camino
ftp Upload / Download (Aplicación)

Hace tiempo que no pongo código por aquí, al menos no código útil, así que vamos a ver que os parece esta pequeña herramienta.

Se trata de una aplicación de consola que permite subir o bajar un archivo de un servidor ftp, pero con la particularidad que lo cifra al subirlo y lo descifra al bajarlo. El cifrado que utiliza es AES de 256 bits, que nos permite usar contraseñas de hasta 32 caracteres, y es lo suficientemente seguro para que lo utilice el gobierno de los EE.UU.

Pero dije que este no era código inútil, así que vamos a buscarle alguna utilidad. La primera, y mas evidente, es subir un archivo:
Código:
ftpup --key=clave --local=archivo.txt --password=pass --user=user --remote=/archivo.txt --server=servidor.com
El comando anterior subiría el archivo "archivo.txt" al servidor "servidor.com", usando el nombre de usuario "user", el password "pass" y la clave de cifrado "clave". Hasta ahora nada que no se pudiera hacer con cualquier otro cliente de ftp, salvo el cifrado. Se me ocurre que puede servir para hacer una copia de seguridad de un documento privado, si lo combinamos, por ejemplo, con las tareas programadas de Windows.

Para bajarlo, nada mas sencillo que esto:
Código:
ftpup -d --key=clave --local=archivo.txt --password=pass --user=user --remote=/archivo.txt --server=servidor.com
Pero ya me conocéis, hay que buscar otro uso mas interesante a esto, darle otra vuelta de tuerca. Que os parece utilizarlo para guardar, y leer, anotaciones cifradas desde cualquier ordenador, sin dejar ningún rastro en el equipo. Pues vamos a probar, lo primero es decir que en el parámetro --local se puede usar un "." para decir que se utilice en vez de un archivo, la entrada y salida estándar. Sabiendo esto, podríamos hacer algo como esto:
Código:
echo Mensaje secreto | ftpup --key=clave --local=. --password=pass --user=user --remote=/archivo.txt --server=servidor.com
Y para leerlo algo como esto:
Código:
ftpup -d --key=clave --local=. --password=pass --user=user --remote=/archivo.txt --server=servidor.com
Y ya puestos, podríamos guardar cómodamente nuestras contraseñas en un archivo de texto, y desde nuestra casa subirlas al ftp. Así desde cualquier equipo en el que estemos podremos ver las contraseñas en pantalla, si necesidad de guardar ningún archivo en el disco.

Bueno, seguro que alguna utilidad mas se le puede sacar. Como siempre, criticas (constructivas) y sugerencias serán bien recibidas. Espero vuestros comentarios.

El código (es una aplicación de consola):
Código Delphi [-]
program ftpup;

{$APPTYPE CONSOLE}

uses
  Windows,
  SysUtils,
  Classes,
  WinInet,
  AES in 'AES.pas';

type
  EGetOptError = class(Exception);

var
  Options: record
    Download: Boolean; 
    Key: String;
    Local: String;
    Password: String;
    Port: Integer;
    Remote: String;
    Server: String;
    User: String;
  end;

function Starts(Sub, Str: String): Boolean;
begin
  Result:= SameText(Sub,Copy(Str,1,Length(sub)));
end;

procedure Getopt;
var
  i,j: Integer;
  Str: String;
begin
  FillChar(Options,Sizeof(Options),#0);
  for i:= 1 to ParamCount do
  begin
    Str:= ParamStr(i);
    if (Copy(Str,1,2) = '--') and (Length(Str) > 2) then
    begin
      if SameText(Str,'--Download') then
        Options.Download:= TRUE
      else if Starts('--Key=',Str) then
      begin
        if Options.Key = EmptyStr then
          Options.Key:= Copy(Str,Length('--Key=') + 1,MAXINT)
        else
          raise EGetOptError.Create(Str);
      end else if Starts('--Local=',Str) then
      begin
        if Options.Local = EmptyStr then
          Options.Local:= Copy(Str,Length('--Local=') + 1,MAXINT)
        else
          raise EGetOptError.Create(Str);
      end else if Starts('--Remote=',Str) then
      begin
        if Options.Remote = EmptyStr then
          Options.Remote:= Copy(Str,Length('--Remote=') + 1,MAXINT)
        else
          raise EGetOptError.Create(Str);
      end else if Starts('--Password=',Str) then
      begin
        if Options.Password = EmptyStr then
          Options.Password:= Copy(Str,Length('--Password=') + 1,MAXINT)
        else
          raise EGetOptError.Create(Str);
      end else if Starts('--Port=',Str) then
      begin
        if Options.Port = 0 then
          Options.Port:= StrToInt(Copy(Str,Length('--Port=') + 1,MAXINT))
        else
          raise EGetOptError.Create(Str);
      end else if Starts('--Server=',Str) then
      begin
        if Options.Server = EmptyStr then
          Options.Server:= Copy(Str,Length('--Server=') + 1,MAXINT)
        else
          raise EGetOptError.Create(Str);
      end else if Starts('--User=',Str) then
      begin
        if Options.User = EmptyStr then
          Options.User:= Copy(Str,Length('--User=') + 1,MAXINT)
        else
          raise EGetOptError.Create(Str);
      end else
        raise EGetOptError.Create(Str);
    end else if (Copy(Str,1,1) = '-') and (Length(Str) > 1) then
    begin
      Str:= UpperCase(Str);
      for j:= 2 to Length(Str) do
      begin
        if Str[j] = 'D' then
          Options.Download:= TRUE
        else
          raise EGetOptError.Create(Str);
      end;
    end else
    begin
      raise EGetOptError.Create(Str);
    end;
  end;
  if Options.Port = 0 then
    Options.Port:= 21;
end;

function ftpUpload(Stream: TStream; RemoteFile, Server: String; Port: Word;
  Username, Password: PChar; Key: TAESExpandedKey): Boolean;
var
  hNet: HINTERNET;
  hCon: HINTERNET;
  hFile: HINTERNET;
  Context: DWORD;
  Count: Cardinal;
  State, Temp: TAESState;
  Size: int64;
begin
  Result := FALSE;
  Context:= 0;
  hNet := InternetOpen('agent', INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0);
  if (hNet <> nil) then
  begin
    hCon:= InternetConnect(hNet,PChar(Server),Port,Username,Password,
      INTERNET_SERVICE_FTP,0,Context);
    if (hCon <> nil) then
    begin
      hFile:= FtpOpenFile(hCon,PChar(RemoteFile),GENERIC_WRITE,
        FTP_TRANSFER_TYPE_BINARY,Context);
      if hFile <> nil then
      begin
        try
          if Stream is TFileStream then
            Size:= Stream.Size
          else
            Size:= -1;
          if InternetWriteFile(hFile,@Size,Sizeof(Size),Count) and
            (Count = Sizeof(Size))  then
          begin
            FillChar(Temp,Sizeof(Temp),#0);
            FillChar(State,Sizeof(State),#0);
            Count:= Stream.Read(State,Sizeof(State));
            while  Count > 0 do
            begin
              XORState(State,Temp);
              AESEncrypt(State,Key);
              if not InternetWriteFile(hFile,@State,Sizeof(State),Count) then
                break;
              Temp:= State;
              FillChar(State,Sizeof(State),#0);
              Count:= Stream.Read(State,Sizeof(State));
            end;
            Result:= Count = 0;
          end;
          if not Result then
            Writeln(SysErrorMessage(GetLastError));
        except
          On E: Exception do
            Writeln(E.Message);
        end;
        InternetCloseHandle(hFile);
      end else Writeln(SysErrorMessage(GetLastError));
      InternetCloseHandle(hCon);
    end else Writeln(SysErrorMessage(GetLastError));
    InternetCloseHandle(hNet);
  end else Writeln(SysErrorMessage(GetLastError));
end;

function ftpDownload(Stream: TStream; RemoteFile, Server: String; Port: Word;
  Username, Password: PChar; Key: TAESExpandedKey): Boolean;
var
  hNet: HINTERNET;
  hCon: HINTERNET;
  hFile: HINTERNET;
  Context: DWORD;
  Count: Cardinal;
  State, Temp, Ant: TAESState;
  Size: int64;
begin
  Result := FALSE;
  Context:= 0;
  hNet := InternetOpen('agent', INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0);
  if (hNet <> nil) then
  begin
    hCon:= InternetConnect(hNet,PChar(Server),Port,Username,Password,
      INTERNET_SERVICE_FTP,0,Context);
    if (hCon <> nil) then
    begin
      hFile:= FtpOpenFile(hCon,PChar(RemoteFile),GENERIC_READ,
        FTP_TRANSFER_TYPE_BINARY,Context);
      if hFile <> nil then
      begin
        try
          if InternetReadFile(hFile,@Size,Sizeof(Size),Count) and
            (Count = Sizeof(Size))  then
          begin
            FillChar(Temp,Sizeof(Temp),#0);
            FillChar(State,Sizeof(State),#0);
            if InternetReadFile(hFile,@State,Sizeof(State),Count) then
            begin
              while  Count > 0 do
              begin
                Ant:= State;
                AESDecrypt(State,Key);
                XORState(State,Temp);
                if Stream.Write(State,Count) <> Integer(Count) then
                  break;
                Temp:= Ant;
                FillChar(State,Sizeof(State),#0);
                if not InternetReadFile(hFile,@State,Sizeof(State),Count) then
                  break;
              end;
              Result:= Count = 0;
            end;
            if (Stream is TFileStream) and (Stream.Size > Size)
              and (Size > 0 )then
              Stream.Size:= Size;
            if not Result then
              Writeln(SysErrorMessage(GetLastError));
          end;
        except
          On E: Exception do
            Writeln(E.Message);
        end;
        InternetCloseHandle(hFile);
      end else Writeln(SysErrorMessage(GetLastError));
      InternetCloseHandle(hCon);
    end else Writeln(SysErrorMessage(GetLastError));
    InternetCloseHandle(hNet);
  end else Writeln(SysErrorMessage(GetLastError));
end;

procedure Run;
var
  AESKey: TAESKey;
  ExKey: TAESExpandedKey;
  Stream: TStream;
begin
  FillChar(AESKey,Sizeof(AESKey),#0);
  if Length(Options.Key) > Sizeof(AESKey) then
    move(PChar(Options.Key)^,AESKey,Sizeof(AESKey))
  else
    move(PChar(Options.Key)^,AESKey,Length(Options.Key));
  AESExpandKey(ExKey,AESKey);
  if Options.Local = '.' then
  begin
    if Options.Download then
      Stream:= THandleStream.Create(GetStdHandle(STD_OUTPUT_HANDLE))
    else
      Stream:= THandleStream.Create(GetStdHandle(STD_INPUT_HANDLE));
  end else
  begin
    if Options.Download then
      Stream:= TFileStream.Create(Options.Local,fmCreate)
    else
      Stream:= TFileStream.Create(Options.Local,fmOpenRead or fmShareDenyNone);
  end;
  try
    if Options.Download then
      ftpDownload(Stream,Options.Remote,Options.Server,Options.Port,
        PChar(Options.User),PChar(Options.Password),ExKey)
    else
      ftpUpload(Stream,Options.Remote,Options.Server,Options.Port,
        PChar(Options.User),PChar(Options.Password),ExKey)
  finally
    Stream.Free;
  end;
end;

procedure Help;
begin
  Writeln;
  Writeln('Uso: ftpup [opciones]');
  Writeln('  --download -d');
  Writeln('    Baja el archivo del servidor');
  Writeln('  --key');
  Writeln('    Clave de cifrado, hasta 32 caracteres.');
  Writeln('  --local');
  Writeln('    Archivo local. Se puede utilizar un . para indicar la');
  Writeln('    entrada o salida estandar');
  Writeln('  --password');
  Writeln('    Clave de acceso al servidor ftp');
  Writeln('  --port');
  Writeln('    El puerto del ftp');
  Writeln('  --remote');
  Writeln('    Ruta del archivo remoto');
  Writeln('  --server');
  Writeln('    Direccion del servidor ftp');
  Writeln('  --user');
  Writeln('    Nombre de usuario del ftp');
  Writeln;
  Writeln('Ejemplos:');
  Writeln('  ftpup --key=clave --local=archivo.txt --password=pass ' +
    '--user=user --remote=/archivo.txt --server=servidor.com');
  Writeln('    Sube al servidor el archivo "archivo.txt".');
  Writeln('  ftpup -d --key=clave --local=. --password=pass ' +
    '--user=user --remote=/archivo.txt --server=servidor.com');
  Writeln('    Descarga el archivo "archivo.txt" y lo muestra por pantalla');
  Writeln;      
end;


begin
  try
    if ParamCount > 0 then
    begin
      GetOpt;
      Run;
    end else
      Help;
  except
    On E: EGetOptError do
    begin
      Writeln('Error en el parametro: ',E.Message);
      Help;
    end;
    On E: Exception do
      Writeln(E.Message);
  end;
end.
Archivos Adjuntos
Tipo de Archivo: zip ftpup.zip (8,7 KB, 56 visitas)

Última edición por seoane fecha: 26-08-2007 a las 13:49:42.
Responder Con Cita
  #2  
Antiguo 26-08-2007
Avatar de ArdiIIa
[ArdiIIa] ArdiIIa is offline
Miembro Premium
 
Registrado: nov 2003
Ubicación: Valencia city
Posts: 1.481
Poder: 22
ArdiIIa Va por buen camino
A pesar de que lo has proclamado a los cuatro vientos, no estoy muy seguro de que no tengas nada contra las Indy...
__________________
Un poco de tu generosidad puede salvar la vida a un niño. ASÍ DE SENCILLO
Responder Con Cita
  #3  
Antiguo 26-08-2007
Avatar de seoane
[seoane] seoane is offline
Miembro Premium
 
Registrado: feb 2004
Ubicación: A Coruña, España
Posts: 3.717
Poder: 24
seoane Va por buen camino
Cita:
Empezado por ArdiIIa Ver Mensaje
A pesar de que lo has proclamado a los cuatro vientos, no estoy muy seguro de que no tengas nada contra las Indy...
Yo contra Indy no tengo nada, pero a veces es como "matar moscas a cañonazos". Con lo simple que queda con wininet, además de pequeño (menos de 100 kb) y, sobre todo, utiliza la misma configuración del proxy que el internet explorer, ¿que mas se puede pedir?.

Todo esto no significa que cuando hay que "sacar el cañón para matar un mosca rebelde", por ejemplo para usar SSL, no utilice Indy.

A todo esto, ¿que te parece el programa Ardilla?
Responder Con Cita
  #4  
Antiguo 26-08-2007
Avatar de Casimiro Notevi
Casimiro Notevi Casimiro Notevi is offline
Moderador
 
Registrado: sep 2004
Ubicación: En algún lugar.
Posts: 32.257
Poder: 10
Casimiro Notevi Tiene un aura espectacularCasimiro Notevi Tiene un aura espectacular
Esto sí que es código "no inútil".
Tiene todo lo mejor que existe, las 3 "b": bueno, bonito y barato
Responder Con Cita
  #5  
Antiguo 26-08-2007
Avatar de seoane
[seoane] seoane is offline
Miembro Premium
 
Registrado: feb 2004
Ubicación: A Coruña, España
Posts: 3.717
Poder: 24
seoane Va por buen camino
Cita:
Empezado por Casimiro Notevi Ver Mensaje
Esto sí que es código "no inútil".
Tiene todo lo mejor que existe, las 3 "b": bueno, bonito y barato
Eso, eso ... así me gusta Casimiro
Responder Con Cita
  #6  
Antiguo 26-08-2007
Avatar de eduarcol
[eduarcol] eduarcol is offline
Miembro Premium
 
Registrado: ago 2003
Ubicación: En los estados Zulia y Merida de Venezuela
Posts: 4.151
Poder: 26
eduarcol Va por buen camino
Esta muy bueno seoane, con tu permiso lo voy a comenzar a utilizar, voy a crear una especie de servicio para actualizar los sistemas, cuando lo termine lo coloco por aca a ver que tal
__________________
...Yo naci en esta ribera del arauca vibr@d0r
Soy hermano de la espuma,
de la garza, de la rosa y del sol...
Viva Venezuela
Responder Con Cita
  #7  
Antiguo 26-08-2007
Avatar de Jure
Jure Jure is offline
Miembro
 
Registrado: may 2003
Ubicación: Valencia, Vzla.
Posts: 528
Poder: 22
Jure Va por buen camino
Thumbs up

Cita:
Empezado por seoane Ver Mensaje
... Con lo simple que queda con wininet, además de pequeño (menos de 100 kb) y, sobre todo, utiliza la misma configuración del proxy que el internet explorer, ¿que mas se puede pedir?....
Seoane es un excelente código, como muy bien dices: Simple, corto y práctico. Gracias por compartirlo
__________________

"Dios juzga al árbol por sus frutos, y no por sus raíces"


Como esta la sibidigua ???
Responder Con Cita
  #8  
Antiguo 26-08-2007
Avatar de seoane
[seoane] seoane is offline
Miembro Premium
 
Registrado: feb 2004
Ubicación: A Coruña, España
Posts: 3.717
Poder: 24
seoane Va por buen camino
Cita:
Empezado por eduarcol Ver Mensaje
Esta muy bueno seoane, con tu permiso lo voy a comenzar a utilizar, voy a crear una especie de servicio para actualizar los sistemas, cuando lo termine lo coloco por aca a ver que tal
Excelente, ya nos contaras que tal te fue

Cita:
Empezado por Jure Ver Mensaje
Seoane es un excelente código, como muy bien dices: Simple, corto y práctico. Gracias por compartirlo
Gracias
Responder Con Cita
  #9  
Antiguo 31-08-2007
Avatar de seoane
[seoane] seoane is offline
Miembro Premium
 
Registrado: feb 2004
Ubicación: A Coruña, España
Posts: 3.717
Poder: 24
seoane Va por buen camino
Vamos a darle un poco de vida a este hilo

Imaginar que que queremos descifrar un archivo cifrado con ftpup desde linux.

Nada nos impide usar algo como esto:
Código:
wine ftpup (Parametros)
Funcionaría, pero por qué no crear una aplicación propia para linux. Vamos a utilizar el compilador freepascal y el siguiente código:
Código Delphi [-]
program cifrar;

uses
  SysUtils,
  Classes,
  AES in 'AES.pas';

type
  EGetOptError = class(Exception);

var
  Options: record
    Decrypt: Boolean;
    Dest: String;
    Key: String;
    Source: String;    
  end;

function Starts(Sub, Str: String): Boolean;
begin
  Result:= SameText(Sub,Copy(Str,1,Length(sub)));
end;

procedure Getopt;
var
  i,j: Integer;
  Str: String;
begin
  FillChar(Options,Sizeof(Options),#0);
  for i:= 1 to ParamCount do
  begin
    Str:= ParamStr(i);
    if (Copy(Str,1,2) = '--') and (Length(Str) > 2) then
    begin
      if SameText(Str,'--Decrypt') then
        Options.Decrypt:= TRUE
      else if Starts('--Key=',Str) then
      begin
        if Options.Key = EmptyStr then
          Options.Key:= Copy(Str,Length('--Key=') + 1,MAXINT)
        else
          raise EGetOptError.Create(Str);
      end else if Starts('--Source=',Str) then
      begin
        if Options.Source = EmptyStr then
          Options.Source:= Copy(Str,Length('--Source=') + 1,MAXINT)
        else
          raise EGetOptError.Create(Str);
      end else if Starts('--Dest=',Str) then
      begin
        if Options.Dest = EmptyStr then
          Options.Dest:= Copy(Str,Length('--Dest=') + 1,MAXINT)
        else
          raise EGetOptError.Create(Str);
      end;
    end else if (Copy(Str,1,1) = '-') and (Length(Str) > 1) then
    begin
      Str:= UpperCase(Str);
      for j:= 2 to Length(Str) do
      begin
        if Str[j] = 'D' then
          Options.Decrypt:= TRUE
        else
          raise EGetOptError.Create(Str);
      end;
    end else
    begin
      raise EGetOptError.Create(Str);
    end;
  end;
end;


procedure Run;
var
  AESKey: TAESKey;
  ExKey: TAESExpandedKey;
  Src, Dst: TStream;
  Size: int64;
  IV: TAESState;
begin
  FillChar(AESKey,Sizeof(AESKey),#0);
  if Length(Options.Key) > Sizeof(AESKey) then
    move(PChar(Options.Key)^,AESKey,Sizeof(AESKey))
  else
    move(PChar(Options.Key)^,AESKey,Length(Options.Key));
  AESExpandKey(ExKey,AESKey);
  FillChar(IV,Sizeof(IV),#0);  
  Src:= TFileStream.Create(Options.Source,fmOpenRead or fmShareDenyNone);
  try
    Dst:= TFileStream.Create(Options.Dest,fmCreate); 
    try 
      if Options.Decrypt then
      begin
        if Src.Read(Size,Sizeof(Size)) = Sizeof(Size) then
        begin
          AESDecryptStreamCBC(IV,Src,Dst,ExKey);
          if (Size > 0) and (Src.Size > Size) then
            Dst.Size:= Size;
        end;
      end else
      begin
        Size:= Src.Size;
        Dst.Write(Size,Sizeof(Size));
        AESEncryptStreamCBC(IV,Src,Dst,ExKey);
      end;
    finally
      Dst.Free;
    end;
  finally
    Src.Free;
  end;
end;

procedure Help;
begin
  Writeln;
  Writeln('Uso: cifrar [opciones]');
  Writeln('  --decrypt -d');
  Writeln('    Descifrar (Cifrar es la opcion por defecto)');
  Writeln('  --key');
  Writeln('    Clave de cifrado, hasta 32 caracteres.');
  Writeln('  --source');
  Writeln('    Archivo de origen');
  Writeln('  --dest');
  Writeln('    Archivo de destino.');  
  Writeln;
  Writeln('Ejemplos:');
  Writeln('  cifrar --key=clave --source=archivo.txt --dest=archivo.bin');
  Writeln('  cifrar -d --key=clave --source=archivo.txt --dest=archivo.bin');
  Writeln;      
end;


begin
  try
    if ParamCount > 0 then
    begin
      GetOpt;
      Run;
    end else
      Help;
  except
    On E: EGetOptError do
    begin
      Writeln('Error en el parametro: ',E.Message);
      Help;
    end;
    On E: Exception do
      Writeln(E.Message);
  end;
end.
Y lo compilamos de la siguiente manera:
Código:
fpc -Sd cifrar.pas
El programa resultante permite cifrar y descifrar un archivo utilizando AES 256, siguiendo el mismo formato que el programa ftpup.

Por ejemplo, así cifra:
Código:
./cifrar --source=archivo.txt --dest=archivo.bin --key=clave
Y así descifra:
Código:
./cifrar -d --source=archivo.bin --dest=archivo.txt --key=clave
PD: La unit AES.pas la puedes conseguir aquí

Última edición por seoane fecha: 31-08-2007 a las 16:26:06.
Responder Con Cita
  #10  
Antiguo 31-08-2007
Avatar de Casimiro Notevi
Casimiro Notevi Casimiro Notevi is offline
Moderador
 
Registrado: sep 2004
Ubicación: En algún lugar.
Posts: 32.257
Poder: 10
Casimiro Notevi Tiene un aura espectacularCasimiro Notevi Tiene un aura espectacular
Estupendo, seoane, lo pruebo en cuanto tenga un momento. (*)






(*) Cuando reciba mi nuevo monitor
Responder Con Cita
  #11  
Antiguo 31-08-2007
Avatar de seoane
[seoane] seoane is offline
Miembro Premium
 
Registrado: feb 2004
Ubicación: A Coruña, España
Posts: 3.717
Poder: 24
seoane Va por buen camino
Cita:
Empezado por Casimiro Notevi Ver Mensaje
Estupendo, seoane, lo pruebo en cuanto tenga un momento.
Sera un placer que me digas tu opinión


PD: Usa el código que hay ahora, el que puse al principio tenia algunos errores.
Responder Con Cita
Respuesta



Normas de Publicación
no Puedes crear nuevos temas
no Puedes responder a temas
no Puedes adjuntar archivos
no Puedes editar tus mensajes

El código vB está habilitado
Las caritas están habilitado
Código [IMG] está habilitado
Código HTML está deshabilitado
Saltar a Foro

Temas Similares
Tema Autor Foro Respuestas Último mensaje
upload masivo kayetano PHP 12 06-12-2006 17:45:39
UPLOAD de varios archivos por código HombreSigma .NET 3 04-12-2005 16:23:07
download periódico tcp_ip_es Internet 13 14-10-2005 18:00:27
como upload una bB.D. bdf con un form kassel PHP 4 22-01-2004 22:01:55
download delphi 5 Emiro Varios 2 26-10-2003 12:42:26


La franja horaria es GMT +2. Ahora son las 01:52:30.


Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi
Copyright 1996-2007 Club Delphi