initial import
This commit is contained in:
		
						commit
						1092c73986
					
				| 
						 | 
				
			
			@ -0,0 +1 @@
 | 
			
		|||
.pio
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,39 @@
 | 
			
		|||
 | 
			
		||||
This directory is intended for project header files.
 | 
			
		||||
 | 
			
		||||
A header file is a file containing C declarations and macro definitions
 | 
			
		||||
to be shared between several project source files. You request the use of a
 | 
			
		||||
header file in your project source file (C, C++, etc) located in `src` folder
 | 
			
		||||
by including it, with the C preprocessing directive `#include'.
 | 
			
		||||
 | 
			
		||||
```src/main.c
 | 
			
		||||
 | 
			
		||||
#include "header.h"
 | 
			
		||||
 | 
			
		||||
int main (void)
 | 
			
		||||
{
 | 
			
		||||
 ...
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Including a header file produces the same results as copying the header file
 | 
			
		||||
into each source file that needs it. Such copying would be time-consuming
 | 
			
		||||
and error-prone. With a header file, the related declarations appear
 | 
			
		||||
in only one place. If they need to be changed, they can be changed in one
 | 
			
		||||
place, and programs that include the header file will automatically use the
 | 
			
		||||
new version when next recompiled. The header file eliminates the labor of
 | 
			
		||||
finding and changing all the copies as well as the risk that a failure to
 | 
			
		||||
find one copy will result in inconsistencies within a program.
 | 
			
		||||
 | 
			
		||||
In C, the usual convention is to give header files names that end with `.h'.
 | 
			
		||||
It is most portable to use only letters, digits, dashes, and underscores in
 | 
			
		||||
header file names, and at most one dot.
 | 
			
		||||
 | 
			
		||||
Read more about using header files in official GCC documentation:
 | 
			
		||||
 | 
			
		||||
* Include Syntax
 | 
			
		||||
* Include Operation
 | 
			
		||||
* Once-Only Headers
 | 
			
		||||
* Computed Includes
 | 
			
		||||
 | 
			
		||||
https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,47 @@
 | 
			
		|||
/*
 | 
			
		||||
   Copyright 2016-2019 Bo Zimmerman
 | 
			
		||||
 | 
			
		||||
   Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
   you may not use this file except in compliance with the License.
 | 
			
		||||
   You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
     http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
   Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
   distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
   See the License for the specific language governing permissions and
 | 
			
		||||
   limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
enum ConnFlag
 | 
			
		||||
{
 | 
			
		||||
  FLAG_DISCONNECT_ON_EXIT=1,
 | 
			
		||||
  FLAG_PETSCII=2,
 | 
			
		||||
  FLAG_TELNET=4,
 | 
			
		||||
  FLAG_ECHO=8,
 | 
			
		||||
  FLAG_XONXOFF=16,
 | 
			
		||||
  FLAG_SECURE=32,
 | 
			
		||||
  FLAG_RTSCTS=64
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class ConnSettings
 | 
			
		||||
{
 | 
			
		||||
  public:
 | 
			
		||||
    boolean petscii = false;
 | 
			
		||||
    boolean telnet = false;
 | 
			
		||||
    boolean echo = false;
 | 
			
		||||
    boolean xonxoff = false;
 | 
			
		||||
    boolean rtscts = false;
 | 
			
		||||
    boolean secure = false;
 | 
			
		||||
 | 
			
		||||
    ConnSettings(int flagBitmap);
 | 
			
		||||
    ConnSettings(const char *dmodifiers);
 | 
			
		||||
    ConnSettings(String modifiers);
 | 
			
		||||
    int getBitmap();
 | 
			
		||||
    int getBitmap(FlowControlType forceCheck);
 | 
			
		||||
    void setFlag(ConnFlag flagMask, boolean newVal);
 | 
			
		||||
    String getFlagString();
 | 
			
		||||
 | 
			
		||||
    static void IPtoStr(IPAddress *ip, String &str);
 | 
			
		||||
    static IPAddress *parseIP(const char *ipStr);
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,48 @@
 | 
			
		|||
/*
 | 
			
		||||
   Copyright 2016-2019 Bo Zimmerman
 | 
			
		||||
 | 
			
		||||
   Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
   you may not use this file except in compliance with the License.
 | 
			
		||||
   You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
     http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
   Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
   distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
   See the License for the specific language governing permissions and
 | 
			
		||||
   limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
enum LogOutputState
 | 
			
		||||
{
 | 
			
		||||
  LOS_NADA=0,
 | 
			
		||||
  LOS_SocketIn=1,
 | 
			
		||||
  LOS_SocketOut=2,
 | 
			
		||||
  LOS_SerialIn=3,
 | 
			
		||||
  LOS_SerialOut=4
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static unsigned long expectedSerialTime = 1000;
 | 
			
		||||
 | 
			
		||||
static boolean logFileOpen = false;
 | 
			
		||||
static bool logFileDebug= false;
 | 
			
		||||
static File logFile; 
 | 
			
		||||
 | 
			
		||||
static void logSerialOut(const uint8_t c);
 | 
			
		||||
static void logSocketOut(const uint8_t c);
 | 
			
		||||
static void logSerialIn(const uint8_t c);
 | 
			
		||||
static void logSocketIn(const uint8_t c);
 | 
			
		||||
static void logPrint(const char* msg);
 | 
			
		||||
static void logPrintln(const char* msg);
 | 
			
		||||
static void logPrintf(const char* format, ...);
 | 
			
		||||
static void logPrintfln(const char* format, ...);
 | 
			
		||||
static char *TOHEX(const char *s, char *hex, const size_t len);
 | 
			
		||||
static char *TOHEX(long a);
 | 
			
		||||
static char *TOHEX(int a);
 | 
			
		||||
static char *TOHEX(unsigned int a);
 | 
			
		||||
static char *TOHEX(unsigned long a);
 | 
			
		||||
static char *tohex(uint8_t a);
 | 
			
		||||
static char *TOHEX(uint8_t a);
 | 
			
		||||
static uint8_t FROMHEX(uint8_t a1, uint8_t a2);
 | 
			
		||||
static char *FROMHEX(const char *hex, char *s, const size_t len);
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,75 @@
 | 
			
		|||
/*
 | 
			
		||||
   Copyright 2016-2019 Bo Zimmerman
 | 
			
		||||
 | 
			
		||||
   Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
   you may not use this file except in compliance with the License.
 | 
			
		||||
   You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
	   http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
   Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
   distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
   See the License for the specific language governing permissions and
 | 
			
		||||
   limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
#ifdef ZIMODEM_ESP32
 | 
			
		||||
# include <WiFi.h>
 | 
			
		||||
# define ENC_TYPE_NONE WIFI_AUTH_OPEN
 | 
			
		||||
# include <HardwareSerial.h>
 | 
			
		||||
# include <SPIFFS.h>
 | 
			
		||||
# include <Update.h>
 | 
			
		||||
# include "SD.h"
 | 
			
		||||
# include "SPI.h"
 | 
			
		||||
# include "driver/uart.h"
 | 
			
		||||
  static HardwareSerial HWSerial(UART_NUM_2);
 | 
			
		||||
#else
 | 
			
		||||
# include "ESP8266WiFi.h"
 | 
			
		||||
# define HWSerial Serial
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include <FS.h>
 | 
			
		||||
 | 
			
		||||
char petToAsc(char c);
 | 
			
		||||
bool ascToPet(char *c, Stream *stream);
 | 
			
		||||
char ascToPetcii(char c);
 | 
			
		||||
bool handleAsciiIAC(char *c, Stream *stream);
 | 
			
		||||
 | 
			
		||||
static void setCharArray(char **target, const char *src)
 | 
			
		||||
{
 | 
			
		||||
  if(src == NULL)
 | 
			
		||||
    return;
 | 
			
		||||
  if(*target != NULL)
 | 
			
		||||
    free(*target);
 | 
			
		||||
  *target = (char *)malloc(strlen(src)+1);
 | 
			
		||||
  strcpy(*target,src);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void freeCharArray(char **arr)
 | 
			
		||||
{
 | 
			
		||||
  if(*arr == NULL)
 | 
			
		||||
    return;
 | 
			
		||||
  free(*arr);
 | 
			
		||||
  *arr = NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int modifierCompare(const char *match1, const char *match2)
 | 
			
		||||
{
 | 
			
		||||
  if(strlen(match1) != strlen(match2))
 | 
			
		||||
    return -1;
 | 
			
		||||
    
 | 
			
		||||
  for(int i1=0;i1<strlen(match1);i1++)
 | 
			
		||||
  {
 | 
			
		||||
    char c1=tolower(match1[i1]);
 | 
			
		||||
    bool found=false;
 | 
			
		||||
    for(int i2=0;i2<strlen(match2);i2++)
 | 
			
		||||
    {
 | 
			
		||||
      char c2=tolower(match2[i2]);
 | 
			
		||||
      found = found || (c1==c2);
 | 
			
		||||
    }
 | 
			
		||||
    if(!found)
 | 
			
		||||
      return -1;
 | 
			
		||||
  }
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,35 @@
 | 
			
		|||
/*
 | 
			
		||||
   Copyright 2016-2019 Bo Zimmerman
 | 
			
		||||
 | 
			
		||||
   Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
   you may not use this file except in compliance with the License.
 | 
			
		||||
   You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
     http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
   Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
   distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
   See the License for the specific language governing permissions and
 | 
			
		||||
   limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
class PhoneBookEntry
 | 
			
		||||
{
 | 
			
		||||
  public:
 | 
			
		||||
    unsigned long number;
 | 
			
		||||
    const char *address;
 | 
			
		||||
    const char *modifiers;
 | 
			
		||||
    const char *notes;
 | 
			
		||||
    PhoneBookEntry *next = null;
 | 
			
		||||
 | 
			
		||||
    PhoneBookEntry(unsigned long phnum, const char *addr, const char *mod, const char *note);
 | 
			
		||||
    ~PhoneBookEntry();
 | 
			
		||||
 | 
			
		||||
    static void loadPhonebook();
 | 
			
		||||
    static void clearPhonebook();
 | 
			
		||||
    static void savePhonebook();
 | 
			
		||||
    static bool checkPhonebookEntry(String cmd);
 | 
			
		||||
    static PhoneBookEntry *findPhonebookEntry(long number);
 | 
			
		||||
    static PhoneBookEntry *findPhonebookEntry(String number);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,44 @@
 | 
			
		|||
#ifdef INCLUDE_SD_SHELL
 | 
			
		||||
#ifndef ZIMODEM_PROTO_FTP
 | 
			
		||||
#define ZIMODEM_PROTO_FTP
 | 
			
		||||
/*
 | 
			
		||||
   Copyright 2016-2019 Bo Zimmerman
 | 
			
		||||
 | 
			
		||||
   Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
   you may not use this file except in compliance with the License.
 | 
			
		||||
   You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
     http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
   Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
   distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
   See the License for the specific language governing permissions and
 | 
			
		||||
   limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
class FTPHost
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
  char *hostIp = 0;
 | 
			
		||||
  int port = 0;
 | 
			
		||||
  bool doSSL = false;
 | 
			
		||||
  char *username = 0;
 | 
			
		||||
  char *pw = 0;
 | 
			
		||||
  char *path = 0;
 | 
			
		||||
  char *file = 0;
 | 
			
		||||
  ~FTPHost();
 | 
			
		||||
  bool doGet(FS *fs, const char *localpath, const char *remotepath);
 | 
			
		||||
  bool doPut(File &f, const char *remotepath);
 | 
			
		||||
  bool doLS(ZSerial *serial, const char *remotepath);
 | 
			
		||||
  bool parseUrl(uint8_t *vbuf, char **req);
 | 
			
		||||
  void fixPath(const char *remotepath);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
FTPHost *makeFTPHost(bool isUrl, FTPHost **host, uint8_t *buf, char **req);
 | 
			
		||||
bool parseFTPUrl(uint8_t *vbuf, char **hostIp, char **req, int *port, bool *doSSL, char **username, char **pw);
 | 
			
		||||
bool doFTPGet(FS *fs, const char *hostIp, int port, const char *localpath, const char *remotepath, const char *username, const char *pw, const bool doSSL);
 | 
			
		||||
bool doFTPPut(File &f, const char *hostIp, int port, const char *remotepath, const char *username, const char *pw, const bool doSSL);
 | 
			
		||||
bool doFTPLS(ZSerial *serial, const char *hostIp, int port, const char *remotepath, const char *username, const char *pw, const bool doSSL);
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,84 @@
 | 
			
		|||
#ifdef INCLUDE_SD_SHELL
 | 
			
		||||
#ifdef INCLUDE_HOSTCM
 | 
			
		||||
/* Converted from source reverse engineered from SP9000 roms by Rob Ferguson */
 | 
			
		||||
#include <FS.h>
 | 
			
		||||
 | 
			
		||||
# define HCM_BUFSIZ  104
 | 
			
		||||
# define HCM_SENDBUF (208/2 - 6)
 | 
			
		||||
# define HCM_FNSIZ 32
 | 
			
		||||
# define HCM_MAXFN 16
 | 
			
		||||
 | 
			
		||||
typedef struct _HCMFile
 | 
			
		||||
{
 | 
			
		||||
  char descriptor;
 | 
			
		||||
  File f;
 | 
			
		||||
  uint8_t mode;
 | 
			
		||||
  uint8_t format;
 | 
			
		||||
  uint8_t type;
 | 
			
		||||
  int reclen;
 | 
			
		||||
  char filename[HCM_FNSIZ+1];
 | 
			
		||||
  struct _HCMFile *nxt;
 | 
			
		||||
} HCMFile;
 | 
			
		||||
 | 
			
		||||
class HostCM
 | 
			
		||||
{
 | 
			
		||||
private:
 | 
			
		||||
  ZSerial hserial;
 | 
			
		||||
  const struct _HCOpts
 | 
			
		||||
  {
 | 
			
		||||
    unsigned int  speed = 15; //B9600
 | 
			
		||||
    unsigned int  parity = 0;// ?!
 | 
			
		||||
    unsigned int  stopb=0;
 | 
			
		||||
    unsigned char lineend=0xd;
 | 
			
		||||
    unsigned char prompt=0x11;
 | 
			
		||||
    unsigned char response=0x13;
 | 
			
		||||
    unsigned char ext=0;
 | 
			
		||||
  } opt PROGMEM;
 | 
			
		||||
 | 
			
		||||
  uint8_t outbuf[HCM_BUFSIZ];
 | 
			
		||||
  int odex = 0;
 | 
			
		||||
 | 
			
		||||
  uint8_t inbuf[HCM_BUFSIZ+1];
 | 
			
		||||
  int idex = 0;
 | 
			
		||||
 | 
			
		||||
  bool aborted = false;
 | 
			
		||||
  unsigned long lastNonPlusTm = 0;
 | 
			
		||||
  unsigned int plussesInARow = 0;
 | 
			
		||||
  unsigned long plusTimeExpire = 0;
 | 
			
		||||
  HCMFile files[HCM_MAXFN];
 | 
			
		||||
  FS *hFS = &SD;
 | 
			
		||||
  File openDirF = (File)0;
 | 
			
		||||
  File renameF = (File)0;
 | 
			
		||||
 | 
			
		||||
  char checksum(uint8_t *b, int n);
 | 
			
		||||
  void checkDoPlusPlusPlus(const int c, const unsigned long tm);
 | 
			
		||||
  bool checkPlusPlusPlusExpire(const unsigned long tm);
 | 
			
		||||
  void sendNAK();
 | 
			
		||||
  void sendACK();
 | 
			
		||||
  void sendError(const char* format, ...);
 | 
			
		||||
  bool closeAllFiles();
 | 
			
		||||
  HCMFile *addNewFileEntry();
 | 
			
		||||
  void delFileEntry(HCMFile *e);
 | 
			
		||||
  HCMFile *getFileByDescriptor(char c);
 | 
			
		||||
  int numOpenFiles();
 | 
			
		||||
 | 
			
		||||
  void protoOpenFile();
 | 
			
		||||
  void protoCloseFile();
 | 
			
		||||
  void protoPutToFile();
 | 
			
		||||
  void protoGetFileBytes();
 | 
			
		||||
  void protoOpenDir();
 | 
			
		||||
  void protoNextDirFile();
 | 
			
		||||
  void protoCloseDir();
 | 
			
		||||
  void protoSetRenameFile();
 | 
			
		||||
  void protoFinRenameFile();
 | 
			
		||||
  void protoEraseFile();
 | 
			
		||||
  void protoSeekFile();
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
  void receiveLoop();
 | 
			
		||||
  bool isAborted();
 | 
			
		||||
  HostCM(FS *fs);
 | 
			
		||||
  ~HostCM();
 | 
			
		||||
};
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,22 @@
 | 
			
		|||
#ifndef ZIMODEM_PROTO_HTTP
 | 
			
		||||
#define ZIMODEM_PROTO_HTTP
 | 
			
		||||
/*
 | 
			
		||||
   Copyright 2016-2019 Bo Zimmerman
 | 
			
		||||
 | 
			
		||||
   Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
   you may not use this file except in compliance with the License.
 | 
			
		||||
   You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
     http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
   Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
   distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
   See the License for the specific language governing permissions and
 | 
			
		||||
   limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
bool parseWebUrl(uint8_t *vbuf, char **hostIp, char **req, int *port, bool *doSSL);
 | 
			
		||||
bool doWebGetBytes(const char *hostIp, int port, const char *req, const bool doSSL, uint8_t *buf, int *bufSize);
 | 
			
		||||
WiFiClient *doWebGetStream(const char *hostIp, int port, const char *req, bool doSSL, uint32_t *responseSize);
 | 
			
		||||
bool doWebGet(const char *hostIp, int port, FS *fs, const char *filename, const char *req, const bool doSSL);
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,155 @@
 | 
			
		|||
#include <FS.h>
 | 
			
		||||
 | 
			
		||||
class KModem
 | 
			
		||||
{
 | 
			
		||||
private:
 | 
			
		||||
  static const int MAXPACKSIZ = 94; /* Maximum packet size */
 | 
			
		||||
  static const int MAXTRY = 20;     /* Times to retry a packet */
 | 
			
		||||
  static const int MYTIME = 10;     /* (10) Seconds after which I should be timed out */
 | 
			
		||||
  static const int MAXTIM = 60;     /* (60) Maximum timeout interval */
 | 
			
		||||
  static const int MINTIM = 2;      /* (2) Minumum timeout interval */
 | 
			
		||||
  static const char MYQUOTE ='#';   /* Quote character I will use */
 | 
			
		||||
  static const int MYPAD = 0;       /* Number of padding characters I will need */
 | 
			
		||||
  static const int MYPCHAR = 0;     /* Padding character I need (NULL) */
 | 
			
		||||
  static const char MYEOL = '\n';   /* End-Of-Line character I need */
 | 
			
		||||
  static const char SOH = 1;        /* Start of header */
 | 
			
		||||
  static const char CR = 13;        /* ASCII Carriage Return */
 | 
			
		||||
  static const char SP = 32;        /* ASCII space */
 | 
			
		||||
  static const char DEL = 127;      /* Delete (rubout) */
 | 
			
		||||
  static const char ESCCHR = '^';   /* Default escape character for CONNECT */
 | 
			
		||||
  static const char NUL = '\0';     /* Null character */
 | 
			
		||||
  static const char FALSE = 0;
 | 
			
		||||
  static const char TRUE = -1;
 | 
			
		||||
 | 
			
		||||
  int size=0,              /* Size of present data */
 | 
			
		||||
      rpsiz=0,             /* Maximum receive packet size */
 | 
			
		||||
      spsiz=0,             /* Maximum send packet size */
 | 
			
		||||
      pad=0,               /* How much padding to send */
 | 
			
		||||
      timint=0,            /* Timeout for foreign host on sends */
 | 
			
		||||
      n=0,                 /* Packet number */
 | 
			
		||||
      numtry=0,            /* Times this packet retried */
 | 
			
		||||
      oldtry=0,            /* Times previous packet retried */
 | 
			
		||||
      image=1,             /* -1 means 8-bit mode */
 | 
			
		||||
      debug=99,            /* indicates level of debugging output (0=none) */
 | 
			
		||||
      filecount=0,         /* Number of files left to send */
 | 
			
		||||
      filenum=0,
 | 
			
		||||
      mflg=0,              /* Flag for MacKermit mode */
 | 
			
		||||
      xflg=0;              /* flag for xmit directory structure */
 | 
			
		||||
  char state,              /* Present state of the automaton */
 | 
			
		||||
       padchar,            /* Padding character to send */
 | 
			
		||||
       eol,                /* End-Of-Line character to send */
 | 
			
		||||
       escchr,             /* Connect command escape character */
 | 
			
		||||
       quote,              /* Quote character in incoming data */
 | 
			
		||||
       *filnam,            /* Current file name */
 | 
			
		||||
       *filnamo,           /* File name sent */
 | 
			
		||||
       *ttyline,           /* Pointer to tty line */
 | 
			
		||||
       recpkt[MAXPACKSIZ], /* Receive packet buffer */
 | 
			
		||||
       packet[MAXPACKSIZ], /* Packet buffer */
 | 
			
		||||
       ldata[1024];        /* First line of data to send over connection */
 | 
			
		||||
  String **filelist = 0;
 | 
			
		||||
  int  (*recvChar)(ZSerial *ser, int);
 | 
			
		||||
  void (*sendChar)(ZSerial *ser, char);
 | 
			
		||||
  bool (*dataHandler)(File *kfp, unsigned long number, char *buffer, int len);
 | 
			
		||||
 | 
			
		||||
  void flushinput();
 | 
			
		||||
  void rpar(char data[]);
 | 
			
		||||
  void spar(char data[]);
 | 
			
		||||
  int gnxtfl();
 | 
			
		||||
  void bufemp(char buffer[], int len);
 | 
			
		||||
  void prerrpkt(char *msg);
 | 
			
		||||
  int bufill(char buffer[]);
 | 
			
		||||
  int rpack(int *len, int *num, char *data);
 | 
			
		||||
  int spack(char type, int num, int len, char *data);
 | 
			
		||||
  char rdata();
 | 
			
		||||
  char rinit();
 | 
			
		||||
  char rfile();
 | 
			
		||||
  char sfile();
 | 
			
		||||
  char sinit();
 | 
			
		||||
  char sdata();
 | 
			
		||||
  char sbreak();
 | 
			
		||||
  char seof();
 | 
			
		||||
 | 
			
		||||
  bool kfpClosed = true;
 | 
			
		||||
  String *errStr = 0;
 | 
			
		||||
public:
 | 
			
		||||
  String rootpath = "";
 | 
			
		||||
  FS *kfileSystem = &SD;
 | 
			
		||||
  File kfp;
 | 
			
		||||
  ZSerial kserial;
 | 
			
		||||
 | 
			
		||||
  KModem(FlowControlType commandFlow,
 | 
			
		||||
         int (*recvChar)(ZSerial *ser, int),
 | 
			
		||||
         void (*sendChar)(ZSerial *ser, char),
 | 
			
		||||
         bool (*dataHandler)(File *kfp, unsigned long, char*, int),
 | 
			
		||||
         String &errors);
 | 
			
		||||
  void setTransmitList(String **fileList, int numFiles);
 | 
			
		||||
  bool receive();
 | 
			
		||||
  bool transmit();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static int kReceiveSerial(ZSerial *ser, int del)
 | 
			
		||||
{
 | 
			
		||||
  unsigned long end=millis() + (del * 1000L);
 | 
			
		||||
  while(millis() < end)
 | 
			
		||||
  {
 | 
			
		||||
    serialOutDeque();
 | 
			
		||||
    if(ser->available() > 0)
 | 
			
		||||
    {
 | 
			
		||||
      int c=ser->read();
 | 
			
		||||
      logSerialIn(c);
 | 
			
		||||
      return c;
 | 
			
		||||
    }
 | 
			
		||||
    yield();
 | 
			
		||||
  }
 | 
			
		||||
  return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void kSendSerial(ZSerial *ser, char c)
 | 
			
		||||
{
 | 
			
		||||
  ser->write((uint8_t)c);
 | 
			
		||||
  ser->flush();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool kUDataHandler(File *kfp, unsigned long number, char *buf, int sz)
 | 
			
		||||
{
 | 
			
		||||
  for(int i=0;i<sz;i++)
 | 
			
		||||
    kfp->write((uint8_t)buf[i]);
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool kDDataHandler(File *kfp, unsigned long number, char *buf, int sz)
 | 
			
		||||
{
 | 
			
		||||
  for(int i=0;i<sz;i++)
 | 
			
		||||
  {
 | 
			
		||||
    int c=kfp->read();
 | 
			
		||||
    if(c<0)
 | 
			
		||||
    {
 | 
			
		||||
      if(i==0)
 | 
			
		||||
        return false;
 | 
			
		||||
      buf[i] = (char)26;
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
      buf[i] = (char)c;
 | 
			
		||||
  }
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static boolean kDownload(FlowControlType commandFlow, FS &fs, String **fileList, int fileCount, String &errors)
 | 
			
		||||
{
 | 
			
		||||
  KModem kmo(commandFlow, kReceiveSerial, kSendSerial, kDDataHandler, errors);
 | 
			
		||||
  kmo.kfileSystem = &fs;
 | 
			
		||||
  kmo.setTransmitList(fileList,fileCount);
 | 
			
		||||
  bool result = kmo.transmit();
 | 
			
		||||
  return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static boolean kUpload(FlowControlType commandFlow, FS &fs, String rootPath, String &errors)
 | 
			
		||||
{
 | 
			
		||||
  KModem kmo(commandFlow, kReceiveSerial, kSendSerial, kUDataHandler, errors);
 | 
			
		||||
  kmo.kfileSystem = &fs;
 | 
			
		||||
  kmo.rootpath = rootPath;
 | 
			
		||||
  bool result = kmo.receive();
 | 
			
		||||
  return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,21 @@
 | 
			
		|||
#ifndef ZIMODEM_PROTO_PING
 | 
			
		||||
#define ZIMODEM_PROTO_PING
 | 
			
		||||
#ifdef INCLUDE_PING
 | 
			
		||||
/*
 | 
			
		||||
   Copyright 2023-2023 Bo Zimmerman
 | 
			
		||||
 | 
			
		||||
   Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
   you may not use this file except in compliance with the License.
 | 
			
		||||
   You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
     http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
   Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
   distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
   See the License for the specific language governing permissions and
 | 
			
		||||
   limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
int ping(char *host);
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,140 @@
 | 
			
		|||
/*
 | 
			
		||||
   Copyright 2018-2019 Bo Zimmerman
 | 
			
		||||
 | 
			
		||||
   Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
   you may not use this file except in compliance with the License.
 | 
			
		||||
   You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
     http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
   Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
   distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
   See the License for the specific language governing permissions and
 | 
			
		||||
   limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
#include <FS.h>
 | 
			
		||||
 | 
			
		||||
class XModem 
 | 
			
		||||
{
 | 
			
		||||
  typedef enum
 | 
			
		||||
  {
 | 
			
		||||
    Crc,
 | 
			
		||||
    ChkSum  
 | 
			
		||||
  } transfer_t;
 | 
			
		||||
  
 | 
			
		||||
  private:
 | 
			
		||||
    //holds readed byte (due to dataAvail())
 | 
			
		||||
    int byte;
 | 
			
		||||
    //expected block number
 | 
			
		||||
    unsigned char blockNo;
 | 
			
		||||
    //extended block number, send to dataHandler()
 | 
			
		||||
    unsigned long blockNoExt;
 | 
			
		||||
    //retry counter for NACK
 | 
			
		||||
    int retries;
 | 
			
		||||
    //buffer
 | 
			
		||||
    char buffer[128];
 | 
			
		||||
    //repeated block flag
 | 
			
		||||
    bool repeatedBlock;
 | 
			
		||||
    File *xfile = null;
 | 
			
		||||
    ZSerial xserial;
 | 
			
		||||
 | 
			
		||||
    int  (*recvChar)(ZSerial *ser, int);
 | 
			
		||||
    void (*sendChar)(ZSerial *ser, char);
 | 
			
		||||
    bool (*dataHandler)(File *xfile, unsigned long number, char *buffer, int len);
 | 
			
		||||
    unsigned short crc16_ccitt(char *buf, int size);
 | 
			
		||||
    bool dataAvail(int delay);
 | 
			
		||||
    int dataRead(int delay);
 | 
			
		||||
    void dataWrite(char symbol);
 | 
			
		||||
    bool receiveFrameNo(void);
 | 
			
		||||
    bool receiveData(void);
 | 
			
		||||
    bool checkCrc(void);
 | 
			
		||||
    bool checkChkSum(void);
 | 
			
		||||
    bool receiveFrames(transfer_t transfer);
 | 
			
		||||
    bool sendNack(void);
 | 
			
		||||
    void init(void);
 | 
			
		||||
    
 | 
			
		||||
    bool transmitFrames(transfer_t);
 | 
			
		||||
    unsigned char generateChkSum(void);
 | 
			
		||||
    
 | 
			
		||||
  public:
 | 
			
		||||
    static const unsigned char XMO_NACK = 21;
 | 
			
		||||
    static const unsigned char XMO_ACK =  6;
 | 
			
		||||
 | 
			
		||||
    static const unsigned char XMO_SOH =  1;
 | 
			
		||||
    static const unsigned char XMO_EOT =  4;
 | 
			
		||||
    static const unsigned char XMO_CAN =  0x18;
 | 
			
		||||
 | 
			
		||||
    static const int receiveDelay=7000;
 | 
			
		||||
    static const int rcvRetryLimit = 10;
 | 
			
		||||
 | 
			
		||||
  
 | 
			
		||||
    XModem(File &f,
 | 
			
		||||
           FlowControlType commandFlow,
 | 
			
		||||
           int (*recvChar)(ZSerial *ser, int),
 | 
			
		||||
           void (*sendChar)(ZSerial *ser, char),
 | 
			
		||||
           bool (*dataHandler)(File *xfile, unsigned long, char*, int));
 | 
			
		||||
    bool receive();
 | 
			
		||||
    bool transmit();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static int xReceiveSerial(ZSerial *ser, int del)
 | 
			
		||||
{
 | 
			
		||||
  unsigned long end=micros() + (del * 1000L);
 | 
			
		||||
  while(micros() < end)
 | 
			
		||||
  {
 | 
			
		||||
    serialOutDeque();
 | 
			
		||||
    if(ser->available() > 0)
 | 
			
		||||
    {
 | 
			
		||||
      int c=ser->read();
 | 
			
		||||
      logSerialIn(c);
 | 
			
		||||
      return c;
 | 
			
		||||
    }
 | 
			
		||||
    yield();
 | 
			
		||||
  }
 | 
			
		||||
  return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void xSendSerial(ZSerial *ser, char c)
 | 
			
		||||
{
 | 
			
		||||
  ser->write((uint8_t)c);
 | 
			
		||||
  ser->flush();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool xUDataHandler(File *xfile, unsigned long number, char *buf, int sz)
 | 
			
		||||
{
 | 
			
		||||
  for(int i=0;i<sz;i++)
 | 
			
		||||
    xfile->write((uint8_t)buf[i]);
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool xDDataHandler(File *xfile, unsigned long number, char *buf, int sz)
 | 
			
		||||
{
 | 
			
		||||
  for(int i=0;i<sz;i++)
 | 
			
		||||
  {
 | 
			
		||||
    int c=xfile->read();
 | 
			
		||||
    if(c<0)
 | 
			
		||||
    {
 | 
			
		||||
      if(i==0)
 | 
			
		||||
        return false;
 | 
			
		||||
      buf[i] = (char)26;
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
      buf[i] = (char)c;
 | 
			
		||||
  }
 | 
			
		||||
  return true;  
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static boolean xDownload(FlowControlType commandFlow, File &f, String &errors)
 | 
			
		||||
{
 | 
			
		||||
  XModem xmo(f,commandFlow, xReceiveSerial, xSendSerial, xDDataHandler);
 | 
			
		||||
  bool result = xmo.transmit();
 | 
			
		||||
  return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static boolean xUpload(FlowControlType commandFlow, File &f, String &errors)
 | 
			
		||||
{
 | 
			
		||||
  XModem xmo(f,commandFlow, xReceiveSerial, xSendSerial, xUDataHandler);
 | 
			
		||||
  bool result = xmo.receive();
 | 
			
		||||
  return result;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,504 @@
 | 
			
		|||
/*
 | 
			
		||||
 * zmodem.h
 | 
			
		||||
 * zmodem constants
 | 
			
		||||
 * (C) Mattheij Computer Service 1994
 | 
			
		||||
 *
 | 
			
		||||
 *  Date: Thu, 19 Nov 2015 10:10:02 +0100
 | 
			
		||||
 *  From: Jacques Mattheij
 | 
			
		||||
 *  Subject: Re: zmodem license
 | 
			
		||||
 *  To: Stephen Hurd, Fernando Toledo
 | 
			
		||||
 *  CC: Rob Swindell
 | 
			
		||||
 *
 | 
			
		||||
 *  Hello there to all of you,
 | 
			
		||||
 *
 | 
			
		||||
 *  So, this email will then signify as the transfer of any and all rights I
 | 
			
		||||
 *  held up to this point with relation to the copyright of the zmodem
 | 
			
		||||
 *  package as released by me many years ago and all associated files to
 | 
			
		||||
 *  Stephen Hurd. Fernando Toledo and Rob Swindell are named as
 | 
			
		||||
 *  witnesses to this transfer.
 | 
			
		||||
 *
 | 
			
		||||
 *  ...
 | 
			
		||||
 *
 | 
			
		||||
 *  best regards,
 | 
			
		||||
 *
 | 
			
		||||
 *  Jacques Mattheij
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/* $Id: zmodem.h,v 1.55 2018/02/01 08:20:19 deuce Exp $ */
 | 
			
		||||
 | 
			
		||||
#ifndef _ZMODEM_H
 | 
			
		||||
#define _ZMODEM_H
 | 
			
		||||
 | 
			
		||||
#define ZMODEM_FILE_SIZE_MAX  0xffffffff  /* 32-bits, blame Chuck */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * ascii constants
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#define BOOL bool
 | 
			
		||||
#define BYTE uint8_t
 | 
			
		||||
#define uchar uint8_t
 | 
			
		||||
#define MAX_PATH 253
 | 
			
		||||
#define NOINP   -1      /* input buffer empty (incom only) */
 | 
			
		||||
#define LOG_EMERG       0       /* system is unusable */
 | 
			
		||||
#define LOG_ALERT       1       /* action must be taken immediately */
 | 
			
		||||
#define LOG_CRIT        2       /* critical conditions */
 | 
			
		||||
#define LOG_ERR         3       /* error conditions */
 | 
			
		||||
#define LOG_WARNING     4       /* warning conditions */
 | 
			
		||||
#define LOG_NOTICE      5       /* normal but significant condition */
 | 
			
		||||
#define LOG_INFO        6       /* informational */
 | 
			
		||||
#define LOG_DEBUG       7       /* debug-level messages */
 | 
			
		||||
 | 
			
		||||
#define  ZMO_DLE      0x10
 | 
			
		||||
#define  ZMO_XON      0x11
 | 
			
		||||
#define  ZMO_XOFF     0x13
 | 
			
		||||
#define  ZMO_CAN      0x18
 | 
			
		||||
 | 
			
		||||
#ifndef INT_TO_BOOL
 | 
			
		||||
#define INT_TO_BOOL(x)  ((x)?ZTRUE:ZFALSE)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define ZFALSE 0
 | 
			
		||||
#define ZTRUE 1
 | 
			
		||||
 | 
			
		||||
#define TERMINATE(str)                      str[sizeof(str)-1]=0
 | 
			
		||||
 | 
			
		||||
/* This is a bound-safe version of strcpy basically - only works with fixed-length arrays */
 | 
			
		||||
#ifdef SAFECOPY_USES_SPRINTF
 | 
			
		||||
#define SAFECOPY(dst,src)                   sprintf(dst,"%.*s",(int)sizeof(dst)-1,src)
 | 
			
		||||
#else   /* strncpy is faster */
 | 
			
		||||
#define SAFECOPY(dst,src)                   (strncpy(dst,src,sizeof(dst)), TERMINATE(dst))
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * zmodem constants
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#define ZBLOCKLEN  1024    /* "true" Zmodem max subpacket length */
 | 
			
		||||
 | 
			
		||||
#define ZMAXHLEN    0x10    /* maximum header information length */
 | 
			
		||||
#define ZMAXSPLEN   0x400    /* maximum subpacket length */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#define  ZPAD     0x2a    /* pad character; begins frames */
 | 
			
		||||
#define  ZDLE     0x18    /* ctrl-x zmodem escape */
 | 
			
		||||
#define  ZDLEE    0x58    /* escaped ZDLE */
 | 
			
		||||
 | 
			
		||||
#define  ZBIN     0x41    /* binary frame indicator (CRC16) */
 | 
			
		||||
#define  ZHEX     0x42    /* hex frame indicator */
 | 
			
		||||
#define  ZBIN32   0x43    /* binary frame indicator (CRC32) */
 | 
			
		||||
#define  ZBINR32  0x44    /* run length encoded binary frame (CRC32) */
 | 
			
		||||
 | 
			
		||||
#define  ZVBIN    0x61    /* binary frame indicator (CRC16) */
 | 
			
		||||
#define  ZVHEX    0x62    /* hex frame indicator */
 | 
			
		||||
#define  ZVBIN32  0x63    /* binary frame indicator (CRC32) */
 | 
			
		||||
#define  ZVBINR32 0x64    /* run length encoded binary frame (CRC32) */
 | 
			
		||||
 | 
			
		||||
#define  ZRESC    0x7e    /* run length encoding flag / escape character */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * zmodem frame types
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#define  ZRQINIT     0x00    /* request receive init (s->r) */
 | 
			
		||||
#define  ZRINIT      0x01    /* receive init (r->s) */
 | 
			
		||||
#define  ZSINIT      0x02    /* send init sequence (optional) (s->r) */
 | 
			
		||||
#define  ZACK        0x03    /* ack to ZRQINIT ZRINIT or ZSINIT (s<->r) */
 | 
			
		||||
#define  ZFILE       0x04    /* file name (s->r) */
 | 
			
		||||
#define  ZSKIP       0x05    /* skip this file (r->s) */
 | 
			
		||||
#define  ZNAK        0x06    /* last packet was corrupted (?) */
 | 
			
		||||
#define  ZABORT      0x07    /* abort batch transfers (?) */
 | 
			
		||||
#define  ZFIN        0x08    /* finish session (s<->r) */
 | 
			
		||||
#define  ZRPOS       0x09    /* resume data transmission here (r->s) */
 | 
			
		||||
#define  ZDATA       0x0a    /* data packet(s) follow (s->r) */
 | 
			
		||||
#define  ZEOF        0x0b    /* end of file reached (s->r) */
 | 
			
		||||
#define  ZFERR       0x0c    /* fatal read or write error detected (?) */
 | 
			
		||||
#define  ZCRC        0x0d    /* request for file CRC and response (?) */
 | 
			
		||||
#define  ZCHALLENGE  0x0e    /* security challenge (r->s) */
 | 
			
		||||
#define  ZCOMPL      0x0f    /* request is complete (?) */
 | 
			
		||||
#define  ZCAN        0x10    /* pseudo frame;
 | 
			
		||||
                   other end cancelled session with 5* CAN */
 | 
			
		||||
#define  ZFREECNT    0x11    /* request free bytes on file system (s->r) */
 | 
			
		||||
#define  ZCOMMAND    0x12    /* issue command (s->r) */
 | 
			
		||||
#define  ZSTDERR     0x13    /* output data to stderr (??) */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * ZDLE sequences
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#define  ZCRCE    0x68    /* CRC next, frame ends, header packet follows */
 | 
			
		||||
#define  ZCRCG    0x69    /* CRC next, frame continues nonstop */
 | 
			
		||||
#define  ZCRCQ    0x6a    /* CRC next, frame continuous, ZACK expected */
 | 
			
		||||
#define  ZCRCW    0x6b    /* CRC next, frame ends,       ZACK expected */
 | 
			
		||||
#define  ZRUB0    0x6c    /* translate to rubout 0x7f */
 | 
			
		||||
#define  ZRUB1    0x6d    /* translate to rubout 0xff */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * frame specific data.
 | 
			
		||||
 * entries are prefixed with their location in the header array.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Byte positions within header array
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#define FTYPE 0          /* frame type */
 | 
			
		||||
 | 
			
		||||
#define ZF0  4          /* First flags byte */
 | 
			
		||||
#define ZF1  3
 | 
			
		||||
#define ZF2  2
 | 
			
		||||
#define ZF3  1
 | 
			
		||||
 | 
			
		||||
#define ZP0  1          /* Low order 8 bits of position */
 | 
			
		||||
#define ZP1  2
 | 
			
		||||
#define ZP2  3
 | 
			
		||||
#define ZP3  4          /* High order 8 bits of file position */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * ZRINIT frame
 | 
			
		||||
 * zmodem receiver capability flags
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#define  ZF0_CANFDX    0x01  /* Receiver can send and receive true full duplex */
 | 
			
		||||
#define  ZF0_CANOVIO   0x02  /* receiver can receive data during disk I/O */
 | 
			
		||||
#define  ZF0_CANBRK    0x04  /* receiver can send a break signal */
 | 
			
		||||
#define  ZF0_CANCRY    0x08  /* Receiver can decrypt DONT USE */
 | 
			
		||||
#define  ZF0_CANLZW    0x10  /* Receiver can uncompress DONT USE */
 | 
			
		||||
#define  ZF0_CANFC32   0x20  /* Receiver can use 32 bit Frame Check */
 | 
			
		||||
#define  ZF0_ESCCTL    0x40  /* Receiver expects ctl chars to be escaped */
 | 
			
		||||
#define  ZF0_ESC8      0x80  /* Receiver expects 8th bit to be escaped */
 | 
			
		||||
 | 
			
		||||
#define ZF1_CANVHDR    0x01  /* Variable headers OK */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * ZSINIT frame
 | 
			
		||||
 * zmodem sender capability
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#define ZF0_TESCCTL   0x40  /* Transmitter expects ctl chars to be escaped */
 | 
			
		||||
#define ZF0_TESC8     0x80  /* Transmitter expects 8th bit to be escaped */
 | 
			
		||||
 | 
			
		||||
#define ZATTNLEN      0x20  /* Max length of attention string */
 | 
			
		||||
#define ALTCOFF       ZF1    /* Offset to alternate canit string, 0 if not used */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * ZFILE frame
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Conversion options one of these in ZF0
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#define ZF0_ZCBIN   1    /* Binary transfer - inhibit conversion */
 | 
			
		||||
#define ZF0_ZCNL    2    /* Convert NL to local end of line convention */
 | 
			
		||||
#define ZF0_ZCRESUM 3    /* Resume interrupted file transfer */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Management include options, one of these ored in ZF1
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#define ZF1_ZMSKNOLOC  0x80  /* Skip file if not present at rx */
 | 
			
		||||
#define ZF1_ZMMASK     0x1f  /* Mask for the choices below */
 | 
			
		||||
#define ZF1_ZMNEWL      1    /* Transfer if source newer or longer */
 | 
			
		||||
#define ZF1_ZMCRC       2    /* Transfer if different file CRC or length */
 | 
			
		||||
#define ZF1_ZMAPND      3    /* Append contents to existing file (if any) */
 | 
			
		||||
#define ZF1_ZMCLOB      4    /* Replace existing file */
 | 
			
		||||
#define ZF1_ZMNEW       5    /* Transfer if source newer */
 | 
			
		||||
#define ZF1_ZMDIFF      6    /* Transfer if dates or lengths different */
 | 
			
		||||
#define ZF1_ZMPROT      7    /* Protect destination file */
 | 
			
		||||
#define ZF1_ZMCHNG      8    /* Change filename if destination exists */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Transport options, one of these in ZF2
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#define ZF2_ZTNOR    0    /* no compression */
 | 
			
		||||
#define ZF2_ZTLZW    1    /* Lempel-Ziv compression */
 | 
			
		||||
#define ZF2_ZTRLE    3    /* Run Length encoding */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Extended options for ZF3, bit encoded
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#define ZF3_ZCANVHDR   0x01  /* Variable headers OK */
 | 
			
		||||
                             /* Receiver window size override */
 | 
			
		||||
#define ZF3_ZRWOVR     0x04  /* byte position for receive window override/256 */
 | 
			
		||||
#define ZF3_ZXSPARS    0x40  /* encoding for sparse file operations */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * ZCOMMAND frame
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#define ZF0_ZCACK1     0x01  /* Acknowledge, then do command */
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
 | 
			
		||||
  BYTE      rxd_header[ZMAXHLEN];              /* last received header */
 | 
			
		||||
  int       rxd_header_len;                  /* last received header size */
 | 
			
		||||
  uint32_t  rxd_header_pos;                  /* last received header position value */
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * receiver capability flags
 | 
			
		||||
   * extracted from the ZRINIT frame as received
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  BOOL can_full_duplex;
 | 
			
		||||
  BOOL can_overlap_io;
 | 
			
		||||
  BOOL can_break;
 | 
			
		||||
  BOOL can_fcs_32;
 | 
			
		||||
  BOOL want_fcs_16;
 | 
			
		||||
  BOOL escape_ctrl_chars;
 | 
			
		||||
  BOOL escape_8th_bit;
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * file management options.
 | 
			
		||||
   * only one should be on
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  int management_newer;
 | 
			
		||||
  int management_clobber;
 | 
			
		||||
  int management_protect;
 | 
			
		||||
 | 
			
		||||
  /* from zmtx.c */
 | 
			
		||||
 | 
			
		||||
  BYTE tx_data_subpacket[8192];
 | 
			
		||||
  BYTE rx_data_subpacket[8192];              /* zzap = 8192 */
 | 
			
		||||
 | 
			
		||||
  char       current_file_name[MAX_PATH+1];
 | 
			
		||||
  int64_t    current_file_size;
 | 
			
		||||
  int64_t    current_file_pos;
 | 
			
		||||
  time_t     current_file_time;
 | 
			
		||||
  unsigned   current_file_num;
 | 
			
		||||
  unsigned   total_files;
 | 
			
		||||
  int64_t    total_bytes;
 | 
			
		||||
  unsigned   files_remaining;
 | 
			
		||||
  int64_t    bytes_remaining;
 | 
			
		||||
  int64_t    transfer_start_pos;
 | 
			
		||||
  time_t     transfer_start_time;
 | 
			
		||||
 | 
			
		||||
  int      receive_32bit_data;
 | 
			
		||||
  int      use_crc16;
 | 
			
		||||
  int32_t  ack_file_pos;        /* file position used in acknowledgement of correctly */
 | 
			
		||||
                    /* received data subpackets */
 | 
			
		||||
 | 
			
		||||
  int last_sent;
 | 
			
		||||
 | 
			
		||||
  int n_cans;
 | 
			
		||||
 | 
			
		||||
  /* Stuff added by RRS */
 | 
			
		||||
 | 
			
		||||
  /* Status */
 | 
			
		||||
  BOOL      cancelled;
 | 
			
		||||
  BOOL      local_abort;
 | 
			
		||||
  BOOL      file_skipped;
 | 
			
		||||
  BOOL      no_streaming;
 | 
			
		||||
  BOOL      frame_in_transit;
 | 
			
		||||
  unsigned  recv_bufsize;  /* Receiver specified buffer size */
 | 
			
		||||
  int32_t   crc_request;
 | 
			
		||||
  unsigned  errors;
 | 
			
		||||
  unsigned  consecutive_errors;
 | 
			
		||||
 | 
			
		||||
  /* Configuration */
 | 
			
		||||
  BOOL      escape_telnet_iac;
 | 
			
		||||
  unsigned  init_timeout;
 | 
			
		||||
  unsigned  send_timeout;
 | 
			
		||||
  unsigned  recv_timeout;
 | 
			
		||||
  unsigned  crc_timeout;
 | 
			
		||||
  unsigned  max_errors;
 | 
			
		||||
  unsigned  block_size;
 | 
			
		||||
  unsigned  max_block_size;
 | 
			
		||||
  int64_t   max_file_size;    /* 0 = unlimited */
 | 
			
		||||
  int       *log_level;
 | 
			
		||||
  /* error C2520: conversion from unsigned __int64 to double not implemented, use signed __int64 */
 | 
			
		||||
  void*    cbdata;
 | 
			
		||||
} zmodem_t;
 | 
			
		||||
 | 
			
		||||
class ZModem
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
  ZModem(FS *zfs, void* cbdata);
 | 
			
		||||
  ~ZModem();
 | 
			
		||||
  BOOL send_file( char* name, File* fp, BOOL request_init, time_t* start, uint64_t* bytes_sent);
 | 
			
		||||
  int get_zfin();
 | 
			
		||||
  int recv_init();
 | 
			
		||||
  int lputs(void* unused, int level, const char* str);
 | 
			
		||||
  int lprintf(int level, const char *fmt, ...);
 | 
			
		||||
  int send_zabort();
 | 
			
		||||
  int send_zfin();
 | 
			
		||||
  int recv_files(const char* download_dir, uint64_t* bytes_received);
 | 
			
		||||
  unsigned recv_file_data( File*, int64_t offset);
 | 
			
		||||
  zmodem_t *zm=0;
 | 
			
		||||
  ZSerial zserial;
 | 
			
		||||
  FS *zfileSystem=0;
 | 
			
		||||
private:
 | 
			
		||||
  char* ver(char *buf);
 | 
			
		||||
  const char* source(void);
 | 
			
		||||
  int rx();
 | 
			
		||||
  int tx(BYTE ch);
 | 
			
		||||
  int send_ack( int32_t pos);
 | 
			
		||||
  int send_nak();
 | 
			
		||||
  int send_zskip();
 | 
			
		||||
  int send_zrinit();
 | 
			
		||||
  int send_pos_header(int type, int32_t pos, BOOL hex);
 | 
			
		||||
  int get_zrinit();
 | 
			
		||||
  BOOL get_crc( int32_t length, uint32_t* crc);
 | 
			
		||||
  void parse_zrinit();
 | 
			
		||||
  void parse_zfile_subpacket();
 | 
			
		||||
  int recv_file_frame(File* fp);
 | 
			
		||||
  int recv_header_and_check();
 | 
			
		||||
  int send_hex(uchar val);
 | 
			
		||||
  int send_padded_zdle();
 | 
			
		||||
  int send_hex_header(unsigned char * p);
 | 
			
		||||
  int send_bin32_header(unsigned char * p);
 | 
			
		||||
  int send_bin16_header(unsigned char * p);
 | 
			
		||||
  int send_bin_header(unsigned char * p);
 | 
			
		||||
  int send_data32(uchar subpkt_type, unsigned char * p, size_t l);
 | 
			
		||||
  int send_data16(uchar subpkt_type,unsigned char * p, size_t l);
 | 
			
		||||
  int send_data(uchar subpkt_type, unsigned char * p, size_t l);
 | 
			
		||||
  int send_data_subpkt(uchar subpkt_type, unsigned char * p, size_t l);
 | 
			
		||||
  int data_waiting(unsigned timeout);
 | 
			
		||||
  void recv_purge();
 | 
			
		||||
  void flush();
 | 
			
		||||
  int send_raw(unsigned char ch);
 | 
			
		||||
  int send_esc(unsigned char c);
 | 
			
		||||
  int recv_data32(unsigned char * p, unsigned maxlen, unsigned* l);
 | 
			
		||||
  int recv_data16(register unsigned char* p, unsigned maxlen, unsigned* l);
 | 
			
		||||
  int recv_data(unsigned char* p, size_t maxlen, unsigned* l, BOOL ack);
 | 
			
		||||
  BOOL recv_subpacket(BOOL ack);
 | 
			
		||||
  int recv_nibble();
 | 
			
		||||
  int recv_hex();
 | 
			
		||||
  int recv_raw();
 | 
			
		||||
  BOOL recv_bin16_header();
 | 
			
		||||
  BOOL recv_hex_header();
 | 
			
		||||
  BOOL recv_bin32_header();
 | 
			
		||||
  int recv_header_raw(int errors);
 | 
			
		||||
  int recv_header();
 | 
			
		||||
  BOOL request_crc(int32_t length);
 | 
			
		||||
  BOOL recv_crc(uint32_t* crc);
 | 
			
		||||
  BOOL handle_zrpos(uint64_t* pos);
 | 
			
		||||
  BOOL handle_zack();
 | 
			
		||||
  BOOL is_connected();
 | 
			
		||||
  BOOL is_cancelled();
 | 
			
		||||
  int send_from(File* fp, uint64_t pos, uint64_t* sent);
 | 
			
		||||
  int send_znak();
 | 
			
		||||
  int send_zeof(uint32_t pos);
 | 
			
		||||
  void progress(void* cbdata, int64_t current_pos);
 | 
			
		||||
  int send_byte(void* unused, uchar ch, unsigned timeout);
 | 
			
		||||
  int recv_byte(void* unused, unsigned timeout); /* seconds */
 | 
			
		||||
  ulong frame_pos(int type);
 | 
			
		||||
  char* getfname(const char* path);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static ZModem *initZSerial(FS &fs, FlowControlType commandFlow)
 | 
			
		||||
{
 | 
			
		||||
  ZModem *modem = new ZModem(&SD, NULL);
 | 
			
		||||
  modem->zserial.setFlowControlType(FCT_DISABLED);
 | 
			
		||||
  if(commandFlow==FCT_RTSCTS)
 | 
			
		||||
    modem->zserial.setFlowControlType(FCT_RTSCTS);
 | 
			
		||||
  else
 | 
			
		||||
    modem->zserial.setFlowControlType(FCT_NORMAL);
 | 
			
		||||
  modem->zserial.setPetsciiMode(false);
 | 
			
		||||
  modem->zserial.setXON(true);
 | 
			
		||||
  return modem;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static boolean zDownload(FlowControlType flow, FS &fs, String filePath, String &errors)
 | 
			
		||||
{
 | 
			
		||||
  time_t starttime = 0;
 | 
			
		||||
  uint64_t bytes_sent=0;
 | 
			
		||||
  BOOL success=ZFALSE;
 | 
			
		||||
  char filePathC[MAX_PATH];
 | 
			
		||||
  File F;
 | 
			
		||||
 | 
			
		||||
  ZModem *modem = initZSerial(fs, flow);
 | 
			
		||||
 | 
			
		||||
  //static int send_files(char** fname, uint fnames)
 | 
			
		||||
  F=modem->zfileSystem->open(filePath);
 | 
			
		||||
  modem->zm->files_remaining = 1;
 | 
			
		||||
  modem->zm->bytes_remaining = F.size();
 | 
			
		||||
  strcpy(filePathC,filePath.c_str());
 | 
			
		||||
  success=modem->send_file(filePathC, &F, ZTRUE, &starttime, &bytes_sent);
 | 
			
		||||
  if(success)
 | 
			
		||||
    modem->get_zfin();
 | 
			
		||||
  F.close();
 | 
			
		||||
 | 
			
		||||
  modem->zserial.flushAlways();
 | 
			
		||||
  delete modem;
 | 
			
		||||
  return (success==ZTRUE) && (modem->zm->cancelled==ZFALSE);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static boolean zUpload(FlowControlType flow, FS &fs, String dirPath, String &errors)
 | 
			
		||||
{
 | 
			
		||||
  BOOL success=ZFALSE;
 | 
			
		||||
  int   i;
 | 
			
		||||
  char str[MAX_PATH];
 | 
			
		||||
  File fp;
 | 
			
		||||
  int err;
 | 
			
		||||
 | 
			
		||||
  ZModem *modem = initZSerial(fs,flow);
 | 
			
		||||
 | 
			
		||||
  //static int receive_files(char** fname_list, int fnames)
 | 
			
		||||
  //TODO: loop might be necc around here, for multiple files?
 | 
			
		||||
  i=modem->recv_init();
 | 
			
		||||
  if(modem->zm->cancelled || (i<0))
 | 
			
		||||
  {
 | 
			
		||||
    delete modem;
 | 
			
		||||
    return ZFALSE;
 | 
			
		||||
  }
 | 
			
		||||
  switch(i) {
 | 
			
		||||
    case ZFILE:
 | 
			
		||||
      //SAFECOPY(fname,zm.current_file_name);
 | 
			
		||||
      //file_bytes = zm.current_file_size;
 | 
			
		||||
      //ftime = zm.current_file_time;
 | 
			
		||||
      //total_files = zm.files_remaining;
 | 
			
		||||
      //total_bytes = zm.bytes_remaining;
 | 
			
		||||
      break;
 | 
			
		||||
    case ZFIN:
 | 
			
		||||
    case ZCOMPL:
 | 
			
		||||
      delete modem;
 | 
			
		||||
      return ZTRUE; // was (!success)
 | 
			
		||||
    default:
 | 
			
		||||
      delete modem;
 | 
			
		||||
      return ZFALSE;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  strcpy(str,dirPath.c_str());
 | 
			
		||||
  if(str[strlen(str)-1]!='/')
 | 
			
		||||
  {
 | 
			
		||||
    str[strlen(str)]='/';
 | 
			
		||||
    str[strlen(str)+1]=0;
 | 
			
		||||
  }
 | 
			
		||||
  strcpy(str+strlen(str),modem->zm->current_file_name);
 | 
			
		||||
 | 
			
		||||
  fp = modem->zfileSystem->open(str,FILE_WRITE);
 | 
			
		||||
  if(!fp)
 | 
			
		||||
  {
 | 
			
		||||
    modem->lprintf(LOG_ERR,"Error %d creating %s",errno,str);
 | 
			
		||||
    modem->send_zabort();
 | 
			
		||||
    //zmodem_send_zskip(); //TODO: for when we move to multiple files
 | 
			
		||||
    //continue;
 | 
			
		||||
    delete modem;
 | 
			
		||||
    return ZFALSE;
 | 
			
		||||
  }
 | 
			
		||||
  err=modem->recv_file_data(&fp,0);
 | 
			
		||||
 | 
			
		||||
  if(err<=modem->zm->max_errors && !modem->zm->cancelled)
 | 
			
		||||
    success=ZTRUE;
 | 
			
		||||
 | 
			
		||||
  if(success)
 | 
			
		||||
    modem->send_zfin();
 | 
			
		||||
 | 
			
		||||
  fp.close();
 | 
			
		||||
  if(modem->zm->local_abort)
 | 
			
		||||
  {
 | 
			
		||||
    modem->lprintf(LOG_ERR,"Locally aborted, sending cancel to remote");
 | 
			
		||||
    modem->send_zabort();
 | 
			
		||||
    delete modem;
 | 
			
		||||
    return ZFALSE;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  modem->zserial.flushAlways();
 | 
			
		||||
  delete modem;
 | 
			
		||||
  return (success == ZTRUE);
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,174 @@
 | 
			
		|||
/*
 | 
			
		||||
   Copyright 2016-2019 Bo Zimmerman
 | 
			
		||||
 | 
			
		||||
   Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
   you may not use this file except in compliance with the License.
 | 
			
		||||
   You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
     http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
   Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
   distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
   See the License for the specific language governing permissions and
 | 
			
		||||
   limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#include <WiFiUdp.h>
 | 
			
		||||
 | 
			
		||||
static const char *TimeZones[243][2] PROGMEM = { {"UTC","0"},
 | 
			
		||||
    {"A","1"},{"CDT","10:30"},{"ACST","9:30"},{"ACT","-5"},
 | 
			
		||||
    {"ACT","9:30/10:30"},{"ACWST","8:45"},{"ADT","3"},{"ADT","-3"},
 | 
			
		||||
    {"AEDT","11"},{"AEST","10"},{"AET","11"},{"AFT","4:30"},
 | 
			
		||||
    {"AKDT","-8"},{"AKST","-9"},{"ALMT","6"},{"AMST","-3"},{"AMST","5"},
 | 
			
		||||
    {"AMT","-4"},{"AMT","4"},{"ANAST","12"},{"ANAT","12"},{"AQTT","5"},
 | 
			
		||||
    {"ART","-3"},{"AST","2"},{"AST","-4"},{"AT","-4/-3"},{"AWDT","9"},
 | 
			
		||||
    {"AWST","8"},{"AZOST","0"},{"AZOT","-1"},{"AZST","5"},{"AZT","4"},
 | 
			
		||||
    {"AOE","-12"},{"B","2"},{"BNT","8"},{"BOT","-4"},{"BRST","-2"},
 | 
			
		||||
    {"BRT","-3"},{"BST","6"},{"BST","11"},{"BST","1"},{"BTT","6"},
 | 
			
		||||
    {"C","3"},{"CAST","8"},{"CAT","2"},{"CCT","6:30"},{"CDT","-5"},
 | 
			
		||||
    {"CDT","-4"},{"CEST","2"},{"CET","1"},{"CHADT","13:45"},
 | 
			
		||||
    {"CHAST","12:45"},{"CHOST","9"},{"CHOT","8"},{"CHUT","10"},
 | 
			
		||||
    {"CIDST","-4"},{"CIST","-5"},{"CKT","-10"},{"CLST","-3"},
 | 
			
		||||
    {"CLT","-4"},{"COT","-5"},{"CST","-6"},{"CST","8"},{"CST","-5"},
 | 
			
		||||
    {"CT","-6/-5"},{"CVT","-1"},{"CXT","7"},{"ChST","10"},{"D","4"},
 | 
			
		||||
    {"DAVT","7"},{"DDUT","10"},{"E","5"},{"EASST","-5"},{"EAST","-6"},
 | 
			
		||||
    {"EAT","3"},{"ECT","-5"},{"EDT","-4"},{"EEST","3"},{"EET","2"},
 | 
			
		||||
    {"EGST","0"},{"EGT","-1"},{"EST","-5"},{"ET","-5/-4"},{"F","6"},
 | 
			
		||||
    {"FET","3"},{"FJST","13"},{"FJT","12"},{"FKST","-3"},{"FKT","-4"},
 | 
			
		||||
    {"FNT","-2"},{"G","7"},{"GALT","-6"},{"GAMT","-9"},{"GET","4"},
 | 
			
		||||
    {"GFT","-3"},{"GILT","12"},{"GMT","0"},{"GST","4"},{"GST","-2"},
 | 
			
		||||
    {"GYT","-4"},{"H","8"},{"HADT","-9"},{"HAST","-10"},{"HKT","8"},
 | 
			
		||||
    {"HOVST","8"},{"HOVT","7"},{"I","9"},{"ICT","7"},{"IDT","3"},
 | 
			
		||||
    {"IOT","6"},{"IRDT","4:30"},{"IRKST","9"},{"IRKT","8"},
 | 
			
		||||
    {"IRST","3:30"},{"IST","5:30"},{"IST","1"},{"IST","2"},{"JST","9"},
 | 
			
		||||
    {"K","10"},{"KGT","6"},{"KOST","11"},{"KRAST","8"},{"KRAT","7"},
 | 
			
		||||
    {"KST","9"},{"KUYT","4"},{"L","11"},{"LHDT","11"},{"LHST","10:30"},
 | 
			
		||||
    {"LINT","14"},{"M","12"},{"MAGST","12"},{"MAGT","11"},{"MART","-9:30"},
 | 
			
		||||
    {"MAWT","5"},{"MDT","-6"},{"MHT","12"},{"MMT","6:30"},{"MSD","4"},
 | 
			
		||||
    {"MSK","3"},{"MST","-7"},{"MT","-7/-6"},{"MUT","4"},{"MVT","5"},
 | 
			
		||||
    {"MYT","8"},{"N","-1"},{"NCT","11"},{"NDT","-2:30"},{"NFT","11"},
 | 
			
		||||
    {"NOVST","7"},{"NOVT","6"},{"NPT","5:45"},{"NRT","12"},{"NST","-3:30"},
 | 
			
		||||
    {"NUT","-11"},{"NZDT","13"},{"NZST","12"},{"O","-2"},{"OMSST","7"},
 | 
			
		||||
    {"OMST","6"},{"ORAT","5"},{"P","-3"},{"PDT","-7"},{"PET","-5"},
 | 
			
		||||
    {"PETST","12"},{"PETT","12"},{"PGT","10"},{"PHOT","13"},{"PHT","8"},
 | 
			
		||||
    {"PKT","5"},{"PMDT","-2"},{"PMST","-3"},{"PONT","11"},{"PST","-8"},
 | 
			
		||||
    {"PST","-8"},{"PT","-8/-7"},{"PWT","9"},{"PYST","-3"},{"PYT","-4"},
 | 
			
		||||
    {"PYT","8:30"},{"Q","-4"},{"QYZT","6"},{"R","-5"},{"RET","4"},
 | 
			
		||||
    {"ROTT","-3"},{"S","-6"},{"SAKT","11"},{"SAMT","4"},{"SAST","2"},
 | 
			
		||||
    {"SBT","11"},{"SCT","4"},{"SGT","8"},{"SRET","11"},{"SRT","-3"},
 | 
			
		||||
    {"SST","-11"},{"SYOT","3"},{"T","-7"},{"TAHT","-10"},{"TFT","5"},
 | 
			
		||||
    {"TJT","5"},{"TKT","13"},{"TLT","9"},{"TMT","5"},{"TOST","14"},
 | 
			
		||||
    {"TOT","13"},{"TRT","3"},{"TVT","12"},{"U","-8"},{"ULAST","9"},
 | 
			
		||||
    {"ULAT","8"},{"UYST","-2"},{"UYT","-3"},{"UZT","5"},
 | 
			
		||||
    {"V","-9"},{"VET","-4"},{"VLAST","11"},{"VLAT","10"},{"VOST","6"},
 | 
			
		||||
    {"VUT","11"},{"W","-10"},{"WAKT","12"},{"WARST","-3"},{"WAST","2"},
 | 
			
		||||
    {"WAT","1"},{"WEST","1"},{"WET","0"},{"WFT","12"},{"WGST","-2"},
 | 
			
		||||
    {"WGT","-3"},{"WIB","7"},{"WIT","9"},{"WITA","8"},{"WST","14"},
 | 
			
		||||
    {"WST","1"},{"WT","0"},{"X","-11"},{"Y","-12"},{"YAKST","10"},
 | 
			
		||||
    {"YAKT","9"},{"YAPT","10"},{"YEKST","6"},{"YEKT","5"},{"Z","0"}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class DateTimeClock
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
  DateTimeClock(uint32_t epochSecs);
 | 
			
		||||
  DateTimeClock();
 | 
			
		||||
  DateTimeClock(int year, int month, int day, int hour, int min, int sec, int millis);
 | 
			
		||||
protected:
 | 
			
		||||
  uint16_t year=0;
 | 
			
		||||
  uint8_t month=0;
 | 
			
		||||
  uint8_t day=0;
 | 
			
		||||
  uint8_t hour=0;
 | 
			
		||||
  uint8_t min=0;
 | 
			
		||||
  uint8_t sec=0;
 | 
			
		||||
  uint16_t milsec=0;
 | 
			
		||||
  char str[55];
 | 
			
		||||
 | 
			
		||||
  bool isLeapYear();
 | 
			
		||||
  uint8_t getDaysInThisMonth();
 | 
			
		||||
public:
 | 
			
		||||
  int getYear();
 | 
			
		||||
  void setYear(int y);
 | 
			
		||||
  void addYear(uint32_t y);
 | 
			
		||||
  int getMonth();
 | 
			
		||||
  void setMonth(int m);
 | 
			
		||||
  void addMonth(uint32_t m);
 | 
			
		||||
  int getDay();
 | 
			
		||||
  void setDay(int d);
 | 
			
		||||
  void addDay(uint32_t d);
 | 
			
		||||
  int getHour();
 | 
			
		||||
  void setHour(int h);
 | 
			
		||||
  void addHour(uint32_t h);
 | 
			
		||||
  int getMinute();
 | 
			
		||||
  void setMinute(int mm);
 | 
			
		||||
  void addMinute(uint32_t mm);
 | 
			
		||||
  int getSecond();
 | 
			
		||||
  void setSecond(int s);
 | 
			
		||||
  void addSecond(uint32_t s);
 | 
			
		||||
  int getMillis();;
 | 
			
		||||
  void setMillis(int s);
 | 
			
		||||
  void addMillis(uint64_t s);
 | 
			
		||||
 | 
			
		||||
  void setByUnixEpoch(uint32_t unisex);
 | 
			
		||||
  uint32_t getUnixEpoch();
 | 
			
		||||
 | 
			
		||||
  int getDoWNumber();
 | 
			
		||||
  const char *getDoW();
 | 
			
		||||
 | 
			
		||||
  bool isInStandardTime();
 | 
			
		||||
  bool isInDaylightSavingsTime();
 | 
			
		||||
 | 
			
		||||
  void setTime(DateTimeClock &clock);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class RealTimeClock : DateTimeClock
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
  RealTimeClock(uint32_t epochSecs);
 | 
			
		||||
  RealTimeClock();
 | 
			
		||||
  RealTimeClock(int year, int month, int day, int hour, int min, int sec, int millis);
 | 
			
		||||
 | 
			
		||||
  void tick();
 | 
			
		||||
 | 
			
		||||
  bool isTimeSet();
 | 
			
		||||
 | 
			
		||||
  bool reset();
 | 
			
		||||
 | 
			
		||||
  int getTimeZoneCode();
 | 
			
		||||
  void setTimeZoneCode(int val);
 | 
			
		||||
  bool setTimeZone(String str);
 | 
			
		||||
 | 
			
		||||
  String getFormat();
 | 
			
		||||
  void setFormat(String fmt);
 | 
			
		||||
 | 
			
		||||
  String getNtpServerHost();
 | 
			
		||||
  void setNtpServerHost(String newHost);
 | 
			
		||||
 | 
			
		||||
  bool isDisabled();
 | 
			
		||||
  void setDisabled(bool tf);
 | 
			
		||||
 | 
			
		||||
  void forceUpdate();
 | 
			
		||||
 | 
			
		||||
  DateTimeClock &getCurrentTime();
 | 
			
		||||
  String getCurrentTimeFormatted();
 | 
			
		||||
 | 
			
		||||
  // should be private
 | 
			
		||||
private:
 | 
			
		||||
  bool disabled = false;
 | 
			
		||||
  DateTimeClock adjClock;
 | 
			
		||||
  WiFiUDP udp;
 | 
			
		||||
  bool udpStarted = false;
 | 
			
		||||
  uint32_t lastMillis = 0;
 | 
			
		||||
  uint32_t nextNTPMillis = 0;
 | 
			
		||||
  int32_t ntpPeriodMillis = 60 * 1000; // every minute
 | 
			
		||||
  int32_t ntpPeriodLongMillis = 5 * 60 * 60 * 1000; // every 5 hours
 | 
			
		||||
  uint8_t tzCode = 0;
 | 
			
		||||
  String format="%M/%d/%yyyy %h:%mm:%ss%aa %z";
 | 
			
		||||
  String ntpServerName = "time.nist.gov";
 | 
			
		||||
 | 
			
		||||
  void startUdp();
 | 
			
		||||
  bool sendTimeRequest();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,91 @@
 | 
			
		|||
/*
 | 
			
		||||
   Copyright 2016-2019 Bo Zimmerman
 | 
			
		||||
 | 
			
		||||
   Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
   you may not use this file except in compliance with the License.
 | 
			
		||||
   You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
     http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
   Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
   distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
   See the License for the specific language governing permissions and
 | 
			
		||||
   limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
#ifndef ZHEADER_SEROUT_H
 | 
			
		||||
#define ZHEADER_SEROUT_H
 | 
			
		||||
 | 
			
		||||
#define DBG_BYT_CTR 20
 | 
			
		||||
 | 
			
		||||
#define SER_WRITE_BUFSIZE 4096
 | 
			
		||||
 | 
			
		||||
enum FlowControlType
 | 
			
		||||
{
 | 
			
		||||
  FCT_RTSCTS=0,
 | 
			
		||||
  FCT_NORMAL=1,
 | 
			
		||||
  FCT_AUTOOFF=2,
 | 
			
		||||
  FCT_MANUAL=3,
 | 
			
		||||
  FCT_DISABLED=4,
 | 
			
		||||
  FCT_INVALID=5
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static bool enableRtsCts = true;
 | 
			
		||||
#ifdef ZIMODEM_ESP32
 | 
			
		||||
#  define SER_BUFSIZE 0x7F
 | 
			
		||||
#else
 | 
			
		||||
#  define SER_BUFSIZE 128
 | 
			
		||||
#endif
 | 
			
		||||
static uint8_t TBUF[SER_WRITE_BUFSIZE];
 | 
			
		||||
static char FBUF[256];
 | 
			
		||||
static int TBUFhead=0;
 | 
			
		||||
static int TBUFtail=0;
 | 
			
		||||
static int serialDelayMs = 0;
 | 
			
		||||
 | 
			
		||||
static void serialDirectWrite(uint8_t c);
 | 
			
		||||
static void serialOutDeque();
 | 
			
		||||
static int serialOutBufferBytesRemaining();
 | 
			
		||||
static void clearSerialOutBuffer();
 | 
			
		||||
 | 
			
		||||
class ZSerial : public Stream
 | 
			
		||||
{
 | 
			
		||||
  private:
 | 
			
		||||
    bool petsciiMode = false;
 | 
			
		||||
    FlowControlType flowControlType=DEFAULT_FCT;
 | 
			
		||||
    bool XON_STATE=true;
 | 
			
		||||
    void enqueByte(uint8_t c);
 | 
			
		||||
  public:
 | 
			
		||||
    ZSerial();
 | 
			
		||||
    void setPetsciiMode(bool petscii);
 | 
			
		||||
    bool isPetsciiMode();
 | 
			
		||||
    void setFlowControlType(FlowControlType type);
 | 
			
		||||
    FlowControlType getFlowControlType();
 | 
			
		||||
    void setXON(bool isXON);
 | 
			
		||||
    bool isXON();
 | 
			
		||||
    bool isSerialOut();
 | 
			
		||||
    bool isSerialHalted();
 | 
			
		||||
    bool isSerialCancelled();
 | 
			
		||||
    bool isPacketOut();
 | 
			
		||||
    int getConfigFlagBitmap();
 | 
			
		||||
    
 | 
			
		||||
    void prints(String str);
 | 
			
		||||
    void prints(const char *expr);
 | 
			
		||||
    void printc(const char c);
 | 
			
		||||
    void printc(uint8_t c);
 | 
			
		||||
    virtual size_t write(uint8_t c);
 | 
			
		||||
    size_t write(uint8_t *buf, int bufSz);
 | 
			
		||||
    void printb(uint8_t c);
 | 
			
		||||
    void printd(double f);
 | 
			
		||||
    void printi(int i);
 | 
			
		||||
    void printf(const char* format, ...);
 | 
			
		||||
    void flush();
 | 
			
		||||
    void flushAlways();
 | 
			
		||||
    int availableForWrite();
 | 
			
		||||
    char drainForXonXoff();
 | 
			
		||||
 | 
			
		||||
    virtual int available();
 | 
			
		||||
    virtual int read();
 | 
			
		||||
    virtual int peek();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,27 @@
 | 
			
		|||
#ifndef _STRING_STREAM_H_INCLUDED_
 | 
			
		||||
#define _STRING_STREAM_H_INCLUDED_
 | 
			
		||||
 | 
			
		||||
class StringStream : public Stream
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    StringStream(const String &s)
 | 
			
		||||
    {
 | 
			
		||||
      str = s;
 | 
			
		||||
      position = 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Stream methods
 | 
			
		||||
    virtual int available() { return str.length() - position; }
 | 
			
		||||
    virtual int read() { return position < str.length() ? str[position++] : -1; }
 | 
			
		||||
    virtual int peek() { return position < str.length() ? str[position] : -1; }
 | 
			
		||||
    virtual void flush() { };
 | 
			
		||||
    // Print methods
 | 
			
		||||
    virtual size_t write(uint8_t c) { str += (char)c; return 1;};
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    String str;
 | 
			
		||||
    int length;
 | 
			
		||||
    int position;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif // _STRING_STREAM_H_INCLUDED_
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,123 @@
 | 
			
		|||
/*
 | 
			
		||||
   Copyright 2016-2019 Bo Zimmerman
 | 
			
		||||
 | 
			
		||||
   Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
   you may not use this file except in compliance with the License.
 | 
			
		||||
   You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
	   http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
   Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
   distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
   See the License for the specific language governing permissions and
 | 
			
		||||
   limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#define PACKET_BUF_SIZE 256
 | 
			
		||||
 | 
			
		||||
#ifdef ZIMODEM_ESP32
 | 
			
		||||
# include <WiFiClientSecure.h>
 | 
			
		||||
#endif
 | 
			
		||||
#ifdef INCLUDE_SSH
 | 
			
		||||
# include "wifisshclient.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static WiFiClient *createWiFiClient(bool SSL)
 | 
			
		||||
{
 | 
			
		||||
#ifdef ZIMODEM_ESP32
 | 
			
		||||
  if(SSL)
 | 
			
		||||
  {
 | 
			
		||||
    WiFiClientSecure *c = new WiFiClientSecure();
 | 
			
		||||
    c->setInsecure();
 | 
			
		||||
    return c;
 | 
			
		||||
  }
 | 
			
		||||
  else
 | 
			
		||||
#else
 | 
			
		||||
  //WiFiClientSecure *c = new WiFiClientSecure();
 | 
			
		||||
  //c->setInsecure();
 | 
			
		||||
#endif
 | 
			
		||||
  return new WiFiClient();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
typedef struct Packet
 | 
			
		||||
{
 | 
			
		||||
  uint8_t num = 0;
 | 
			
		||||
  uint16_t len = 0;
 | 
			
		||||
  uint8_t buf[PACKET_BUF_SIZE] = {0};
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class WiFiClientNode : public Stream
 | 
			
		||||
{
 | 
			
		||||
  private:
 | 
			
		||||
    void finishConnectionLink();
 | 
			
		||||
    int flushOverflowBuffer();
 | 
			
		||||
    void fillUnderflowBuf();
 | 
			
		||||
    WiFiClient client;
 | 
			
		||||
    WiFiClient *clientPtr;
 | 
			
		||||
    bool answered=true;
 | 
			
		||||
    int ringsRemain=0;
 | 
			
		||||
    unsigned long nextRingMillis = 0;
 | 
			
		||||
    unsigned long nextDisconnect = 0;
 | 
			
		||||
    void constructNode();
 | 
			
		||||
    void constructNode(char *hostIp, int newport, int flagsBitmap, int ringDelay);
 | 
			
		||||
    void constructNode(char *hostIp, int newport, char *username, char *password, int flagsBitmap, int ringDelay);
 | 
			
		||||
 | 
			
		||||
  public:
 | 
			
		||||
    int id=0;
 | 
			
		||||
    char *host;
 | 
			
		||||
    int port;
 | 
			
		||||
    bool wasConnected=false;
 | 
			
		||||
    bool serverClient=false;
 | 
			
		||||
    int flagsBitmap = 0;
 | 
			
		||||
    char *delimiters = NULL;
 | 
			
		||||
    char *maskOuts = NULL;
 | 
			
		||||
    char *stateMachine = NULL;
 | 
			
		||||
    char *machineState = NULL;
 | 
			
		||||
    String machineQue = "";
 | 
			
		||||
 | 
			
		||||
    uint8_t nextPacketNum=1;
 | 
			
		||||
    uint8_t blankPackets=0;
 | 
			
		||||
    struct Packet lastPacket[3]; // 0 = current buf, 1&2 are back-cache bufs
 | 
			
		||||
    //struct Packet underflowBuf; // underflows no longer handled this way
 | 
			
		||||
    WiFiClientNode *next = null;
 | 
			
		||||
 | 
			
		||||
    WiFiClientNode(char *hostIp, int newport, int flagsBitmap);
 | 
			
		||||
    WiFiClientNode(char *hostIp, int newport, char *username, char *password, int flagsBitmap);
 | 
			
		||||
    WiFiClientNode(WiFiClient newClient, int flagsBitmap, int ringDelay);
 | 
			
		||||
    ~WiFiClientNode();
 | 
			
		||||
    bool isConnected();
 | 
			
		||||
 | 
			
		||||
    FlowControlType getFlowControl();
 | 
			
		||||
    bool isPETSCII();
 | 
			
		||||
    bool isEcho();
 | 
			
		||||
    bool isTelnet();
 | 
			
		||||
 | 
			
		||||
    bool isAnswered();
 | 
			
		||||
    void answer();
 | 
			
		||||
    int ringsRemaining(int delta);
 | 
			
		||||
    unsigned long nextRingTime(long delta);
 | 
			
		||||
    void markForDisconnect();
 | 
			
		||||
    bool isMarkedForDisconnect();
 | 
			
		||||
 | 
			
		||||
    bool isDisconnectedOnStreamExit();
 | 
			
		||||
    void setDisconnectOnStreamExit(bool tf);
 | 
			
		||||
 | 
			
		||||
    void setNoDelay(bool tf);
 | 
			
		||||
 | 
			
		||||
    size_t write(uint8_t c);
 | 
			
		||||
    size_t write(const uint8_t *buf, size_t size);
 | 
			
		||||
    void print(String s);
 | 
			
		||||
    int read();
 | 
			
		||||
    int peek();
 | 
			
		||||
    void flush();
 | 
			
		||||
    void flushAlways();
 | 
			
		||||
    int available();
 | 
			
		||||
    int read(uint8_t *buf, size_t size);
 | 
			
		||||
    String readLine(unsigned int timeout);
 | 
			
		||||
 | 
			
		||||
    static int getNumOpenWiFiConnections();
 | 
			
		||||
    static void checkForAutoDisconnections();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,52 @@
 | 
			
		|||
/*
 | 
			
		||||
   Copyright 2016-2019 Bo Zimmerman
 | 
			
		||||
 | 
			
		||||
   Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
   you may not use this file except in compliance with the License.
 | 
			
		||||
   You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
	   http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
   Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
   distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
   See the License for the specific language governing permissions and
 | 
			
		||||
   limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
static int WiFiNextClientId = 0;
 | 
			
		||||
 | 
			
		||||
class WiFiServerSpec
 | 
			
		||||
{
 | 
			
		||||
  public:
 | 
			
		||||
    int port;
 | 
			
		||||
    int id;
 | 
			
		||||
    int flagsBitmap = 0;
 | 
			
		||||
    char *delimiters = NULL;
 | 
			
		||||
    char *maskOuts = NULL;
 | 
			
		||||
    char *stateMachine = NULL;
 | 
			
		||||
 | 
			
		||||
    WiFiServerSpec();
 | 
			
		||||
    WiFiServerSpec(WiFiServerSpec ©);
 | 
			
		||||
    ~WiFiServerSpec();
 | 
			
		||||
 | 
			
		||||
    WiFiServerSpec& operator=(const WiFiServerSpec&);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class WiFiServerNode : public WiFiServerSpec
 | 
			
		||||
{
 | 
			
		||||
  public:
 | 
			
		||||
    WiFiServer *server;
 | 
			
		||||
    WiFiServerNode *next = null;
 | 
			
		||||
 | 
			
		||||
    WiFiServerNode(int port, int flagsBitmap);
 | 
			
		||||
    bool hasClient();
 | 
			
		||||
    ~WiFiServerNode();
 | 
			
		||||
 | 
			
		||||
    static WiFiServerNode *FindServer(int port);
 | 
			
		||||
    static void DestroyAllServers();
 | 
			
		||||
    static bool ReadWiFiServer(File &f, WiFiServerSpec &node);
 | 
			
		||||
    static void SaveWiFiServers();
 | 
			
		||||
    static void RestoreWiFiServers();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,79 @@
 | 
			
		|||
#ifdef INCLUDE_SSH
 | 
			
		||||
/*
 | 
			
		||||
   Copyright 2023-2023 Bo Zimmerman
 | 
			
		||||
 | 
			
		||||
   Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
   you may not use this file except in compliance with the License.
 | 
			
		||||
   You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
     http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
   Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
   distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
   See the License for the specific language governing permissions and
 | 
			
		||||
   limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
#include "Arduino.h"
 | 
			
		||||
#include "IPAddress.h"
 | 
			
		||||
#include <WiFi.h>
 | 
			
		||||
#include "src/libssh2/libssh2_config.h"
 | 
			
		||||
#include "src/libssh2/libssh2.h"
 | 
			
		||||
 | 
			
		||||
class WiFiSSHClient : public WiFiClient
 | 
			
		||||
{
 | 
			
		||||
protected:
 | 
			
		||||
  String _username = "";
 | 
			
		||||
  String _password = "";
 | 
			
		||||
  libssh2_socket_t sock = null;
 | 
			
		||||
  LIBSSH2_SESSION *session = null;
 | 
			
		||||
  LIBSSH2_CHANNEL *channel = null;
 | 
			
		||||
  static const size_t INTERNAL_BUF_SIZE = 1024;
 | 
			
		||||
  size_t ibufSz = 0;
 | 
			
		||||
  char ibuf[INTERNAL_BUF_SIZE];
 | 
			
		||||
 | 
			
		||||
  bool finishLogin();
 | 
			
		||||
  void closeSSH();
 | 
			
		||||
  void intern_buffer_fill();
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    WiFiSSHClient();
 | 
			
		||||
    ~WiFiSSHClient();
 | 
			
		||||
    int connect(IPAddress ip, uint16_t port) override;
 | 
			
		||||
    int connect(IPAddress ip, uint16_t port, int32_t timeout_ms) override;
 | 
			
		||||
    int connect(const char *host, uint16_t port) override;
 | 
			
		||||
    int connect(const char *host, uint16_t port, int32_t timeout_ms) override;
 | 
			
		||||
    void setLogin(String username, String password);
 | 
			
		||||
    int peek() override;
 | 
			
		||||
    size_t write(uint8_t data) override;
 | 
			
		||||
    size_t write(const uint8_t *buf, size_t size) override;
 | 
			
		||||
    int available() override;
 | 
			
		||||
    int read() override;
 | 
			
		||||
    int read(uint8_t *buf, size_t size) override;
 | 
			
		||||
    void flush() {}
 | 
			
		||||
    void stop() override;
 | 
			
		||||
    uint8_t connected() override;
 | 
			
		||||
    int fd() const override;
 | 
			
		||||
 | 
			
		||||
    operator bool()
 | 
			
		||||
    {
 | 
			
		||||
        return connected();
 | 
			
		||||
    }
 | 
			
		||||
    WiFiSSHClient &operator=(const WiFiSSHClient &other);
 | 
			
		||||
    bool operator==(const bool value)
 | 
			
		||||
    {
 | 
			
		||||
        return bool() == value;
 | 
			
		||||
    }
 | 
			
		||||
    bool operator!=(const bool value)
 | 
			
		||||
    {
 | 
			
		||||
        return bool() != value;
 | 
			
		||||
    }
 | 
			
		||||
    bool operator==(const WiFiSSHClient &);
 | 
			
		||||
    bool operator!=(const WiFiSSHClient &rhs)
 | 
			
		||||
    {
 | 
			
		||||
        return !this->operator==(rhs);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
};
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,61 @@
 | 
			
		|||
/*
 | 
			
		||||
   Copyright 2016-2019 Bo Zimmerman
 | 
			
		||||
 | 
			
		||||
   Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
   you may not use this file except in compliance with the License.
 | 
			
		||||
   You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
     http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
   Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
   distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
   See the License for the specific language governing permissions and
 | 
			
		||||
   limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#ifdef INCLUDE_SD_SHELL
 | 
			
		||||
class ZBrowser : public ZMode
 | 
			
		||||
{
 | 
			
		||||
  private:
 | 
			
		||||
    enum ZBrowseState
 | 
			
		||||
    {
 | 
			
		||||
      ZBROW_MAIN=0,
 | 
			
		||||
    } currState;
 | 
			
		||||
    
 | 
			
		||||
    ZSerial serial;
 | 
			
		||||
 | 
			
		||||
    void switchBackToCommandMode();
 | 
			
		||||
    String makePath(String addendum);
 | 
			
		||||
    String fixPathNoSlash(String path);
 | 
			
		||||
    String stripDir(String path);
 | 
			
		||||
    String stripFilename(String path);
 | 
			
		||||
    String stripArgs(String line, String &argLetters);
 | 
			
		||||
    String cleanOneArg(String line);
 | 
			
		||||
    String cleanFirstArg(String line);
 | 
			
		||||
    String cleanRemainArg(String line);
 | 
			
		||||
    bool isMask(String mask);
 | 
			
		||||
    bool matches(String fname, String mask);
 | 
			
		||||
    void makeFileList(String ***l, int *n, String p, String mask, bool recurse);
 | 
			
		||||
    void deleteFile(String fname, String mask, bool recurse);
 | 
			
		||||
    void showDirectory(String path, String mask, String prefix, bool recurse);
 | 
			
		||||
    void copyFiles(String source, String mask, String target, bool recurse, bool overwrite);
 | 
			
		||||
    
 | 
			
		||||
    FTPHost *ftpHost = 0;
 | 
			
		||||
    bool showMenu;
 | 
			
		||||
    bool savedEcho;
 | 
			
		||||
    String path="/";
 | 
			
		||||
    String EOLN;
 | 
			
		||||
    char EOLNC[5];
 | 
			
		||||
    unsigned long lastNumber;
 | 
			
		||||
    String lastString;
 | 
			
		||||
 | 
			
		||||
  public:
 | 
			
		||||
    ~ZBrowser();
 | 
			
		||||
    void switchTo();
 | 
			
		||||
    void serialIncoming();
 | 
			
		||||
    void loop();
 | 
			
		||||
    void init();
 | 
			
		||||
    void doModeCommand(String &line);
 | 
			
		||||
};
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,202 @@
 | 
			
		|||
/*
 | 
			
		||||
   Copyright 2016-2019 Bo Zimmerman
 | 
			
		||||
 | 
			
		||||
   Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
   you may not use this file except in compliance with the License.
 | 
			
		||||
   You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
	   http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
   Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
   distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
   See the License for the specific language governing permissions and
 | 
			
		||||
   limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
const int MAX_COMMAND_SIZE=256;
 | 
			
		||||
static const char *CONFIG_FILE_OLD = "/zconfig.txt";
 | 
			
		||||
static const char *CONFIG_FILE     = "/zconfig_v2.txt";
 | 
			
		||||
#define ZI_STATE_MACHINE_LEN 7
 | 
			
		||||
#define DEFAULT_TERMTYPE "Zimodem"
 | 
			
		||||
#define DEFAULT_BUSYMSG "\r\nBUSY\r\n7\r\n"
 | 
			
		||||
 | 
			
		||||
static void parseHostInfo(uint8_t *vbuf, char **hostIp, int *port, char **username, char **password);
 | 
			
		||||
static bool validateHostInfo(uint8_t *vbuf);
 | 
			
		||||
 | 
			
		||||
enum ZResult
 | 
			
		||||
{
 | 
			
		||||
  ZOK,
 | 
			
		||||
  ZERROR,
 | 
			
		||||
  ZCONNECT,
 | 
			
		||||
  ZNOCARRIER,
 | 
			
		||||
  ZNOANSWER,
 | 
			
		||||
  ZIGNORE,
 | 
			
		||||
  ZIGNORE_SPECIAL
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum ConfigOptions
 | 
			
		||||
{
 | 
			
		||||
  CFG_WIFISSI=0,
 | 
			
		||||
  CFG_WIFIPW=1,
 | 
			
		||||
  CFG_BAUDRATE=2,
 | 
			
		||||
  CFG_EOLN=3,
 | 
			
		||||
  CFG_FLOWCONTROL=4,
 | 
			
		||||
  CFG_ECHO=5,
 | 
			
		||||
  CFG_RESP_SUPP=6,
 | 
			
		||||
  CFG_RESP_NUM=7,
 | 
			
		||||
  CFG_RESP_LONG=8,
 | 
			
		||||
  CFG_PETSCIIMODE=9,
 | 
			
		||||
  CFG_DCDMODE=10,
 | 
			
		||||
  CFG_UART=11,
 | 
			
		||||
  CFG_CTSMODE=12,
 | 
			
		||||
  CFG_RTSMODE=13,
 | 
			
		||||
  CFG_DCDPIN=14,
 | 
			
		||||
  CFG_CTSPIN=15,
 | 
			
		||||
  CFG_RTSPIN=16,
 | 
			
		||||
  CFG_S0_RINGS=17,
 | 
			
		||||
  CFG_S41_STREAM=18,
 | 
			
		||||
  CFG_S60_LISTEN=19,
 | 
			
		||||
  CFG_RIMODE=20,
 | 
			
		||||
  CFG_DTRMODE=21,
 | 
			
		||||
  CFG_DSRMODE=22,
 | 
			
		||||
  CFG_RIPIN=23,
 | 
			
		||||
  CFG_DTRPIN=24,
 | 
			
		||||
  CFG_DSRPIN=25,
 | 
			
		||||
  CFG_TIMEZONE=26,
 | 
			
		||||
  CFG_TIMEFMT=27,
 | 
			
		||||
  CFG_TIMEURL=28,
 | 
			
		||||
  CFG_HOSTNAME=29,
 | 
			
		||||
  CFG_PRINTDELAYMS=30,
 | 
			
		||||
  CFG_PRINTSPEC=31,
 | 
			
		||||
  CFG_TERMTYPE=32,
 | 
			
		||||
  CFG_STATIC_IP=33,
 | 
			
		||||
  CFG_STATIC_DNS=34,
 | 
			
		||||
  CFG_STATIC_GW=35,
 | 
			
		||||
  CFG_STATIC_SN=36,
 | 
			
		||||
  CFG_BUSYMSG=37,
 | 
			
		||||
  CFG_S62_TELNET=38,
 | 
			
		||||
  CFG_LAST=38
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const ConfigOptions v2HexCfgs[] = { CFG_WIFISSI, CFG_WIFIPW, CFG_TIMEZONE, CFG_TIMEFMT, CFG_TIMEURL,
 | 
			
		||||
    CFG_PRINTSPEC, CFG_BUSYMSG, CFG_HOSTNAME, CFG_TERMTYPE, (ConfigOptions)255 };
 | 
			
		||||
 | 
			
		||||
enum BinType
 | 
			
		||||
{
 | 
			
		||||
  BTYPE_NORMAL=0,
 | 
			
		||||
  BTYPE_HEX=1,
 | 
			
		||||
  BTYPE_DEC=2,
 | 
			
		||||
  BTYPE_NORMAL_NOCHK=3,
 | 
			
		||||
  BTYPE_NORMAL_PLUS=4,
 | 
			
		||||
  BTYPE_HEX_PLUS=5,
 | 
			
		||||
  BTYPE_DEC_PLUS=6,
 | 
			
		||||
  BTYPE_INVALID=7
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class ZCommand : public ZMode
 | 
			
		||||
{
 | 
			
		||||
  friend class WiFiClientNode;
 | 
			
		||||
  friend class ZConfig;
 | 
			
		||||
  friend class ZBrowser;
 | 
			
		||||
#ifdef INCLUDE_IRCC
 | 
			
		||||
  friend class ZIRCMode;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
  private:
 | 
			
		||||
    char CRLF[4];
 | 
			
		||||
    char LFCR[4];
 | 
			
		||||
    char LF[2];
 | 
			
		||||
    char CR[2];
 | 
			
		||||
    char BS=8;
 | 
			
		||||
    char ringCounter = 1;
 | 
			
		||||
 | 
			
		||||
    ZSerial serial;
 | 
			
		||||
    bool packetXOn = true;
 | 
			
		||||
    BinType binType = BTYPE_NORMAL;
 | 
			
		||||
    uint8_t nbuf[MAX_COMMAND_SIZE];
 | 
			
		||||
    char hbuf[MAX_COMMAND_SIZE];
 | 
			
		||||
    int eon=0;
 | 
			
		||||
    int lastServerClientId = 0;
 | 
			
		||||
    WiFiClientNode *current = null;
 | 
			
		||||
    bool autoStreamMode=false;
 | 
			
		||||
    bool telnetSupport=true;
 | 
			
		||||
    bool preserveListeners=false;
 | 
			
		||||
    unsigned long lastNonPlusTimeMs = 0;
 | 
			
		||||
    unsigned long currentExpiresTimeMs = 0;
 | 
			
		||||
    char *tempDelimiters = NULL;
 | 
			
		||||
    char *tempMaskOuts = NULL;
 | 
			
		||||
    char *tempStateMachine = NULL;
 | 
			
		||||
    char *delimiters = NULL;
 | 
			
		||||
    char *maskOuts = NULL;
 | 
			
		||||
    char *stateMachine = NULL;
 | 
			
		||||
    char *machineState = NULL;
 | 
			
		||||
    String machineQue = "";
 | 
			
		||||
    String previousCommand = "";
 | 
			
		||||
    WiFiClientNode *nextConn=null;
 | 
			
		||||
    int lastPacketId = -1;
 | 
			
		||||
 | 
			
		||||
    byte CRC8(const byte *data, byte len);
 | 
			
		||||
 | 
			
		||||
    void showInitMessage();
 | 
			
		||||
    bool readSerialStream();
 | 
			
		||||
    void clearPlusProgress();
 | 
			
		||||
    bool checkPlusEscape();
 | 
			
		||||
    String getNextSerialCommand();
 | 
			
		||||
    ZResult doSerialCommand();
 | 
			
		||||
    void setConfigDefaults();
 | 
			
		||||
    void parseConfigOptions(String configArguments[]);
 | 
			
		||||
    void setOptionsFromSavedConfig(String configArguments[]);
 | 
			
		||||
    void reSaveConfig();
 | 
			
		||||
    void reSendLastPacket(WiFiClientNode *conn, uint8_t which);
 | 
			
		||||
    void acceptNewConnection();
 | 
			
		||||
    void headerOut(const int channel, const int num, const int sz, const int crc8);
 | 
			
		||||
    void sendConnectionNotice(int nodeId);
 | 
			
		||||
    void sendNextPacket();
 | 
			
		||||
    void connectionArgs(WiFiClientNode *c);
 | 
			
		||||
    void updateAutoAnswer();
 | 
			
		||||
    uint8_t *doStateMachine(uint8_t *buf, uint16_t *bufLen, char **machineState, String *machineQue, char *stateMachine);
 | 
			
		||||
    uint8_t *doMaskOuts(uint8_t *buf, uint16_t *bufLen, char *maskOuts);
 | 
			
		||||
    ZResult doWebDump(Stream *in, int len, const bool cacheFlag);
 | 
			
		||||
    ZResult doWebDump(const char *filename, const bool cache);
 | 
			
		||||
 | 
			
		||||
    ZResult doResetCommand();
 | 
			
		||||
    ZResult doNoListenCommand();
 | 
			
		||||
    ZResult doBaudCommand(int vval, uint8_t *vbuf, int vlen);
 | 
			
		||||
    ZResult doTransmitCommand(int vval, uint8_t *vbuf, int vlen, bool isNumber, const char *dmodifiers, int *crc8);
 | 
			
		||||
    ZResult doLastPacket(int vval, uint8_t *vbuf, int vlen, bool isNumber);
 | 
			
		||||
    ZResult doConnectCommand(int vval, uint8_t *vbuf, int vlen, bool isNumber, const char *dmodifiers);
 | 
			
		||||
    ZResult doWiFiCommand(int vval, uint8_t *vbuf, int vlen, bool isNumber, const char *dmodifiers);
 | 
			
		||||
    ZResult doDialStreamCommand(unsigned long vval, uint8_t *vbuf, int vlen, bool isNumber, const char *dmodifiers);
 | 
			
		||||
    ZResult doPhonebookCommand(unsigned long vval, uint8_t *vbuf, int vlen, bool isNumber, const char *dmodifiers);
 | 
			
		||||
    ZResult doAnswerCommand(int vval, uint8_t *vbuf, int vlen, bool isNumber, const char *dmodifiers);
 | 
			
		||||
    ZResult doHangupCommand(int vval, uint8_t *vbuf, int vlen, bool isNumber);
 | 
			
		||||
    ZResult doEOLNCommand(int vval, uint8_t *vbuf, int vlen, bool isNumber);
 | 
			
		||||
    ZResult doInfoCommand(int vval, uint8_t *vbuf, int vlen, bool isNumber);
 | 
			
		||||
    ZResult doWebStream(int vval, uint8_t *vbuf, int vlen, bool isNumber, const char *filename, bool cache);
 | 
			
		||||
    ZResult doUpdateFirmware(int vval, uint8_t *vbuf, int vlen, bool isNumber);
 | 
			
		||||
    ZResult doTimeZoneSetupCommand(int vval, uint8_t *vbuf, int vlen, bool isNumber);
 | 
			
		||||
 | 
			
		||||
  public:
 | 
			
		||||
    int packetSize = 127;
 | 
			
		||||
    bool suppressResponses;
 | 
			
		||||
    bool numericResponses;
 | 
			
		||||
    bool longResponses;
 | 
			
		||||
    boolean doEcho;
 | 
			
		||||
    String EOLN;
 | 
			
		||||
    char EC='+';
 | 
			
		||||
    char ECS[32];
 | 
			
		||||
 | 
			
		||||
    ZCommand();
 | 
			
		||||
    void loadConfig();
 | 
			
		||||
 | 
			
		||||
    FlowControlType getFlowControlType();
 | 
			
		||||
    int getConfigFlagBitmap();
 | 
			
		||||
 | 
			
		||||
    void sendOfficialResponse(ZResult res);
 | 
			
		||||
    void serialIncoming();
 | 
			
		||||
    void loop();
 | 
			
		||||
    void reset();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,67 @@
 | 
			
		|||
/*
 | 
			
		||||
   Copyright 2016-2019 Bo Zimmerman
 | 
			
		||||
 | 
			
		||||
   Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
   you may not use this file except in compliance with the License.
 | 
			
		||||
   You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
     http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
   Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
   distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
   See the License for the specific language governing permissions and
 | 
			
		||||
   limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
class ZConfig : public ZMode
 | 
			
		||||
{
 | 
			
		||||
  private:
 | 
			
		||||
    enum ZConfigMenu
 | 
			
		||||
    {
 | 
			
		||||
      ZCFGMENU_MAIN=0,
 | 
			
		||||
      ZCFGMENU_NUM=1,
 | 
			
		||||
      ZCFGMENU_ADDRESS=2,
 | 
			
		||||
      ZCFGMENU_OPTIONS=3,
 | 
			
		||||
      ZCFGMENU_WIMENU=4,
 | 
			
		||||
      ZCFGMENU_WIFIPW=5,
 | 
			
		||||
      ZCFGMENU_WICONFIRM=6,
 | 
			
		||||
      ZCFGMENU_FLOW=7,
 | 
			
		||||
      ZCFGMENU_BBSMENU=8,
 | 
			
		||||
      ZCFGMENU_NEWPORT=9,
 | 
			
		||||
      ZCFGMENU_NEWHOST=10,
 | 
			
		||||
      ZCFGMENU_NOTES=11,
 | 
			
		||||
      ZCFGMENU_NETMENU=12,
 | 
			
		||||
      ZCFGMENU_SUBNET=13,
 | 
			
		||||
      ZCFGMENU_NEWPRINT=14
 | 
			
		||||
    } currState;
 | 
			
		||||
    
 | 
			
		||||
    ZSerial serial; // storage for serial settings only
 | 
			
		||||
 | 
			
		||||
    void switchBackToCommandMode();
 | 
			
		||||
    void doModeCommand();
 | 
			
		||||
    bool showMenu;
 | 
			
		||||
    bool savedEcho;
 | 
			
		||||
    String EOLN;
 | 
			
		||||
    const char *EOLNC;
 | 
			
		||||
    unsigned long lastNumber;
 | 
			
		||||
    String lastAddress;
 | 
			
		||||
    String lastOptions;
 | 
			
		||||
    String lastNotes;
 | 
			
		||||
    WiFiServerSpec serverSpec;
 | 
			
		||||
    bool newListen;
 | 
			
		||||
    bool useDHCP;
 | 
			
		||||
    bool settingsChanged=false;
 | 
			
		||||
    char netOpt = ' ';
 | 
			
		||||
    int lastNumNetworks=0;
 | 
			
		||||
    IPAddress lastIP;
 | 
			
		||||
    IPAddress lastDNS;
 | 
			
		||||
    IPAddress lastGW;
 | 
			
		||||
    IPAddress lastSN;
 | 
			
		||||
 | 
			
		||||
  public:
 | 
			
		||||
    void switchTo();
 | 
			
		||||
    void serialIncoming();
 | 
			
		||||
    void loop();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,34 @@
 | 
			
		|||
/*
 | 
			
		||||
   Copyright 2016-2019 Bo Zimmerman
 | 
			
		||||
 | 
			
		||||
   Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
   you may not use this file except in compliance with the License.
 | 
			
		||||
   You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
     http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
   Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
   distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
   See the License for the specific language governing permissions and
 | 
			
		||||
   limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#ifdef INCLUDE_SD_SHELL
 | 
			
		||||
#ifdef INCLUDE_HOSTCM
 | 
			
		||||
#include "proto_hostcm.h"
 | 
			
		||||
 | 
			
		||||
class ZHostCMMode : public ZMode
 | 
			
		||||
{
 | 
			
		||||
  private:
 | 
			
		||||
    void switchBackToCommandMode();
 | 
			
		||||
    HostCM *proto = 0;
 | 
			
		||||
 | 
			
		||||
  public:
 | 
			
		||||
    void switchTo();
 | 
			
		||||
    void serialIncoming();
 | 
			
		||||
    void loop();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,54 @@
 | 
			
		|||
/*
 | 
			
		||||
 * zircmode.h
 | 
			
		||||
 *
 | 
			
		||||
 *  Created on: May 18, 2022
 | 
			
		||||
 *      Author: Bo Zimmerman
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifdef INCLUDE_IRCC
 | 
			
		||||
class ZIRCMode: public ZMode
 | 
			
		||||
{
 | 
			
		||||
private:
 | 
			
		||||
  ZSerial serial; // storage for serial settings only
 | 
			
		||||
  bool showMenu;
 | 
			
		||||
  bool savedEcho;
 | 
			
		||||
  String EOLN;
 | 
			
		||||
  const char *EOLNC;
 | 
			
		||||
  WiFiClientNode *current = null;
 | 
			
		||||
  unsigned long lastNumber;
 | 
			
		||||
  unsigned long timeout=0;
 | 
			
		||||
  String buf;
 | 
			
		||||
  String nick;
 | 
			
		||||
  String lastAddress;
 | 
			
		||||
  String lastOptions;
 | 
			
		||||
  String lastNotes;
 | 
			
		||||
  String channelName;
 | 
			
		||||
  bool joinReceived;
 | 
			
		||||
  enum ZIRCMenu
 | 
			
		||||
  {
 | 
			
		||||
    ZIRCMENU_MAIN=0,
 | 
			
		||||
    ZIRCMENU_NICK=1,
 | 
			
		||||
    ZIRCMENU_ADDRESS=2,
 | 
			
		||||
    ZIRCMENU_NUM=3,
 | 
			
		||||
    ZIRCMENU_NOTES=4,
 | 
			
		||||
    ZIRCMENU_OPTIONS=5,
 | 
			
		||||
    ZIRCMENU_COMMAND=6
 | 
			
		||||
  } currState;
 | 
			
		||||
  enum ZIRCState
 | 
			
		||||
  {
 | 
			
		||||
    ZIRCSTATE_WAIT=0,
 | 
			
		||||
    ZIRCSTATE_COMMAND=1
 | 
			
		||||
  } ircState;
 | 
			
		||||
 | 
			
		||||
  void switchBackToCommandMode();
 | 
			
		||||
  void doIRCCommand();
 | 
			
		||||
  void loopMenuMode();
 | 
			
		||||
  void loopCommandMode();
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
  void switchTo();
 | 
			
		||||
  void serialIncoming();
 | 
			
		||||
  void loop();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif /* INCLUDE_IRCC */
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,66 @@
 | 
			
		|||
/*
 | 
			
		||||
   Copyright 2020-2020 Bo Zimmerman
 | 
			
		||||
 | 
			
		||||
   Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
   you may not use this file except in compliance with the License.
 | 
			
		||||
   You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
     http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
   Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
   distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
   See the License for the specific language governing permissions and
 | 
			
		||||
   limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
enum PrintPayloadType
 | 
			
		||||
{
 | 
			
		||||
  PETSCII,
 | 
			
		||||
  ASCII,
 | 
			
		||||
  RAW
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static unsigned int DEFAULT_DELAY_MS = 5000;
 | 
			
		||||
 | 
			
		||||
class ZPrint : public ZMode
 | 
			
		||||
{
 | 
			
		||||
  private:
 | 
			
		||||
    WiFiClientNode *wifiSock = null;
 | 
			
		||||
    File tfile;
 | 
			
		||||
    Stream *outStream = null;
 | 
			
		||||
    unsigned int timeoutDelayMs = DEFAULT_DELAY_MS;
 | 
			
		||||
    char *lastPrinterSpec = 0;
 | 
			
		||||
    unsigned long currentExpiresTimeMs = 0;
 | 
			
		||||
    unsigned long nextFlushMs = 0;
 | 
			
		||||
    PrintPayloadType payloadType = PETSCII;
 | 
			
		||||
    unsigned long lastNonPlusTimeMs = 0;
 | 
			
		||||
    int plussesInARow=0;
 | 
			
		||||
    size_t pdex=0;
 | 
			
		||||
    size_t coldex=0;
 | 
			
		||||
    char pbuf[258];
 | 
			
		||||
    ZSerial serial;
 | 
			
		||||
    char lastLastC = 0;
 | 
			
		||||
    char lastC = 0;
 | 
			
		||||
    short jobNum = 0;
 | 
			
		||||
 | 
			
		||||
    size_t writeStr(char *s);
 | 
			
		||||
    size_t writeChunk(char *s, int len);
 | 
			
		||||
    void switchBackToCommandMode(bool error);
 | 
			
		||||
    ZResult finishSwitchTo(char *hostIp, char *req, int port, bool doSSL);
 | 
			
		||||
    void announcePrintJob(const char *hostIp, const int port, const char *req);
 | 
			
		||||
 | 
			
		||||
  public:
 | 
			
		||||
 | 
			
		||||
    ZResult switchTo(char *vbuf, int vlen, bool petscii);
 | 
			
		||||
    ZResult switchToPostScript(char *prefix);
 | 
			
		||||
    void setLastPrinterSpec(const char *spec);
 | 
			
		||||
    bool testPrinterSpec(const char *vbuf, int vlen, bool petscii);
 | 
			
		||||
    char *getLastPrinterSpec();
 | 
			
		||||
    void setTimeoutDelayMs(int ms);
 | 
			
		||||
    int getTimeoutDelayMs();
 | 
			
		||||
 | 
			
		||||
    void serialIncoming();
 | 
			
		||||
    void loop();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,34 @@
 | 
			
		|||
/*
 | 
			
		||||
 * zslipmode.h
 | 
			
		||||
 *
 | 
			
		||||
 *  Created on: May 17, 2022
 | 
			
		||||
 *      Author: Bo Zimmerman
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifdef INCLUDE_SLIP
 | 
			
		||||
extern "C" {
 | 
			
		||||
#include "lwip/raw.h"
 | 
			
		||||
#include "slipif.h"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static ZSerial sserial;
 | 
			
		||||
class ZSLIPMode: public ZMode
 | 
			
		||||
{
 | 
			
		||||
private:
 | 
			
		||||
  void switchBackToCommandMode();
 | 
			
		||||
  String inPacket;
 | 
			
		||||
  bool started=false;
 | 
			
		||||
  bool escaped=false;
 | 
			
		||||
  raw_pcb *_pcb = 0;
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
  static const char SLIP_END = '\xc0';
 | 
			
		||||
  static const char SLIP_ESC = '\xdb';
 | 
			
		||||
  static const char SLIP_ESC_END = '\xdc';
 | 
			
		||||
  static const char SLIP_ESC_ESC = '\xdd';
 | 
			
		||||
  void switchTo();
 | 
			
		||||
  void serialIncoming();
 | 
			
		||||
  void loop();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif /* INCLUDE_SLIP_ */
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,51 @@
 | 
			
		|||
/*
 | 
			
		||||
   Copyright 2016-2019 Bo Zimmerman
 | 
			
		||||
 | 
			
		||||
   Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
   you may not use this file except in compliance with the License.
 | 
			
		||||
   You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
	   http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
   Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
   distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
   See the License for the specific language governing permissions and
 | 
			
		||||
   limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#define ZSTREAM_ESC_BUF_MAX 10
 | 
			
		||||
 | 
			
		||||
class ZStream : public ZMode
 | 
			
		||||
{
 | 
			
		||||
  private:
 | 
			
		||||
    WiFiClientNode *current = null;
 | 
			
		||||
    unsigned long lastNonPlusTimeMs = 0;
 | 
			
		||||
    unsigned long currentExpiresTimeMs = 0;
 | 
			
		||||
    unsigned long nextFlushMs = 0;
 | 
			
		||||
    int plussesInARow = 0;
 | 
			
		||||
    ZSerial serial;
 | 
			
		||||
    int lastDTR = 0;
 | 
			
		||||
    uint8_t escBuf[ZSTREAM_ESC_BUF_MAX];
 | 
			
		||||
    unsigned long nextAlarm = millis() + 5000;
 | 
			
		||||
    
 | 
			
		||||
    void switchBackToCommandMode(bool logout);
 | 
			
		||||
    void socketWrite(uint8_t c);
 | 
			
		||||
    void socketWrite(uint8_t *buf, uint8_t len);
 | 
			
		||||
    void baudDelay();
 | 
			
		||||
 | 
			
		||||
    bool isPETSCII();
 | 
			
		||||
    bool isEcho();
 | 
			
		||||
    FlowControlType getFlowControl();
 | 
			
		||||
    bool isTelnet();
 | 
			
		||||
    bool isDisconnectedOnStreamExit();
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
  public:
 | 
			
		||||
    
 | 
			
		||||
    void switchTo(WiFiClientNode *conn);
 | 
			
		||||
    
 | 
			
		||||
    void serialIncoming();
 | 
			
		||||
    void loop();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,46 @@
 | 
			
		|||
 | 
			
		||||
This directory is intended for project specific (private) libraries.
 | 
			
		||||
PlatformIO will compile them to static libraries and link into executable file.
 | 
			
		||||
 | 
			
		||||
The source code of each library should be placed in a an own separate directory
 | 
			
		||||
("lib/your_library_name/[here are source files]").
 | 
			
		||||
 | 
			
		||||
For example, see a structure of the following two libraries `Foo` and `Bar`:
 | 
			
		||||
 | 
			
		||||
|--lib
 | 
			
		||||
|  |
 | 
			
		||||
|  |--Bar
 | 
			
		||||
|  |  |--docs
 | 
			
		||||
|  |  |--examples
 | 
			
		||||
|  |  |--src
 | 
			
		||||
|  |     |- Bar.c
 | 
			
		||||
|  |     |- Bar.h
 | 
			
		||||
|  |  |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
 | 
			
		||||
|  |
 | 
			
		||||
|  |--Foo
 | 
			
		||||
|  |  |- Foo.c
 | 
			
		||||
|  |  |- Foo.h
 | 
			
		||||
|  |
 | 
			
		||||
|  |- README --> THIS FILE
 | 
			
		||||
|
 | 
			
		||||
|- platformio.ini
 | 
			
		||||
|--src
 | 
			
		||||
   |- main.c
 | 
			
		||||
 | 
			
		||||
and a contents of `src/main.c`:
 | 
			
		||||
```
 | 
			
		||||
#include <Foo.h>
 | 
			
		||||
#include <Bar.h>
 | 
			
		||||
 | 
			
		||||
int main (void)
 | 
			
		||||
{
 | 
			
		||||
  ...
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
PlatformIO Library Dependency Finder will find automatically dependent
 | 
			
		||||
libraries scanning project source files.
 | 
			
		||||
 | 
			
		||||
More information about PlatformIO Library Dependency Finder
 | 
			
		||||
- https://docs.platformio.org/page/librarymanager/ldf.html
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,114 @@
 | 
			
		|||
#if defined(ESP32)
 | 
			
		||||
#ifndef __LIBSSH2_AGENT_H
 | 
			
		||||
#define __LIBSSH2_AGENT_H
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (c) 2009 by Daiki Ueno
 | 
			
		||||
 * Copyright (C) 2010-2014 by Daniel Stenberg
 | 
			
		||||
 * All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Redistribution and use in source and binary forms,
 | 
			
		||||
 * with or without modification, are permitted provided
 | 
			
		||||
 * that the following conditions are met:
 | 
			
		||||
 *
 | 
			
		||||
 *   Redistributions of source code must retain the above
 | 
			
		||||
 *   copyright notice, this list of conditions and the
 | 
			
		||||
 *   following disclaimer.
 | 
			
		||||
 *
 | 
			
		||||
 *   Redistributions in binary form must reproduce the above
 | 
			
		||||
 *   copyright notice, this list of conditions and the following
 | 
			
		||||
 *   disclaimer in the documentation and/or other materials
 | 
			
		||||
 *   provided with the distribution.
 | 
			
		||||
 *
 | 
			
		||||
 *   Neither the name of the copyright holder nor the names
 | 
			
		||||
 *   of any other contributors may be used to endorse or
 | 
			
		||||
 *   promote products derived from this software without
 | 
			
		||||
 *   specific prior written permission.
 | 
			
		||||
 *
 | 
			
		||||
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
 | 
			
		||||
 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 | 
			
		||||
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 | 
			
		||||
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 | 
			
		||||
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 | 
			
		||||
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | 
			
		||||
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 | 
			
		||||
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 | 
			
		||||
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 | 
			
		||||
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 | 
			
		||||
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 | 
			
		||||
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
 | 
			
		||||
 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
 | 
			
		||||
 * OF SUCH DAMAGE.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "libssh2_priv.h"
 | 
			
		||||
#include "misc.h"
 | 
			
		||||
#include "session.h"
 | 
			
		||||
#ifdef WIN32
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/* non-blocking mode on agent connection is not yet implemented, but
 | 
			
		||||
   for future use. */
 | 
			
		||||
typedef enum {
 | 
			
		||||
    agent_NB_state_init = 0,
 | 
			
		||||
    agent_NB_state_request_created,
 | 
			
		||||
    agent_NB_state_request_length_sent,
 | 
			
		||||
    agent_NB_state_request_sent,
 | 
			
		||||
    agent_NB_state_response_length_received,
 | 
			
		||||
    agent_NB_state_response_received
 | 
			
		||||
} agent_nonblocking_states;
 | 
			
		||||
 | 
			
		||||
typedef struct agent_transaction_ctx {
 | 
			
		||||
    unsigned char *request;
 | 
			
		||||
    size_t request_len;
 | 
			
		||||
    unsigned char *response;
 | 
			
		||||
    size_t response_len;
 | 
			
		||||
    agent_nonblocking_states state;
 | 
			
		||||
    size_t send_recv_total;
 | 
			
		||||
} *agent_transaction_ctx_t;
 | 
			
		||||
 | 
			
		||||
typedef int (*agent_connect_func)(LIBSSH2_AGENT *agent);
 | 
			
		||||
typedef int (*agent_transact_func)(LIBSSH2_AGENT *agent,
 | 
			
		||||
                                   agent_transaction_ctx_t transctx);
 | 
			
		||||
typedef int (*agent_disconnect_func)(LIBSSH2_AGENT *agent);
 | 
			
		||||
 | 
			
		||||
struct agent_publickey {
 | 
			
		||||
    struct list_node node;
 | 
			
		||||
 | 
			
		||||
    /* this is the struct we expose externally */
 | 
			
		||||
    struct libssh2_agent_publickey external;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct agent_ops {
 | 
			
		||||
    agent_connect_func connect;
 | 
			
		||||
    agent_transact_func transact;
 | 
			
		||||
    agent_disconnect_func disconnect;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct _LIBSSH2_AGENT
 | 
			
		||||
{
 | 
			
		||||
    LIBSSH2_SESSION *session;  /* the session this "belongs to" */
 | 
			
		||||
 | 
			
		||||
    libssh2_socket_t fd;
 | 
			
		||||
 | 
			
		||||
    struct agent_ops *ops;
 | 
			
		||||
 | 
			
		||||
    struct agent_transaction_ctx transctx;
 | 
			
		||||
    struct agent_publickey *identity;
 | 
			
		||||
    struct list_head head;              /* list of public keys */
 | 
			
		||||
 | 
			
		||||
    char *identity_agent_path; /* Path to a custom identity agent socket */
 | 
			
		||||
 | 
			
		||||
#ifdef WIN32
 | 
			
		||||
    OVERLAPPED overlapped;
 | 
			
		||||
    HANDLE pipe;
 | 
			
		||||
    BOOL pending_io;
 | 
			
		||||
#endif
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#ifdef WIN32
 | 
			
		||||
extern struct agent_ops agent_ops_openssh;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif /* __LIBSSH2_AGENT_H */
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,185 @@
 | 
			
		|||
#if defined(ESP32)
 | 
			
		||||
/* $OpenBSD: bcrypt_pbkdf.c,v 1.4 2013/07/29 00:55:53 tedu Exp $ */
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (c) 2013 Ted Unangst <tedu@openbsd.org>
 | 
			
		||||
 *
 | 
			
		||||
 * Permission to use, copy, modify, and distribute this software for any
 | 
			
		||||
 * purpose with or without fee is hereby granted, provided that the above
 | 
			
		||||
 * copyright notice and this permission notice appear in all copies.
 | 
			
		||||
 *
 | 
			
		||||
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 | 
			
		||||
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 | 
			
		||||
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 | 
			
		||||
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 | 
			
		||||
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 | 
			
		||||
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 | 
			
		||||
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#ifndef HAVE_BCRYPT_PBKDF
 | 
			
		||||
 | 
			
		||||
#include "libssh2_priv.h"
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
#ifdef HAVE_SYS_PARAM_H
 | 
			
		||||
#include <sys/param.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include "blf.h"
 | 
			
		||||
 | 
			
		||||
#define MINIMUM(a,b) (((a) < (b)) ? (a) : (b))
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * pkcs #5 pbkdf2 implementation using the "bcrypt" hash
 | 
			
		||||
 *
 | 
			
		||||
 * The bcrypt hash function is derived from the bcrypt password hashing
 | 
			
		||||
 * function with the following modifications:
 | 
			
		||||
 * 1. The input password and salt are preprocessed with SHA512.
 | 
			
		||||
 * 2. The output length is expanded to 256 bits.
 | 
			
		||||
 * 3. Subsequently the magic string to be encrypted is lengthened and modified
 | 
			
		||||
 *    to "OxychromaticBlowfishSwatDynamite"
 | 
			
		||||
 * 4. The hash function is defined to perform 64 rounds of initial state
 | 
			
		||||
 *    expansion. (More rounds are performed by iterating the hash.)
 | 
			
		||||
 *
 | 
			
		||||
 * Note that this implementation pulls the SHA512 operations into the caller
 | 
			
		||||
 * as a performance optimization.
 | 
			
		||||
 *
 | 
			
		||||
 * One modification from official pbkdf2. Instead of outputting key material
 | 
			
		||||
 * linearly, we mix it. pbkdf2 has a known weakness where if one uses it to
 | 
			
		||||
 * generate (i.e.) 512 bits of key material for use as two 256 bit keys, an
 | 
			
		||||
 * attacker can merely run once through the outer loop below, but the user
 | 
			
		||||
 * always runs it twice. Shuffling output bytes requires computing the
 | 
			
		||||
 * entirety of the key material to assemble any subkey. This is something a
 | 
			
		||||
 * wise caller could do; we just do it for you.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#define BCRYPT_BLOCKS 8
 | 
			
		||||
#define BCRYPT_HASHSIZE (BCRYPT_BLOCKS * 4)
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
bcrypt_hash(uint8_t *sha2pass, uint8_t *sha2salt, uint8_t *out)
 | 
			
		||||
{
 | 
			
		||||
    blf_ctx state;
 | 
			
		||||
    uint8_t ciphertext[BCRYPT_HASHSIZE] = {
 | 
			
		||||
        'O', 'x', 'y', 'c', 'h', 'r', 'o', 'm', 'a', 't', 'i', 'c',
 | 
			
		||||
        'B', 'l', 'o', 'w', 'f', 'i', 's', 'h',
 | 
			
		||||
        'S', 'w', 'a', 't',
 | 
			
		||||
        'D', 'y', 'n', 'a', 'm', 'i', 't', 'e' };
 | 
			
		||||
    uint32_t cdata[BCRYPT_BLOCKS];
 | 
			
		||||
    int i;
 | 
			
		||||
    uint16_t j;
 | 
			
		||||
    uint16_t shalen = SHA512_DIGEST_LENGTH;
 | 
			
		||||
 | 
			
		||||
    /* key expansion */
 | 
			
		||||
    Blowfish_initstate(&state);
 | 
			
		||||
    Blowfish_expandstate(&state, sha2salt, shalen, sha2pass, shalen);
 | 
			
		||||
    for(i = 0; i < 64; i++) {
 | 
			
		||||
        Blowfish_expand0state(&state, sha2salt, shalen);
 | 
			
		||||
        Blowfish_expand0state(&state, sha2pass, shalen);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* encryption */
 | 
			
		||||
    j = 0;
 | 
			
		||||
    for(i = 0; i < BCRYPT_BLOCKS; i++)
 | 
			
		||||
        cdata[i] = Blowfish_stream2word(ciphertext, sizeof(ciphertext),
 | 
			
		||||
                                        &j);
 | 
			
		||||
    for(i = 0; i < 64; i++)
 | 
			
		||||
        blf_enc(&state, cdata, BCRYPT_BLOCKS / 2);
 | 
			
		||||
 | 
			
		||||
    /* copy out */
 | 
			
		||||
    for(i = 0; i < BCRYPT_BLOCKS; i++) {
 | 
			
		||||
        out[4 * i + 3] = (cdata[i] >> 24) & 0xff;
 | 
			
		||||
        out[4 * i + 2] = (cdata[i] >> 16) & 0xff;
 | 
			
		||||
        out[4 * i + 1] = (cdata[i] >> 8) & 0xff;
 | 
			
		||||
        out[4 * i + 0] = cdata[i] & 0xff;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* zap */
 | 
			
		||||
    _libssh2_explicit_zero(ciphertext, sizeof(ciphertext));
 | 
			
		||||
    _libssh2_explicit_zero(cdata, sizeof(cdata));
 | 
			
		||||
    _libssh2_explicit_zero(&state, sizeof(state));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
bcrypt_pbkdf(const char *pass, size_t passlen, const uint8_t *salt,
 | 
			
		||||
             size_t saltlen,
 | 
			
		||||
             uint8_t *key, size_t keylen, unsigned int rounds)
 | 
			
		||||
{
 | 
			
		||||
    uint8_t sha2pass[SHA512_DIGEST_LENGTH];
 | 
			
		||||
    uint8_t sha2salt[SHA512_DIGEST_LENGTH];
 | 
			
		||||
    uint8_t out[BCRYPT_HASHSIZE];
 | 
			
		||||
    uint8_t tmpout[BCRYPT_HASHSIZE];
 | 
			
		||||
    uint8_t *countsalt;
 | 
			
		||||
    size_t i, j, amt, stride;
 | 
			
		||||
    uint32_t count;
 | 
			
		||||
    size_t origkeylen = keylen;
 | 
			
		||||
    libssh2_sha512_ctx ctx;
 | 
			
		||||
 | 
			
		||||
    /* nothing crazy */
 | 
			
		||||
    if(rounds < 1)
 | 
			
		||||
        return -1;
 | 
			
		||||
    if(passlen == 0 || saltlen == 0 || keylen == 0 ||
 | 
			
		||||
       keylen > sizeof(out) * sizeof(out) || saltlen > 1<<20)
 | 
			
		||||
        return -1;
 | 
			
		||||
    countsalt = calloc(1, saltlen + 4);
 | 
			
		||||
    if(countsalt == NULL)
 | 
			
		||||
        return -1;
 | 
			
		||||
    stride = (keylen + sizeof(out) - 1) / sizeof(out);
 | 
			
		||||
    amt = (keylen + stride - 1) / stride;
 | 
			
		||||
 | 
			
		||||
    memcpy(countsalt, salt, saltlen);
 | 
			
		||||
 | 
			
		||||
    /* collapse password */
 | 
			
		||||
    (void)libssh2_sha512_init(&ctx);
 | 
			
		||||
    libssh2_sha512_update(ctx, pass, passlen);
 | 
			
		||||
    libssh2_sha512_final(ctx, sha2pass);
 | 
			
		||||
 | 
			
		||||
    /* generate key, sizeof(out) at a time */
 | 
			
		||||
    for(count = 1; keylen > 0; count++) {
 | 
			
		||||
        countsalt[saltlen + 0] = (count >> 24) & 0xff;
 | 
			
		||||
        countsalt[saltlen + 1] = (count >> 16) & 0xff;
 | 
			
		||||
        countsalt[saltlen + 2] = (count >> 8) & 0xff;
 | 
			
		||||
        countsalt[saltlen + 3] = count & 0xff;
 | 
			
		||||
 | 
			
		||||
        /* first round, salt is salt */
 | 
			
		||||
        (void)libssh2_sha512_init(&ctx);
 | 
			
		||||
        libssh2_sha512_update(ctx, countsalt, saltlen + 4);
 | 
			
		||||
        libssh2_sha512_final(ctx, sha2salt);
 | 
			
		||||
 | 
			
		||||
        bcrypt_hash(sha2pass, sha2salt, tmpout);
 | 
			
		||||
        memcpy(out, tmpout, sizeof(out));
 | 
			
		||||
 | 
			
		||||
        for(i = 1; i < rounds; i++) {
 | 
			
		||||
            /* subsequent rounds, salt is previous output */
 | 
			
		||||
            (void)libssh2_sha512_init(&ctx);
 | 
			
		||||
            libssh2_sha512_update(ctx, tmpout, sizeof(tmpout));
 | 
			
		||||
            libssh2_sha512_final(ctx, sha2salt);
 | 
			
		||||
 | 
			
		||||
            bcrypt_hash(sha2pass, sha2salt, tmpout);
 | 
			
		||||
            for(j = 0; j < sizeof(out); j++)
 | 
			
		||||
                out[j] ^= tmpout[j];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /*
 | 
			
		||||
         * pbkdf2 deviation: output the key material non-linearly.
 | 
			
		||||
         */
 | 
			
		||||
        amt = MINIMUM(amt, keylen);
 | 
			
		||||
        for(i = 0; i < amt; i++) {
 | 
			
		||||
            size_t dest = i * stride + (count - 1);
 | 
			
		||||
            if(dest >= origkeylen) {
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            key[dest] = out[i];
 | 
			
		||||
        }
 | 
			
		||||
        keylen -= i;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* zap */
 | 
			
		||||
    _libssh2_explicit_zero(out, sizeof(out));
 | 
			
		||||
    free(countsalt);
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
#endif /* HAVE_BCRYPT_PBKDF */
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,88 @@
 | 
			
		|||
#if defined(ESP32)
 | 
			
		||||
#ifndef __LIBSSH2_BLF_H
 | 
			
		||||
#define __LIBSSH2_BLF_H
 | 
			
		||||
/* $OpenBSD: blf.h,v 1.7 2007/03/14 17:59:41 grunk Exp $ */
 | 
			
		||||
/*
 | 
			
		||||
 * Blowfish - a fast block cipher designed by Bruce Schneier
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright 1997 Niels Provos <provos@physnet.uni-hamburg.de>
 | 
			
		||||
 * All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Redistribution and use in source and binary forms, with or without
 | 
			
		||||
 * modification, are permitted provided that the following conditions
 | 
			
		||||
 * are met:
 | 
			
		||||
 * 1. Redistributions of source code must retain the above copyright
 | 
			
		||||
 *    notice, this list of conditions and the following disclaimer.
 | 
			
		||||
 * 2. Redistributions in binary form must reproduce the above copyright
 | 
			
		||||
 *    notice, this list of conditions and the following disclaimer in the
 | 
			
		||||
 *    documentation and/or other materials provided with the distribution.
 | 
			
		||||
 * 3. The name of the author may not be used to endorse or promote products
 | 
			
		||||
 *    derived from this software without specific prior written permission.
 | 
			
		||||
 *
 | 
			
		||||
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 | 
			
		||||
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 | 
			
		||||
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 | 
			
		||||
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 | 
			
		||||
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 | 
			
		||||
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 | 
			
		||||
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 | 
			
		||||
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | 
			
		||||
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 | 
			
		||||
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#if !defined(HAVE_BCRYPT_PBKDF) && !defined(HAVE_BLH_H)
 | 
			
		||||
 | 
			
		||||
/* Schneier specifies a maximum key length of 56 bytes.
 | 
			
		||||
 * This ensures that every key bit affects every cipher
 | 
			
		||||
 * bit.  However, the subkeys can hold up to 72 bytes.
 | 
			
		||||
 * Warning: For normal blowfish encryption only 56 bytes
 | 
			
		||||
 * of the key affect all cipherbits.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#define BLF_N   16                      /* Number of Subkeys */
 | 
			
		||||
#define BLF_MAXKEYLEN ((BLF_N-2)*4)     /* 448 bits */
 | 
			
		||||
#define BLF_MAXUTILIZED ((BLF_N + 2)*4)   /* 576 bits */
 | 
			
		||||
 | 
			
		||||
/* Blowfish context */
 | 
			
		||||
typedef struct BlowfishContext {
 | 
			
		||||
        uint32_t S[4][256];     /* S-Boxes */
 | 
			
		||||
        uint32_t P[BLF_N + 2];  /* Subkeys */
 | 
			
		||||
} blf_ctx;
 | 
			
		||||
 | 
			
		||||
/* Raw access to customized Blowfish
 | 
			
		||||
 *      blf_key is just:
 | 
			
		||||
 *      Blowfish_initstate( state )
 | 
			
		||||
 *      Blowfish_expand0state( state, key, keylen )
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
void Blowfish_encipher(blf_ctx *, uint32_t *, uint32_t *);
 | 
			
		||||
void Blowfish_decipher(blf_ctx *, uint32_t *, uint32_t *);
 | 
			
		||||
void Blowfish_initstate(blf_ctx *);
 | 
			
		||||
void Blowfish_expand0state(blf_ctx *, const uint8_t *, uint16_t);
 | 
			
		||||
void Blowfish_expandstate
 | 
			
		||||
(blf_ctx *, const uint8_t *, uint16_t, const uint8_t *, uint16_t);
 | 
			
		||||
 | 
			
		||||
/* Standard Blowfish */
 | 
			
		||||
 | 
			
		||||
void blf_key(blf_ctx *, const uint8_t *, uint16_t);
 | 
			
		||||
void blf_enc(blf_ctx *, uint32_t *, uint16_t);
 | 
			
		||||
void blf_dec(blf_ctx *, uint32_t *, uint16_t);
 | 
			
		||||
 | 
			
		||||
void blf_ecb_encrypt(blf_ctx *, uint8_t *, uint32_t);
 | 
			
		||||
void blf_ecb_decrypt(blf_ctx *, uint8_t *, uint32_t);
 | 
			
		||||
 | 
			
		||||
void blf_cbc_encrypt(blf_ctx *, uint8_t *, uint8_t *, uint32_t);
 | 
			
		||||
void blf_cbc_decrypt(blf_ctx *, uint8_t *, uint8_t *, uint32_t);
 | 
			
		||||
 | 
			
		||||
/* Converts uint8_t to uint32_t */
 | 
			
		||||
uint32_t Blowfish_stream2word(const uint8_t *, uint16_t, uint16_t *);
 | 
			
		||||
 | 
			
		||||
/* bcrypt with pbkd */
 | 
			
		||||
int bcrypt_pbkdf(const char *pass, size_t passlen, const uint8_t *salt,
 | 
			
		||||
                 size_t saltlen,
 | 
			
		||||
                 uint8_t *key, size_t keylen, unsigned int rounds);
 | 
			
		||||
 | 
			
		||||
#endif /* !defined(HAVE_BCRYPT_PBKDF) && !defined(HAVE_BLH_H) */
 | 
			
		||||
#endif /* __LIBSSH2_BLF_H */
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,696 @@
 | 
			
		|||
#if defined(ESP32)
 | 
			
		||||
/* $OpenBSD: blowfish.c,v 1.18 2004/11/02 17:23:26 hshoexer Exp $ */
 | 
			
		||||
/*
 | 
			
		||||
 * Blowfish block cipher for OpenBSD
 | 
			
		||||
 * Copyright 1997 Niels Provos <provos@physnet.uni-hamburg.de>
 | 
			
		||||
 * All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Implementation advice by David Mazieres <dm@lcs.mit.edu>.
 | 
			
		||||
 *
 | 
			
		||||
 * Redistribution and use in source and binary forms, with or without
 | 
			
		||||
 * modification, are permitted provided that the following conditions
 | 
			
		||||
 * are met:
 | 
			
		||||
 * 1. Redistributions of source code must retain the above copyright
 | 
			
		||||
 *    notice, this list of conditions and the following disclaimer.
 | 
			
		||||
 * 2. Redistributions in binary form must reproduce the above copyright
 | 
			
		||||
 *    notice, this list of conditions and the following disclaimer in the
 | 
			
		||||
 *    documentation and/or other materials provided with the distribution.
 | 
			
		||||
 * 3. The name of the author may not be used to endorse or promote products
 | 
			
		||||
 *    derived from this software without specific prior written permission.
 | 
			
		||||
 *
 | 
			
		||||
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 | 
			
		||||
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 | 
			
		||||
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 | 
			
		||||
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 | 
			
		||||
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 | 
			
		||||
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 | 
			
		||||
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 | 
			
		||||
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | 
			
		||||
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 | 
			
		||||
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * This code is derived from section 14.3 and the given source
 | 
			
		||||
 * in section V of Applied Cryptography, second edition.
 | 
			
		||||
 * Blowfish is an unpatented fast block cipher designed by
 | 
			
		||||
 * Bruce Schneier.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#if !defined(HAVE_BCRYPT_PBKDF) && (!defined(HAVE_BLOWFISH_INITSTATE) || \
 | 
			
		||||
                                    !defined(HAVE_BLOWFISH_EXPAND0STATE) || \
 | 
			
		||||
                                    !defined(HAVE_BLF_ENC))
 | 
			
		||||
 | 
			
		||||
#if 0
 | 
			
		||||
#include <stdio.h>              /* used for debugging */
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include <sys/types.h>
 | 
			
		||||
 | 
			
		||||
#include "libssh2.h"
 | 
			
		||||
#include "blf.h"
 | 
			
		||||
 | 
			
		||||
#undef inline
 | 
			
		||||
#ifdef __GNUC__
 | 
			
		||||
#define inline __inline
 | 
			
		||||
#else                           /* !__GNUC__ */
 | 
			
		||||
#define inline
 | 
			
		||||
#endif                          /* !__GNUC__ */
 | 
			
		||||
 | 
			
		||||
/* Function for Feistel Networks */
 | 
			
		||||
 | 
			
		||||
#define F(s, x) ((((s)[        (((x)>>24)&0xFF)]        \
 | 
			
		||||
                   + (s)[0x100 + (((x)>>16)&0xFF)])     \
 | 
			
		||||
                  ^ (s)[0x200 + (((x)>> 8)&0xFF)])      \
 | 
			
		||||
                 + (s)[0x300 + ( (x)     &0xFF)])
 | 
			
		||||
 | 
			
		||||
#define BLFRND(s,p,i,j,n) (i ^= F(s,j) ^ (p)[n])
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
Blowfish_encipher(blf_ctx *c, uint32_t *xl, uint32_t *xr)
 | 
			
		||||
{
 | 
			
		||||
    uint32_t Xl;
 | 
			
		||||
    uint32_t Xr;
 | 
			
		||||
    uint32_t *s = c->S[0];
 | 
			
		||||
    uint32_t *p = c->P;
 | 
			
		||||
 | 
			
		||||
    Xl = *xl;
 | 
			
		||||
    Xr = *xr;
 | 
			
		||||
 | 
			
		||||
    Xl ^= p[0];
 | 
			
		||||
    BLFRND(s, p, Xr, Xl, 1); BLFRND(s, p, Xl, Xr, 2);
 | 
			
		||||
    BLFRND(s, p, Xr, Xl, 3); BLFRND(s, p, Xl, Xr, 4);
 | 
			
		||||
    BLFRND(s, p, Xr, Xl, 5); BLFRND(s, p, Xl, Xr, 6);
 | 
			
		||||
    BLFRND(s, p, Xr, Xl, 7); BLFRND(s, p, Xl, Xr, 8);
 | 
			
		||||
    BLFRND(s, p, Xr, Xl, 9); BLFRND(s, p, Xl, Xr, 10);
 | 
			
		||||
    BLFRND(s, p, Xr, Xl, 11); BLFRND(s, p, Xl, Xr, 12);
 | 
			
		||||
    BLFRND(s, p, Xr, Xl, 13); BLFRND(s, p, Xl, Xr, 14);
 | 
			
		||||
    BLFRND(s, p, Xr, Xl, 15); BLFRND(s, p, Xl, Xr, 16);
 | 
			
		||||
 | 
			
		||||
    *xl = Xr ^ p[17];
 | 
			
		||||
    *xr = Xl;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
Blowfish_decipher(blf_ctx *c, uint32_t *xl, uint32_t *xr)
 | 
			
		||||
{
 | 
			
		||||
    uint32_t Xl;
 | 
			
		||||
    uint32_t Xr;
 | 
			
		||||
    uint32_t *s = c->S[0];
 | 
			
		||||
    uint32_t *p = c->P;
 | 
			
		||||
 | 
			
		||||
    Xl = *xl;
 | 
			
		||||
    Xr = *xr;
 | 
			
		||||
 | 
			
		||||
    Xl ^= p[17];
 | 
			
		||||
    BLFRND(s, p, Xr, Xl, 16); BLFRND(s, p, Xl, Xr, 15);
 | 
			
		||||
    BLFRND(s, p, Xr, Xl, 14); BLFRND(s, p, Xl, Xr, 13);
 | 
			
		||||
    BLFRND(s, p, Xr, Xl, 12); BLFRND(s, p, Xl, Xr, 11);
 | 
			
		||||
    BLFRND(s, p, Xr, Xl, 10); BLFRND(s, p, Xl, Xr, 9);
 | 
			
		||||
    BLFRND(s, p, Xr, Xl, 8); BLFRND(s, p, Xl, Xr, 7);
 | 
			
		||||
    BLFRND(s, p, Xr, Xl, 6); BLFRND(s, p, Xl, Xr, 5);
 | 
			
		||||
    BLFRND(s, p, Xr, Xl, 4); BLFRND(s, p, Xl, Xr, 3);
 | 
			
		||||
    BLFRND(s, p, Xr, Xl, 2); BLFRND(s, p, Xl, Xr, 1);
 | 
			
		||||
 | 
			
		||||
    *xl = Xr ^ p[0];
 | 
			
		||||
    *xr = Xl;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
Blowfish_initstate(blf_ctx *c)
 | 
			
		||||
{
 | 
			
		||||
    /* P-box and S-box tables initialized with digits of Pi */
 | 
			
		||||
 | 
			
		||||
    static const blf_ctx initstate =
 | 
			
		||||
        { {
 | 
			
		||||
                {
 | 
			
		||||
                    0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7,
 | 
			
		||||
                    0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99,
 | 
			
		||||
                    0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16,
 | 
			
		||||
                    0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e,
 | 
			
		||||
                    0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee,
 | 
			
		||||
                    0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013,
 | 
			
		||||
                    0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef,
 | 
			
		||||
                    0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e,
 | 
			
		||||
                    0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60,
 | 
			
		||||
                    0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440,
 | 
			
		||||
                    0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce,
 | 
			
		||||
                    0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a,
 | 
			
		||||
                    0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e,
 | 
			
		||||
                    0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677,
 | 
			
		||||
                    0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193,
 | 
			
		||||
                    0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032,
 | 
			
		||||
                    0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88,
 | 
			
		||||
                    0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239,
 | 
			
		||||
                    0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e,
 | 
			
		||||
                    0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0,
 | 
			
		||||
                    0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3,
 | 
			
		||||
                    0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98,
 | 
			
		||||
                    0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88,
 | 
			
		||||
                    0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe,
 | 
			
		||||
                    0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6,
 | 
			
		||||
                    0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d,
 | 
			
		||||
                    0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b,
 | 
			
		||||
                    0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7,
 | 
			
		||||
                    0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba,
 | 
			
		||||
                    0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463,
 | 
			
		||||
                    0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f,
 | 
			
		||||
                    0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09,
 | 
			
		||||
                    0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3,
 | 
			
		||||
                    0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb,
 | 
			
		||||
                    0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279,
 | 
			
		||||
                    0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8,
 | 
			
		||||
                    0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab,
 | 
			
		||||
                    0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82,
 | 
			
		||||
                    0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db,
 | 
			
		||||
                    0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573,
 | 
			
		||||
                    0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0,
 | 
			
		||||
                    0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b,
 | 
			
		||||
                    0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790,
 | 
			
		||||
                    0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8,
 | 
			
		||||
                    0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4,
 | 
			
		||||
                    0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0,
 | 
			
		||||
                    0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7,
 | 
			
		||||
                    0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c,
 | 
			
		||||
                    0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad,
 | 
			
		||||
                    0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1,
 | 
			
		||||
                    0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299,
 | 
			
		||||
                    0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9,
 | 
			
		||||
                    0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477,
 | 
			
		||||
                    0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf,
 | 
			
		||||
                    0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49,
 | 
			
		||||
                    0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af,
 | 
			
		||||
                    0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa,
 | 
			
		||||
                    0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5,
 | 
			
		||||
                    0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41,
 | 
			
		||||
                    0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915,
 | 
			
		||||
                    0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400,
 | 
			
		||||
                    0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915,
 | 
			
		||||
                    0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664,
 | 
			
		||||
                    0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a},
 | 
			
		||||
                {
 | 
			
		||||
                    0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623,
 | 
			
		||||
                    0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266,
 | 
			
		||||
                    0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1,
 | 
			
		||||
                    0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e,
 | 
			
		||||
                    0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6,
 | 
			
		||||
                    0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1,
 | 
			
		||||
                    0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e,
 | 
			
		||||
                    0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1,
 | 
			
		||||
                    0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737,
 | 
			
		||||
                    0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8,
 | 
			
		||||
                    0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff,
 | 
			
		||||
                    0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd,
 | 
			
		||||
                    0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701,
 | 
			
		||||
                    0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7,
 | 
			
		||||
                    0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41,
 | 
			
		||||
                    0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331,
 | 
			
		||||
                    0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf,
 | 
			
		||||
                    0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af,
 | 
			
		||||
                    0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e,
 | 
			
		||||
                    0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87,
 | 
			
		||||
                    0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c,
 | 
			
		||||
                    0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2,
 | 
			
		||||
                    0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16,
 | 
			
		||||
                    0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd,
 | 
			
		||||
                    0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b,
 | 
			
		||||
                    0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509,
 | 
			
		||||
                    0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e,
 | 
			
		||||
                    0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3,
 | 
			
		||||
                    0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f,
 | 
			
		||||
                    0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a,
 | 
			
		||||
                    0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4,
 | 
			
		||||
                    0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960,
 | 
			
		||||
                    0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66,
 | 
			
		||||
                    0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28,
 | 
			
		||||
                    0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802,
 | 
			
		||||
                    0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84,
 | 
			
		||||
                    0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510,
 | 
			
		||||
                    0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf,
 | 
			
		||||
                    0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14,
 | 
			
		||||
                    0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e,
 | 
			
		||||
                    0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50,
 | 
			
		||||
                    0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7,
 | 
			
		||||
                    0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8,
 | 
			
		||||
                    0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281,
 | 
			
		||||
                    0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99,
 | 
			
		||||
                    0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696,
 | 
			
		||||
                    0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128,
 | 
			
		||||
                    0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73,
 | 
			
		||||
                    0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0,
 | 
			
		||||
                    0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0,
 | 
			
		||||
                    0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105,
 | 
			
		||||
                    0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250,
 | 
			
		||||
                    0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3,
 | 
			
		||||
                    0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285,
 | 
			
		||||
                    0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00,
 | 
			
		||||
                    0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061,
 | 
			
		||||
                    0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb,
 | 
			
		||||
                    0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e,
 | 
			
		||||
                    0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735,
 | 
			
		||||
                    0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc,
 | 
			
		||||
                    0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9,
 | 
			
		||||
                    0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340,
 | 
			
		||||
                    0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20,
 | 
			
		||||
                    0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7},
 | 
			
		||||
                {
 | 
			
		||||
                    0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934,
 | 
			
		||||
                    0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068,
 | 
			
		||||
                    0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af,
 | 
			
		||||
                    0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840,
 | 
			
		||||
                    0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45,
 | 
			
		||||
                    0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504,
 | 
			
		||||
                    0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a,
 | 
			
		||||
                    0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb,
 | 
			
		||||
                    0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee,
 | 
			
		||||
                    0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6,
 | 
			
		||||
                    0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42,
 | 
			
		||||
                    0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b,
 | 
			
		||||
                    0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2,
 | 
			
		||||
                    0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb,
 | 
			
		||||
                    0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527,
 | 
			
		||||
                    0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b,
 | 
			
		||||
                    0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33,
 | 
			
		||||
                    0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c,
 | 
			
		||||
                    0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3,
 | 
			
		||||
                    0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc,
 | 
			
		||||
                    0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17,
 | 
			
		||||
                    0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564,
 | 
			
		||||
                    0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b,
 | 
			
		||||
                    0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115,
 | 
			
		||||
                    0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922,
 | 
			
		||||
                    0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728,
 | 
			
		||||
                    0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0,
 | 
			
		||||
                    0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e,
 | 
			
		||||
                    0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37,
 | 
			
		||||
                    0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d,
 | 
			
		||||
                    0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804,
 | 
			
		||||
                    0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b,
 | 
			
		||||
                    0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3,
 | 
			
		||||
                    0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb,
 | 
			
		||||
                    0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d,
 | 
			
		||||
                    0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c,
 | 
			
		||||
                    0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350,
 | 
			
		||||
                    0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9,
 | 
			
		||||
                    0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a,
 | 
			
		||||
                    0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe,
 | 
			
		||||
                    0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d,
 | 
			
		||||
                    0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc,
 | 
			
		||||
                    0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f,
 | 
			
		||||
                    0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61,
 | 
			
		||||
                    0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2,
 | 
			
		||||
                    0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9,
 | 
			
		||||
                    0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2,
 | 
			
		||||
                    0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c,
 | 
			
		||||
                    0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e,
 | 
			
		||||
                    0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633,
 | 
			
		||||
                    0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10,
 | 
			
		||||
                    0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169,
 | 
			
		||||
                    0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52,
 | 
			
		||||
                    0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027,
 | 
			
		||||
                    0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5,
 | 
			
		||||
                    0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62,
 | 
			
		||||
                    0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634,
 | 
			
		||||
                    0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76,
 | 
			
		||||
                    0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24,
 | 
			
		||||
                    0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc,
 | 
			
		||||
                    0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4,
 | 
			
		||||
                    0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c,
 | 
			
		||||
                    0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837,
 | 
			
		||||
                    0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0},
 | 
			
		||||
                {
 | 
			
		||||
                    0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b,
 | 
			
		||||
                    0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe,
 | 
			
		||||
                    0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b,
 | 
			
		||||
                    0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4,
 | 
			
		||||
                    0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8,
 | 
			
		||||
                    0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6,
 | 
			
		||||
                    0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304,
 | 
			
		||||
                    0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22,
 | 
			
		||||
                    0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4,
 | 
			
		||||
                    0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6,
 | 
			
		||||
                    0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9,
 | 
			
		||||
                    0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59,
 | 
			
		||||
                    0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593,
 | 
			
		||||
                    0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51,
 | 
			
		||||
                    0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28,
 | 
			
		||||
                    0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c,
 | 
			
		||||
                    0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b,
 | 
			
		||||
                    0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28,
 | 
			
		||||
                    0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c,
 | 
			
		||||
                    0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd,
 | 
			
		||||
                    0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a,
 | 
			
		||||
                    0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319,
 | 
			
		||||
                    0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb,
 | 
			
		||||
                    0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f,
 | 
			
		||||
                    0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991,
 | 
			
		||||
                    0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32,
 | 
			
		||||
                    0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680,
 | 
			
		||||
                    0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166,
 | 
			
		||||
                    0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae,
 | 
			
		||||
                    0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb,
 | 
			
		||||
                    0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5,
 | 
			
		||||
                    0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47,
 | 
			
		||||
                    0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370,
 | 
			
		||||
                    0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d,
 | 
			
		||||
                    0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84,
 | 
			
		||||
                    0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048,
 | 
			
		||||
                    0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8,
 | 
			
		||||
                    0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd,
 | 
			
		||||
                    0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9,
 | 
			
		||||
                    0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7,
 | 
			
		||||
                    0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38,
 | 
			
		||||
                    0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f,
 | 
			
		||||
                    0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c,
 | 
			
		||||
                    0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525,
 | 
			
		||||
                    0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1,
 | 
			
		||||
                    0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442,
 | 
			
		||||
                    0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964,
 | 
			
		||||
                    0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e,
 | 
			
		||||
                    0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8,
 | 
			
		||||
                    0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d,
 | 
			
		||||
                    0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f,
 | 
			
		||||
                    0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299,
 | 
			
		||||
                    0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02,
 | 
			
		||||
                    0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc,
 | 
			
		||||
                    0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614,
 | 
			
		||||
                    0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a,
 | 
			
		||||
                    0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6,
 | 
			
		||||
                    0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b,
 | 
			
		||||
                    0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0,
 | 
			
		||||
                    0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060,
 | 
			
		||||
                    0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e,
 | 
			
		||||
                    0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9,
 | 
			
		||||
                    0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f,
 | 
			
		||||
                    0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6}
 | 
			
		||||
            },
 | 
			
		||||
          {
 | 
			
		||||
              0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344,
 | 
			
		||||
              0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89,
 | 
			
		||||
              0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c,
 | 
			
		||||
              0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917,
 | 
			
		||||
              0x9216d5d9, 0x8979fb1b
 | 
			
		||||
          } };
 | 
			
		||||
 | 
			
		||||
    *c = initstate;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint32_t
 | 
			
		||||
Blowfish_stream2word(const uint8_t *data, uint16_t databytes,
 | 
			
		||||
                     uint16_t *current)
 | 
			
		||||
{
 | 
			
		||||
    uint8_t i;
 | 
			
		||||
    uint16_t j;
 | 
			
		||||
    uint32_t temp;
 | 
			
		||||
 | 
			
		||||
    temp = 0x00000000;
 | 
			
		||||
    j = *current;
 | 
			
		||||
 | 
			
		||||
    for(i = 0; i < 4; i++, j++) {
 | 
			
		||||
        if(j >= databytes)
 | 
			
		||||
            j = 0;
 | 
			
		||||
        temp = (temp << 8) | data[j];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    *current = j;
 | 
			
		||||
    return temp;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
Blowfish_expand0state(blf_ctx *c, const uint8_t *key, uint16_t keybytes)
 | 
			
		||||
{
 | 
			
		||||
    uint16_t i;
 | 
			
		||||
    uint16_t j;
 | 
			
		||||
    uint16_t k;
 | 
			
		||||
    uint32_t temp;
 | 
			
		||||
    uint32_t datal;
 | 
			
		||||
    uint32_t datar;
 | 
			
		||||
 | 
			
		||||
    j = 0;
 | 
			
		||||
    for(i = 0; i < BLF_N + 2; i++) {
 | 
			
		||||
        /* Extract 4 int8 to 1 int32 from keystream */
 | 
			
		||||
        temp = Blowfish_stream2word(key, keybytes, &j);
 | 
			
		||||
        c->P[i] = c->P[i] ^ temp;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    j = 0;
 | 
			
		||||
    datal = 0x00000000;
 | 
			
		||||
    datar = 0x00000000;
 | 
			
		||||
    for(i = 0; i < BLF_N + 2; i += 2) {
 | 
			
		||||
        Blowfish_encipher(c, &datal, &datar);
 | 
			
		||||
 | 
			
		||||
        c->P[i] = datal;
 | 
			
		||||
        c->P[i + 1] = datar;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for(i = 0; i < 4; i++) {
 | 
			
		||||
        for(k = 0; k < 256; k += 2) {
 | 
			
		||||
            Blowfish_encipher(c, &datal, &datar);
 | 
			
		||||
 | 
			
		||||
            c->S[i][k] = datal;
 | 
			
		||||
            c->S[i][k + 1] = datar;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
Blowfish_expandstate(blf_ctx *c, const uint8_t *data, uint16_t databytes,
 | 
			
		||||
                     const uint8_t *key, uint16_t keybytes)
 | 
			
		||||
{
 | 
			
		||||
    uint16_t i;
 | 
			
		||||
    uint16_t j;
 | 
			
		||||
    uint16_t k;
 | 
			
		||||
    uint32_t temp;
 | 
			
		||||
    uint32_t datal;
 | 
			
		||||
    uint32_t datar;
 | 
			
		||||
 | 
			
		||||
    j = 0;
 | 
			
		||||
    for(i = 0; i < BLF_N + 2; i++) {
 | 
			
		||||
        /* Extract 4 int8 to 1 int32 from keystream */
 | 
			
		||||
        temp = Blowfish_stream2word(key, keybytes, &j);
 | 
			
		||||
        c->P[i] = c->P[i] ^ temp;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    j = 0;
 | 
			
		||||
    datal = 0x00000000;
 | 
			
		||||
    datar = 0x00000000;
 | 
			
		||||
    for(i = 0; i < BLF_N + 2; i += 2) {
 | 
			
		||||
        datal ^= Blowfish_stream2word(data, databytes, &j);
 | 
			
		||||
        datar ^= Blowfish_stream2word(data, databytes, &j);
 | 
			
		||||
        Blowfish_encipher(c, &datal, &datar);
 | 
			
		||||
 | 
			
		||||
        c->P[i] = datal;
 | 
			
		||||
        c->P[i + 1] = datar;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for(i = 0; i < 4; i++) {
 | 
			
		||||
        for(k = 0; k < 256; k += 2) {
 | 
			
		||||
            datal ^= Blowfish_stream2word(data, databytes, &j);
 | 
			
		||||
            datar ^= Blowfish_stream2word(data, databytes, &j);
 | 
			
		||||
            Blowfish_encipher(c, &datal, &datar);
 | 
			
		||||
 | 
			
		||||
            c->S[i][k] = datal;
 | 
			
		||||
            c->S[i][k + 1] = datar;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
blf_key(blf_ctx *c, const uint8_t *k, uint16_t len)
 | 
			
		||||
{
 | 
			
		||||
    /* Initialize S-boxes and subkeys with Pi */
 | 
			
		||||
    Blowfish_initstate(c);
 | 
			
		||||
 | 
			
		||||
    /* Transform S-boxes and subkeys with key */
 | 
			
		||||
    Blowfish_expand0state(c, k, len);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
blf_enc(blf_ctx *c, uint32_t *data, uint16_t blocks)
 | 
			
		||||
{
 | 
			
		||||
    uint32_t *d;
 | 
			
		||||
    uint16_t i;
 | 
			
		||||
 | 
			
		||||
    d = data;
 | 
			
		||||
    for(i = 0; i < blocks; i++) {
 | 
			
		||||
        Blowfish_encipher(c, d, d + 1);
 | 
			
		||||
        d += 2;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
blf_dec(blf_ctx *c, uint32_t *data, uint16_t blocks)
 | 
			
		||||
{
 | 
			
		||||
    uint32_t *d;
 | 
			
		||||
    uint16_t i;
 | 
			
		||||
 | 
			
		||||
    d = data;
 | 
			
		||||
    for(i = 0; i < blocks; i++) {
 | 
			
		||||
        Blowfish_decipher(c, d, d + 1);
 | 
			
		||||
        d += 2;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
blf_ecb_encrypt(blf_ctx *c, uint8_t *data, uint32_t len)
 | 
			
		||||
{
 | 
			
		||||
    uint32_t l, r;
 | 
			
		||||
    uint32_t i;
 | 
			
		||||
 | 
			
		||||
    for(i = 0; i < len; i += 8) {
 | 
			
		||||
        l = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];
 | 
			
		||||
        r = data[4] << 24 | data[5] << 16 | data[6] << 8 | data[7];
 | 
			
		||||
        Blowfish_encipher(c, &l, &r);
 | 
			
		||||
        data[0] = l >> 24 & 0xff;
 | 
			
		||||
        data[1] = l >> 16 & 0xff;
 | 
			
		||||
        data[2] = l >> 8 & 0xff;
 | 
			
		||||
        data[3] = l & 0xff;
 | 
			
		||||
        data[4] = r >> 24 & 0xff;
 | 
			
		||||
        data[5] = r >> 16 & 0xff;
 | 
			
		||||
        data[6] = r >> 8 & 0xff;
 | 
			
		||||
        data[7] = r & 0xff;
 | 
			
		||||
        data += 8;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
blf_ecb_decrypt(blf_ctx *c, uint8_t *data, uint32_t len)
 | 
			
		||||
{
 | 
			
		||||
    uint32_t l, r;
 | 
			
		||||
    uint32_t i;
 | 
			
		||||
 | 
			
		||||
    for(i = 0; i < len; i += 8) {
 | 
			
		||||
        l = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];
 | 
			
		||||
        r = data[4] << 24 | data[5] << 16 | data[6] << 8 | data[7];
 | 
			
		||||
        Blowfish_decipher(c, &l, &r);
 | 
			
		||||
        data[0] = l >> 24 & 0xff;
 | 
			
		||||
        data[1] = l >> 16 & 0xff;
 | 
			
		||||
        data[2] = l >> 8 & 0xff;
 | 
			
		||||
        data[3] = l & 0xff;
 | 
			
		||||
        data[4] = r >> 24 & 0xff;
 | 
			
		||||
        data[5] = r >> 16 & 0xff;
 | 
			
		||||
        data[6] = r >> 8 & 0xff;
 | 
			
		||||
        data[7] = r & 0xff;
 | 
			
		||||
        data += 8;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
blf_cbc_encrypt(blf_ctx *c, uint8_t *iv, uint8_t *data, uint32_t len)
 | 
			
		||||
{
 | 
			
		||||
    uint32_t l, r;
 | 
			
		||||
    uint32_t i, j;
 | 
			
		||||
 | 
			
		||||
    for(i = 0; i < len; i += 8) {
 | 
			
		||||
        for(j = 0; j < 8; j++)
 | 
			
		||||
            data[j] ^= iv[j];
 | 
			
		||||
        l = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];
 | 
			
		||||
        r = data[4] << 24 | data[5] << 16 | data[6] << 8 | data[7];
 | 
			
		||||
        Blowfish_encipher(c, &l, &r);
 | 
			
		||||
        data[0] = l >> 24 & 0xff;
 | 
			
		||||
        data[1] = l >> 16 & 0xff;
 | 
			
		||||
        data[2] = l >> 8 & 0xff;
 | 
			
		||||
        data[3] = l & 0xff;
 | 
			
		||||
        data[4] = r >> 24 & 0xff;
 | 
			
		||||
        data[5] = r >> 16 & 0xff;
 | 
			
		||||
        data[6] = r >> 8 & 0xff;
 | 
			
		||||
        data[7] = r & 0xff;
 | 
			
		||||
        iv = data;
 | 
			
		||||
        data += 8;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
blf_cbc_decrypt(blf_ctx *c, uint8_t *iva, uint8_t *data, uint32_t len)
 | 
			
		||||
{
 | 
			
		||||
    uint32_t l, r;
 | 
			
		||||
    uint8_t *iv;
 | 
			
		||||
    uint32_t i, j;
 | 
			
		||||
 | 
			
		||||
    iv = data + len - 16;
 | 
			
		||||
    data = data + len - 8;
 | 
			
		||||
    for(i = len - 8; i >= 8; i -= 8) {
 | 
			
		||||
        l = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];
 | 
			
		||||
        r = data[4] << 24 | data[5] << 16 | data[6] << 8 | data[7];
 | 
			
		||||
        Blowfish_decipher(c, &l, &r);
 | 
			
		||||
        data[0] = l >> 24 & 0xff;
 | 
			
		||||
        data[1] = l >> 16 & 0xff;
 | 
			
		||||
        data[2] = l >> 8 & 0xff;
 | 
			
		||||
        data[3] = l & 0xff;
 | 
			
		||||
        data[4] = r >> 24 & 0xff;
 | 
			
		||||
        data[5] = r >> 16 & 0xff;
 | 
			
		||||
        data[6] = r >> 8 & 0xff;
 | 
			
		||||
        data[7] = r & 0xff;
 | 
			
		||||
        for(j = 0; j < 8; j++)
 | 
			
		||||
            data[j] ^= iv[j];
 | 
			
		||||
        iv -= 8;
 | 
			
		||||
        data -= 8;
 | 
			
		||||
    }
 | 
			
		||||
    l = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];
 | 
			
		||||
    r = data[4] << 24 | data[5] << 16 | data[6] << 8 | data[7];
 | 
			
		||||
    Blowfish_decipher(c, &l, &r);
 | 
			
		||||
    data[0] = l >> 24 & 0xff;
 | 
			
		||||
    data[1] = l >> 16 & 0xff;
 | 
			
		||||
    data[2] = l >> 8 & 0xff;
 | 
			
		||||
    data[3] = l & 0xff;
 | 
			
		||||
    data[4] = r >> 24 & 0xff;
 | 
			
		||||
    data[5] = r >> 16 & 0xff;
 | 
			
		||||
    data[6] = r >> 8 & 0xff;
 | 
			
		||||
    data[7] = r & 0xff;
 | 
			
		||||
    for(j = 0; j < 8; j++)
 | 
			
		||||
        data[j] ^= iva[j];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#if 0
 | 
			
		||||
void
 | 
			
		||||
report(uint32_t data[], uint16_t len)
 | 
			
		||||
{
 | 
			
		||||
    uint16_t i;
 | 
			
		||||
    for(i = 0; i < len; i += 2)
 | 
			
		||||
        printf("Block %0hd: %08lx %08lx.\n",
 | 
			
		||||
               i / 2, data[i], data[i + 1]);
 | 
			
		||||
}
 | 
			
		||||
void
 | 
			
		||||
main(void)
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    blf_ctx c;
 | 
			
		||||
    char    key[] = "AAAAA";
 | 
			
		||||
    char    key2[] = "abcdefghijklmnopqrstuvwxyz";
 | 
			
		||||
 | 
			
		||||
    uint32_t data[10];
 | 
			
		||||
    uint32_t data2[] =
 | 
			
		||||
        {0x424c4f57l, 0x46495348l};
 | 
			
		||||
 | 
			
		||||
    uint16_t i;
 | 
			
		||||
 | 
			
		||||
    /* First test */
 | 
			
		||||
    for(i = 0; i < 10; i++)
 | 
			
		||||
        data[i] = i;
 | 
			
		||||
 | 
			
		||||
    blf_key(&c, (uint8_t *) key, 5);
 | 
			
		||||
    blf_enc(&c, data, 5);
 | 
			
		||||
    blf_dec(&c, data, 1);
 | 
			
		||||
    blf_dec(&c, data + 2, 4);
 | 
			
		||||
    printf("Should read as 0 - 9.\n");
 | 
			
		||||
    report(data, 10);
 | 
			
		||||
 | 
			
		||||
    /* Second test */
 | 
			
		||||
    blf_key(&c, (uint8_t *) key2, strlen(key2));
 | 
			
		||||
    blf_enc(&c, data2, 1);
 | 
			
		||||
    printf("\nShould read as: 0x324ed0fe 0xf413a203.\n");
 | 
			
		||||
    report(data2, 2);
 | 
			
		||||
    blf_dec(&c, data2, 1);
 | 
			
		||||
    report(data2, 2);
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif /* !defined(HAVE_BCRYPT_PBKDF) && \
 | 
			
		||||
          (!defined(HAVE_BLOWFISH_INITSTATE) ||   \
 | 
			
		||||
          !defined(HAVE_BLOWFISH_EXPAND0STATE) || \
 | 
			
		||||
          '!defined(HAVE_BLF_ENC)) */
 | 
			
		||||
#endif
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| 
						 | 
				
			
			@ -0,0 +1,143 @@
 | 
			
		|||
#if defined(ESP32)
 | 
			
		||||
#ifndef __LIBSSH2_CHANNEL_H
 | 
			
		||||
#define __LIBSSH2_CHANNEL_H
 | 
			
		||||
/* Copyright (c) 2008-2010 by Daniel Stenberg
 | 
			
		||||
 *
 | 
			
		||||
 * All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Redistribution and use in source and binary forms,
 | 
			
		||||
 * with or without modification, are permitted provided
 | 
			
		||||
 * that the following conditions are met:
 | 
			
		||||
 *
 | 
			
		||||
 *   Redistributions of source code must retain the above
 | 
			
		||||
 *   copyright notice, this list of conditions and the
 | 
			
		||||
 *   following disclaimer.
 | 
			
		||||
 *
 | 
			
		||||
 *   Redistributions in binary form must reproduce the above
 | 
			
		||||
 *   copyright notice, this list of conditions and the following
 | 
			
		||||
 *   disclaimer in the documentation and/or other materials
 | 
			
		||||
 *   provided with the distribution.
 | 
			
		||||
 *
 | 
			
		||||
 *   Neither the name of the copyright holder nor the names
 | 
			
		||||
 *   of any other contributors may be used to endorse or
 | 
			
		||||
 *   promote products derived from this software without
 | 
			
		||||
 *   specific prior written permission.
 | 
			
		||||
 *
 | 
			
		||||
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
 | 
			
		||||
 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 | 
			
		||||
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 | 
			
		||||
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 | 
			
		||||
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 | 
			
		||||
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | 
			
		||||
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 | 
			
		||||
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 | 
			
		||||
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 | 
			
		||||
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 | 
			
		||||
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 | 
			
		||||
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
 | 
			
		||||
 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
 | 
			
		||||
 * OF SUCH DAMAGE.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * _libssh2_channel_receive_window_adjust
 | 
			
		||||
 *
 | 
			
		||||
 * Adjust the receive window for a channel by adjustment bytes. If the amount
 | 
			
		||||
 * to be adjusted is less than LIBSSH2_CHANNEL_MINADJUST and force is 0 the
 | 
			
		||||
 * adjustment amount will be queued for a later packet.
 | 
			
		||||
 *
 | 
			
		||||
 * Always non-blocking.
 | 
			
		||||
 */
 | 
			
		||||
int _libssh2_channel_receive_window_adjust(LIBSSH2_CHANNEL * channel,
 | 
			
		||||
                                           uint32_t adjustment,
 | 
			
		||||
                                           unsigned char force,
 | 
			
		||||
                                           unsigned int *store);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * _libssh2_channel_flush
 | 
			
		||||
 *
 | 
			
		||||
 * Flush data from one (or all) stream
 | 
			
		||||
 * Returns number of bytes flushed, or negative on failure
 | 
			
		||||
 */
 | 
			
		||||
int _libssh2_channel_flush(LIBSSH2_CHANNEL *channel, int streamid);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * _libssh2_channel_free
 | 
			
		||||
 *
 | 
			
		||||
 * Make sure a channel is closed, then remove the channel from the session
 | 
			
		||||
 * and free its resource(s)
 | 
			
		||||
 *
 | 
			
		||||
 * Returns 0 on success, negative on failure
 | 
			
		||||
 */
 | 
			
		||||
int _libssh2_channel_free(LIBSSH2_CHANNEL *channel);
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
_libssh2_channel_extended_data(LIBSSH2_CHANNEL *channel, int ignore_mode);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * _libssh2_channel_write
 | 
			
		||||
 *
 | 
			
		||||
 * Send data to a channel
 | 
			
		||||
 */
 | 
			
		||||
ssize_t
 | 
			
		||||
_libssh2_channel_write(LIBSSH2_CHANNEL *channel, int stream_id,
 | 
			
		||||
                       const unsigned char *buf, size_t buflen);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * _libssh2_channel_open
 | 
			
		||||
 *
 | 
			
		||||
 * Establish a generic session channel
 | 
			
		||||
 */
 | 
			
		||||
LIBSSH2_CHANNEL *
 | 
			
		||||
_libssh2_channel_open(LIBSSH2_SESSION * session, const char *channel_type,
 | 
			
		||||
                      uint32_t channel_type_len,
 | 
			
		||||
                      uint32_t window_size,
 | 
			
		||||
                      uint32_t packet_size,
 | 
			
		||||
                      const unsigned char *message, size_t message_len);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * _libssh2_channel_process_startup
 | 
			
		||||
 *
 | 
			
		||||
 * Primitive for libssh2_channel_(shell|exec|subsystem)
 | 
			
		||||
 */
 | 
			
		||||
int
 | 
			
		||||
_libssh2_channel_process_startup(LIBSSH2_CHANNEL *channel,
 | 
			
		||||
                                 const char *request, size_t request_len,
 | 
			
		||||
                                 const char *message, size_t message_len);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * _libssh2_channel_read
 | 
			
		||||
 *
 | 
			
		||||
 * Read data from a channel
 | 
			
		||||
 *
 | 
			
		||||
 * It is important to not return 0 until the currently read channel is
 | 
			
		||||
 * complete. If we read stuff from the wire but it was no payload data to fill
 | 
			
		||||
 * in the buffer with, we MUST make sure to return PACKET_EAGAIN.
 | 
			
		||||
 */
 | 
			
		||||
ssize_t _libssh2_channel_read(LIBSSH2_CHANNEL *channel, int stream_id,
 | 
			
		||||
                              char *buf, size_t buflen);
 | 
			
		||||
 | 
			
		||||
uint32_t _libssh2_channel_nextid(LIBSSH2_SESSION * session);
 | 
			
		||||
 | 
			
		||||
LIBSSH2_CHANNEL *_libssh2_channel_locate(LIBSSH2_SESSION * session,
 | 
			
		||||
                                         uint32_t channel_id);
 | 
			
		||||
 | 
			
		||||
size_t _libssh2_channel_packet_data_len(LIBSSH2_CHANNEL * channel,
 | 
			
		||||
                                        int stream_id);
 | 
			
		||||
 | 
			
		||||
int _libssh2_channel_close(LIBSSH2_CHANNEL * channel);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * _libssh2_channel_forward_cancel
 | 
			
		||||
 *
 | 
			
		||||
 * Stop listening on a remote port and free the listener
 | 
			
		||||
 * Toss out any pending (un-accept()ed) connections
 | 
			
		||||
 *
 | 
			
		||||
 * Return 0 on success, LIBSSH2_ERROR_EAGAIN if would block, -1 on error
 | 
			
		||||
 */
 | 
			
		||||
int _libssh2_channel_forward_cancel(LIBSSH2_LISTENER *listener);
 | 
			
		||||
 | 
			
		||||
#endif /* __LIBSSH2_CHANNEL_H */
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,379 @@
 | 
			
		|||
#if defined(ESP32)
 | 
			
		||||
/* Copyright (c) 2004-2007, 2019, Sara Golemon <sarag@libssh2.org>
 | 
			
		||||
 * Copyright (c) 2010-2014, Daniel Stenberg <daniel@haxx.se>
 | 
			
		||||
 * All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Redistribution and use in source and binary forms,
 | 
			
		||||
 * with or without modification, are permitted provided
 | 
			
		||||
 * that the following conditions are met:
 | 
			
		||||
 *
 | 
			
		||||
 *   Redistributions of source code must retain the above
 | 
			
		||||
 *   copyright notice, this list of conditions and the
 | 
			
		||||
 *   following disclaimer.
 | 
			
		||||
 *
 | 
			
		||||
 *   Redistributions in binary form must reproduce the above
 | 
			
		||||
 *   copyright notice, this list of conditions and the following
 | 
			
		||||
 *   disclaimer in the documentation and/or other materials
 | 
			
		||||
 *   provided with the distribution.
 | 
			
		||||
 *
 | 
			
		||||
 *   Neither the name of the copyright holder nor the names
 | 
			
		||||
 *   of any other contributors may be used to endorse or
 | 
			
		||||
 *   promote products derived from this software without
 | 
			
		||||
 *   specific prior written permission.
 | 
			
		||||
 *
 | 
			
		||||
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
 | 
			
		||||
 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 | 
			
		||||
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 | 
			
		||||
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 | 
			
		||||
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 | 
			
		||||
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | 
			
		||||
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 | 
			
		||||
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 | 
			
		||||
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 | 
			
		||||
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 | 
			
		||||
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 | 
			
		||||
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
 | 
			
		||||
 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
 | 
			
		||||
 * OF SUCH DAMAGE.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "libssh2_priv.h"
 | 
			
		||||
#ifdef LIBSSH2_HAVE_ZLIB
 | 
			
		||||
#include <zlib.h>
 | 
			
		||||
#undef compress /* dodge name clash with ZLIB macro */
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include "comp.h"
 | 
			
		||||
 | 
			
		||||
/* ********
 | 
			
		||||
 * none *
 | 
			
		||||
 ******** */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * comp_method_none_comp
 | 
			
		||||
 *
 | 
			
		||||
 * Minimalist compression: Absolutely none
 | 
			
		||||
 */
 | 
			
		||||
static int
 | 
			
		||||
comp_method_none_comp(LIBSSH2_SESSION *session,
 | 
			
		||||
                      unsigned char *dest,
 | 
			
		||||
                      size_t *dest_len,
 | 
			
		||||
                      const unsigned char *src,
 | 
			
		||||
                      size_t src_len,
 | 
			
		||||
                      void **abstract)
 | 
			
		||||
{
 | 
			
		||||
    (void) session;
 | 
			
		||||
    (void) abstract;
 | 
			
		||||
    (void) dest;
 | 
			
		||||
    (void) dest_len;
 | 
			
		||||
    (void) src;
 | 
			
		||||
    (void) src_len;
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * comp_method_none_decomp
 | 
			
		||||
 *
 | 
			
		||||
 * Minimalist decompression: Absolutely none
 | 
			
		||||
 */
 | 
			
		||||
static int
 | 
			
		||||
comp_method_none_decomp(LIBSSH2_SESSION * session,
 | 
			
		||||
                        unsigned char **dest,
 | 
			
		||||
                        size_t *dest_len,
 | 
			
		||||
                        size_t payload_limit,
 | 
			
		||||
                        const unsigned char *src,
 | 
			
		||||
                        size_t src_len, void **abstract)
 | 
			
		||||
{
 | 
			
		||||
    (void) session;
 | 
			
		||||
    (void) payload_limit;
 | 
			
		||||
    (void) abstract;
 | 
			
		||||
    *dest = (unsigned char *) src;
 | 
			
		||||
    *dest_len = src_len;
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static const LIBSSH2_COMP_METHOD comp_method_none = {
 | 
			
		||||
    "none",
 | 
			
		||||
    0, /* not really compressing */
 | 
			
		||||
    0, /* isn't used in userauth, go figure */
 | 
			
		||||
    NULL,
 | 
			
		||||
    comp_method_none_comp,
 | 
			
		||||
    comp_method_none_decomp,
 | 
			
		||||
    NULL
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#ifdef LIBSSH2_HAVE_ZLIB
 | 
			
		||||
/* ********
 | 
			
		||||
 * zlib *
 | 
			
		||||
 ******** */
 | 
			
		||||
 | 
			
		||||
/* Memory management wrappers
 | 
			
		||||
 * Yes, I realize we're doing a callback to a callback,
 | 
			
		||||
 * Deal...
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
static voidpf
 | 
			
		||||
comp_method_zlib_alloc(voidpf opaque, uInt items, uInt size)
 | 
			
		||||
{
 | 
			
		||||
    LIBSSH2_SESSION *session = (LIBSSH2_SESSION *) opaque;
 | 
			
		||||
 | 
			
		||||
    return (voidpf) LIBSSH2_ALLOC(session, items * size);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
comp_method_zlib_free(voidpf opaque, voidpf address)
 | 
			
		||||
{
 | 
			
		||||
    LIBSSH2_SESSION *session = (LIBSSH2_SESSION *) opaque;
 | 
			
		||||
 | 
			
		||||
    LIBSSH2_FREE(session, address);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* libssh2_comp_method_zlib_init
 | 
			
		||||
 * All your bandwidth are belong to us (so save some)
 | 
			
		||||
 */
 | 
			
		||||
static int
 | 
			
		||||
comp_method_zlib_init(LIBSSH2_SESSION * session, int compr,
 | 
			
		||||
                      void **abstract)
 | 
			
		||||
{
 | 
			
		||||
    z_stream *strm;
 | 
			
		||||
    int status;
 | 
			
		||||
 | 
			
		||||
    strm = LIBSSH2_CALLOC(session, sizeof(z_stream));
 | 
			
		||||
    if(!strm) {
 | 
			
		||||
        return _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
 | 
			
		||||
                              "Unable to allocate memory for "
 | 
			
		||||
                              "zlib compression/decompression");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    strm->opaque = (voidpf) session;
 | 
			
		||||
    strm->zalloc = (alloc_func) comp_method_zlib_alloc;
 | 
			
		||||
    strm->zfree = (free_func) comp_method_zlib_free;
 | 
			
		||||
    if(compr) {
 | 
			
		||||
        /* deflate */
 | 
			
		||||
        status = deflateInit(strm, Z_DEFAULT_COMPRESSION);
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
        /* inflate */
 | 
			
		||||
        status = inflateInit(strm);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if(status != Z_OK) {
 | 
			
		||||
        LIBSSH2_FREE(session, strm);
 | 
			
		||||
        _libssh2_debug(session, LIBSSH2_TRACE_TRANS,
 | 
			
		||||
                       "unhandled zlib error %d", status);
 | 
			
		||||
        return LIBSSH2_ERROR_COMPRESS;
 | 
			
		||||
    }
 | 
			
		||||
    *abstract = strm;
 | 
			
		||||
 | 
			
		||||
    return LIBSSH2_ERROR_NONE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * libssh2_comp_method_zlib_comp
 | 
			
		||||
 *
 | 
			
		||||
 * Compresses source to destination. Without allocation.
 | 
			
		||||
 */
 | 
			
		||||
static int
 | 
			
		||||
comp_method_zlib_comp(LIBSSH2_SESSION *session,
 | 
			
		||||
                      unsigned char *dest,
 | 
			
		||||
 | 
			
		||||
                      /* dest_len is a pointer to allow this function to
 | 
			
		||||
                         update it with the final actual size used */
 | 
			
		||||
                      size_t *dest_len,
 | 
			
		||||
                      const unsigned char *src,
 | 
			
		||||
                      size_t src_len,
 | 
			
		||||
                      void **abstract)
 | 
			
		||||
{
 | 
			
		||||
    z_stream *strm = *abstract;
 | 
			
		||||
    int out_maxlen = *dest_len;
 | 
			
		||||
    int status;
 | 
			
		||||
 | 
			
		||||
    strm->next_in = (unsigned char *) src;
 | 
			
		||||
    strm->avail_in = src_len;
 | 
			
		||||
    strm->next_out = dest;
 | 
			
		||||
    strm->avail_out = out_maxlen;
 | 
			
		||||
 | 
			
		||||
    status = deflate(strm, Z_PARTIAL_FLUSH);
 | 
			
		||||
 | 
			
		||||
    if((status == Z_OK) && (strm->avail_out > 0)) {
 | 
			
		||||
        *dest_len = out_maxlen - strm->avail_out;
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _libssh2_debug(session, LIBSSH2_TRACE_TRANS,
 | 
			
		||||
                   "unhandled zlib compression error %d, avail_out",
 | 
			
		||||
                   status, strm->avail_out);
 | 
			
		||||
    return _libssh2_error(session, LIBSSH2_ERROR_ZLIB, "compression failure");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * libssh2_comp_method_zlib_decomp
 | 
			
		||||
 *
 | 
			
		||||
 * Decompresses source to destination. Allocates the output memory.
 | 
			
		||||
 */
 | 
			
		||||
static int
 | 
			
		||||
comp_method_zlib_decomp(LIBSSH2_SESSION * session,
 | 
			
		||||
                        unsigned char **dest,
 | 
			
		||||
                        size_t *dest_len,
 | 
			
		||||
                        size_t payload_limit,
 | 
			
		||||
                        const unsigned char *src,
 | 
			
		||||
                        size_t src_len, void **abstract)
 | 
			
		||||
{
 | 
			
		||||
    z_stream *strm = *abstract;
 | 
			
		||||
    /* A short-term alloc of a full data chunk is better than a series of
 | 
			
		||||
       reallocs */
 | 
			
		||||
    char *out;
 | 
			
		||||
    size_t out_maxlen = src_len;
 | 
			
		||||
 | 
			
		||||
    if(src_len <= SIZE_MAX / 4)
 | 
			
		||||
        out_maxlen = src_len * 4;
 | 
			
		||||
    else
 | 
			
		||||
        out_maxlen = payload_limit;
 | 
			
		||||
 | 
			
		||||
    /* If strm is null, then we have not yet been initialized. */
 | 
			
		||||
    if(strm == NULL)
 | 
			
		||||
        return _libssh2_error(session, LIBSSH2_ERROR_COMPRESS,
 | 
			
		||||
                              "decompression uninitialized");;
 | 
			
		||||
 | 
			
		||||
    /* In practice they never come smaller than this */
 | 
			
		||||
    if(out_maxlen < 25)
 | 
			
		||||
        out_maxlen = 25;
 | 
			
		||||
 | 
			
		||||
    if(out_maxlen > payload_limit)
 | 
			
		||||
        out_maxlen = payload_limit;
 | 
			
		||||
 | 
			
		||||
    strm->next_in = (unsigned char *) src;
 | 
			
		||||
    strm->avail_in = src_len;
 | 
			
		||||
    strm->next_out = (unsigned char *) LIBSSH2_ALLOC(session, out_maxlen);
 | 
			
		||||
    out = (char *) strm->next_out;
 | 
			
		||||
    strm->avail_out = out_maxlen;
 | 
			
		||||
    if(!strm->next_out)
 | 
			
		||||
        return _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
 | 
			
		||||
                              "Unable to allocate decompression buffer");
 | 
			
		||||
 | 
			
		||||
    /* Loop until it's all inflated or hit error */
 | 
			
		||||
    for(;;) {
 | 
			
		||||
        int status;
 | 
			
		||||
        size_t out_ofs;
 | 
			
		||||
        char *newout;
 | 
			
		||||
 | 
			
		||||
        status = inflate(strm, Z_PARTIAL_FLUSH);
 | 
			
		||||
 | 
			
		||||
        if(status == Z_OK) {
 | 
			
		||||
            if(strm->avail_out > 0)
 | 
			
		||||
                /* status is OK and the output buffer has not been exhausted
 | 
			
		||||
                   so we're done */
 | 
			
		||||
                break;
 | 
			
		||||
        }
 | 
			
		||||
        else if(status == Z_BUF_ERROR) {
 | 
			
		||||
            /* the input data has been exhausted so we are done */
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            /* error state */
 | 
			
		||||
            LIBSSH2_FREE(session, out);
 | 
			
		||||
            _libssh2_debug(session, LIBSSH2_TRACE_TRANS,
 | 
			
		||||
                           "unhandled zlib error %d", status);
 | 
			
		||||
            return _libssh2_error(session, LIBSSH2_ERROR_ZLIB,
 | 
			
		||||
                                  "decompression failure");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if(out_maxlen > payload_limit || out_maxlen > SIZE_MAX / 2) {
 | 
			
		||||
            LIBSSH2_FREE(session, out);
 | 
			
		||||
            return _libssh2_error(session, LIBSSH2_ERROR_ZLIB,
 | 
			
		||||
                                  "Excessive growth in decompression phase");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /* If we get here we need to grow the output buffer and try again */
 | 
			
		||||
        out_ofs = out_maxlen - strm->avail_out;
 | 
			
		||||
        out_maxlen *= 2;
 | 
			
		||||
        newout = LIBSSH2_REALLOC(session, out, out_maxlen);
 | 
			
		||||
        if(!newout) {
 | 
			
		||||
            LIBSSH2_FREE(session, out);
 | 
			
		||||
            return _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
 | 
			
		||||
                                  "Unable to expand decompression buffer");
 | 
			
		||||
        }
 | 
			
		||||
        out = newout;
 | 
			
		||||
        strm->next_out = (unsigned char *) out + out_ofs;
 | 
			
		||||
        strm->avail_out = out_maxlen - out_ofs;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    *dest = (unsigned char *) out;
 | 
			
		||||
    *dest_len = out_maxlen - strm->avail_out;
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* libssh2_comp_method_zlib_dtor
 | 
			
		||||
 * All done, no more compression for you
 | 
			
		||||
 */
 | 
			
		||||
static int
 | 
			
		||||
comp_method_zlib_dtor(LIBSSH2_SESSION *session, int compr, void **abstract)
 | 
			
		||||
{
 | 
			
		||||
    z_stream *strm = *abstract;
 | 
			
		||||
 | 
			
		||||
    if(strm) {
 | 
			
		||||
        if(compr)
 | 
			
		||||
            deflateEnd(strm);
 | 
			
		||||
        else
 | 
			
		||||
            inflateEnd(strm);
 | 
			
		||||
        LIBSSH2_FREE(session, strm);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    *abstract = NULL;
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const LIBSSH2_COMP_METHOD comp_method_zlib = {
 | 
			
		||||
    "zlib",
 | 
			
		||||
    1, /* yes, this compresses */
 | 
			
		||||
    1, /* do compression during userauth */
 | 
			
		||||
    comp_method_zlib_init,
 | 
			
		||||
    comp_method_zlib_comp,
 | 
			
		||||
    comp_method_zlib_decomp,
 | 
			
		||||
    comp_method_zlib_dtor,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const LIBSSH2_COMP_METHOD comp_method_zlib_openssh = {
 | 
			
		||||
    "zlib@openssh.com",
 | 
			
		||||
    1, /* yes, this compresses */
 | 
			
		||||
    0, /* don't use compression during userauth */
 | 
			
		||||
    comp_method_zlib_init,
 | 
			
		||||
    comp_method_zlib_comp,
 | 
			
		||||
    comp_method_zlib_decomp,
 | 
			
		||||
    comp_method_zlib_dtor,
 | 
			
		||||
};
 | 
			
		||||
#endif /* LIBSSH2_HAVE_ZLIB */
 | 
			
		||||
 | 
			
		||||
/* If compression is enabled by the API, then this array is used which then
 | 
			
		||||
   may allow compression if zlib is available at build time */
 | 
			
		||||
static const LIBSSH2_COMP_METHOD *comp_methods[] = {
 | 
			
		||||
#ifdef LIBSSH2_HAVE_ZLIB
 | 
			
		||||
    &comp_method_zlib,
 | 
			
		||||
    &comp_method_zlib_openssh,
 | 
			
		||||
#endif /* LIBSSH2_HAVE_ZLIB */
 | 
			
		||||
    &comp_method_none,
 | 
			
		||||
    NULL
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* If compression is disabled by the API, then this array is used */
 | 
			
		||||
static const LIBSSH2_COMP_METHOD *no_comp_methods[] = {
 | 
			
		||||
    &comp_method_none,
 | 
			
		||||
    NULL
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const LIBSSH2_COMP_METHOD **
 | 
			
		||||
_libssh2_comp_methods(LIBSSH2_SESSION *session)
 | 
			
		||||
{
 | 
			
		||||
    if(session->flag.compress)
 | 
			
		||||
        return comp_methods;
 | 
			
		||||
    else
 | 
			
		||||
        return no_comp_methods;
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,46 @@
 | 
			
		|||
#if defined(ESP32)
 | 
			
		||||
#ifndef __LIBSSH2_COMP_H
 | 
			
		||||
#define __LIBSSH2_COMP_H
 | 
			
		||||
/* Copyright (C) 2009-2010 by Daniel Stenberg
 | 
			
		||||
 *
 | 
			
		||||
 * Redistribution and use in source and binary forms,
 | 
			
		||||
 * with or without modification, are permitted provided
 | 
			
		||||
 * that the following conditions are met:
 | 
			
		||||
 *
 | 
			
		||||
 *   Redistributions of source code must retain the above
 | 
			
		||||
 *   copyright notice, this list of conditions and the
 | 
			
		||||
 *   following disclaimer.
 | 
			
		||||
 *
 | 
			
		||||
 *   Redistributions in binary form must reproduce the above
 | 
			
		||||
 *   copyright notice, this list of conditions and the following
 | 
			
		||||
 *   disclaimer in the documentation and/or other materials
 | 
			
		||||
 *   provided with the distribution.
 | 
			
		||||
 *
 | 
			
		||||
 *   Neither the name of the copyright holder nor the names
 | 
			
		||||
 *   of any other contributors may be used to endorse or
 | 
			
		||||
 *   promote products derived from this software without
 | 
			
		||||
 *   specific prior written permission.
 | 
			
		||||
 *
 | 
			
		||||
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
 | 
			
		||||
 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 | 
			
		||||
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 | 
			
		||||
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 | 
			
		||||
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 | 
			
		||||
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | 
			
		||||
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 | 
			
		||||
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 | 
			
		||||
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 | 
			
		||||
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 | 
			
		||||
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 | 
			
		||||
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
 | 
			
		||||
 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
 | 
			
		||||
 * OF SUCH DAMAGE.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "libssh2_priv.h"
 | 
			
		||||
 | 
			
		||||
const LIBSSH2_COMP_METHOD **_libssh2_comp_methods(LIBSSH2_SESSION *session);
 | 
			
		||||
 | 
			
		||||
#endif /* __LIBSSH2_COMP_H */
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,353 @@
 | 
			
		|||
#if defined(ESP32)
 | 
			
		||||
/* Copyright (c) 2009, 2010 Simon Josefsson <simon@josefsson.org>
 | 
			
		||||
 * Copyright (c) 2004-2007, Sara Golemon <sarag@libssh2.org>
 | 
			
		||||
 * All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Redistribution and use in source and binary forms,
 | 
			
		||||
 * with or without modification, are permitted provided
 | 
			
		||||
 * that the following conditions are met:
 | 
			
		||||
 *
 | 
			
		||||
 *   Redistributions of source code must retain the above
 | 
			
		||||
 *   copyright notice, this list of conditions and the
 | 
			
		||||
 *   following disclaimer.
 | 
			
		||||
 *
 | 
			
		||||
 *   Redistributions in binary form must reproduce the above
 | 
			
		||||
 *   copyright notice, this list of conditions and the following
 | 
			
		||||
 *   disclaimer in the documentation and/or other materials
 | 
			
		||||
 *   provided with the distribution.
 | 
			
		||||
 *
 | 
			
		||||
 *   Neither the name of the copyright holder nor the names
 | 
			
		||||
 *   of any other contributors may be used to endorse or
 | 
			
		||||
 *   promote products derived from this software without
 | 
			
		||||
 *   specific prior written permission.
 | 
			
		||||
 *
 | 
			
		||||
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
 | 
			
		||||
 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 | 
			
		||||
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 | 
			
		||||
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 | 
			
		||||
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 | 
			
		||||
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | 
			
		||||
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 | 
			
		||||
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 | 
			
		||||
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 | 
			
		||||
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 | 
			
		||||
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 | 
			
		||||
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
 | 
			
		||||
 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
 | 
			
		||||
 * OF SUCH DAMAGE.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "libssh2_priv.h"
 | 
			
		||||
 | 
			
		||||
#ifdef LIBSSH2_CRYPT_NONE
 | 
			
		||||
 | 
			
		||||
/* crypt_none_crypt
 | 
			
		||||
 * Minimalist cipher: VERY secure *wink*
 | 
			
		||||
 */
 | 
			
		||||
static int
 | 
			
		||||
crypt_none_crypt(LIBSSH2_SESSION * session, unsigned char *buf,
 | 
			
		||||
                         void **abstract)
 | 
			
		||||
{
 | 
			
		||||
    /* Do nothing to the data! */
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_none = {
 | 
			
		||||
    "none",
 | 
			
		||||
    "DEK-Info: NONE",
 | 
			
		||||
    8,                /* blocksize (SSH2 defines minimum blocksize as 8) */
 | 
			
		||||
    0,                /* iv_len */
 | 
			
		||||
    0,                /* secret_len */
 | 
			
		||||
    0,                /* flags */
 | 
			
		||||
    NULL,
 | 
			
		||||
    crypt_none_crypt,
 | 
			
		||||
    NULL
 | 
			
		||||
};
 | 
			
		||||
#endif /* LIBSSH2_CRYPT_NONE */
 | 
			
		||||
 | 
			
		||||
struct crypt_ctx
 | 
			
		||||
{
 | 
			
		||||
    int encrypt;
 | 
			
		||||
    _libssh2_cipher_type(algo);
 | 
			
		||||
    _libssh2_cipher_ctx h;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
crypt_init(LIBSSH2_SESSION * session,
 | 
			
		||||
           const LIBSSH2_CRYPT_METHOD * method,
 | 
			
		||||
           unsigned char *iv, int *free_iv,
 | 
			
		||||
           unsigned char *secret, int *free_secret,
 | 
			
		||||
           int encrypt, void **abstract)
 | 
			
		||||
{
 | 
			
		||||
    struct crypt_ctx *ctx = LIBSSH2_ALLOC(session,
 | 
			
		||||
                                          sizeof(struct crypt_ctx));
 | 
			
		||||
    if(!ctx)
 | 
			
		||||
        return LIBSSH2_ERROR_ALLOC;
 | 
			
		||||
 | 
			
		||||
    ctx->encrypt = encrypt;
 | 
			
		||||
    ctx->algo = method->algo;
 | 
			
		||||
    if(_libssh2_cipher_init(&ctx->h, ctx->algo, iv, secret, encrypt)) {
 | 
			
		||||
        LIBSSH2_FREE(session, ctx);
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
    *abstract = ctx;
 | 
			
		||||
    *free_iv = 1;
 | 
			
		||||
    *free_secret = 1;
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
crypt_encrypt(LIBSSH2_SESSION * session, unsigned char *block,
 | 
			
		||||
              size_t blocksize, void **abstract)
 | 
			
		||||
{
 | 
			
		||||
    struct crypt_ctx *cctx = *(struct crypt_ctx **) abstract;
 | 
			
		||||
    (void) session;
 | 
			
		||||
    return _libssh2_cipher_crypt(&cctx->h, cctx->algo, cctx->encrypt, block,
 | 
			
		||||
                                 blocksize);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
crypt_dtor(LIBSSH2_SESSION * session, void **abstract)
 | 
			
		||||
{
 | 
			
		||||
    struct crypt_ctx **cctx = (struct crypt_ctx **) abstract;
 | 
			
		||||
    if(cctx && *cctx) {
 | 
			
		||||
        _libssh2_cipher_dtor(&(*cctx)->h);
 | 
			
		||||
        LIBSSH2_FREE(session, *cctx);
 | 
			
		||||
        *abstract = NULL;
 | 
			
		||||
    }
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#if LIBSSH2_AES_CTR
 | 
			
		||||
static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_aes128_ctr = {
 | 
			
		||||
    "aes128-ctr",
 | 
			
		||||
    "",
 | 
			
		||||
    16,                         /* blocksize */
 | 
			
		||||
    16,                         /* initial value length */
 | 
			
		||||
    16,                         /* secret length -- 16*8 == 128bit */
 | 
			
		||||
    0,                          /* flags */
 | 
			
		||||
    &crypt_init,
 | 
			
		||||
    &crypt_encrypt,
 | 
			
		||||
    &crypt_dtor,
 | 
			
		||||
    _libssh2_cipher_aes128ctr
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_aes192_ctr = {
 | 
			
		||||
    "aes192-ctr",
 | 
			
		||||
    "",
 | 
			
		||||
    16,                         /* blocksize */
 | 
			
		||||
    16,                         /* initial value length */
 | 
			
		||||
    24,                         /* secret length -- 24*8 == 192bit */
 | 
			
		||||
    0,                          /* flags */
 | 
			
		||||
    &crypt_init,
 | 
			
		||||
    &crypt_encrypt,
 | 
			
		||||
    &crypt_dtor,
 | 
			
		||||
    _libssh2_cipher_aes192ctr
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_aes256_ctr = {
 | 
			
		||||
    "aes256-ctr",
 | 
			
		||||
    "",
 | 
			
		||||
    16,                         /* blocksize */
 | 
			
		||||
    16,                         /* initial value length */
 | 
			
		||||
    32,                         /* secret length -- 32*8 == 256bit */
 | 
			
		||||
    0,                          /* flags */
 | 
			
		||||
    &crypt_init,
 | 
			
		||||
    &crypt_encrypt,
 | 
			
		||||
    &crypt_dtor,
 | 
			
		||||
    _libssh2_cipher_aes256ctr
 | 
			
		||||
};
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if LIBSSH2_AES
 | 
			
		||||
static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_aes128_cbc = {
 | 
			
		||||
    "aes128-cbc",
 | 
			
		||||
    "DEK-Info: AES-128-CBC",
 | 
			
		||||
    16,                         /* blocksize */
 | 
			
		||||
    16,                         /* initial value length */
 | 
			
		||||
    16,                         /* secret length -- 16*8 == 128bit */
 | 
			
		||||
    0,                          /* flags */
 | 
			
		||||
    &crypt_init,
 | 
			
		||||
    &crypt_encrypt,
 | 
			
		||||
    &crypt_dtor,
 | 
			
		||||
    _libssh2_cipher_aes128
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_aes192_cbc = {
 | 
			
		||||
    "aes192-cbc",
 | 
			
		||||
    "DEK-Info: AES-192-CBC",
 | 
			
		||||
    16,                         /* blocksize */
 | 
			
		||||
    16,                         /* initial value length */
 | 
			
		||||
    24,                         /* secret length -- 24*8 == 192bit */
 | 
			
		||||
    0,                          /* flags */
 | 
			
		||||
    &crypt_init,
 | 
			
		||||
    &crypt_encrypt,
 | 
			
		||||
    &crypt_dtor,
 | 
			
		||||
    _libssh2_cipher_aes192
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_aes256_cbc = {
 | 
			
		||||
    "aes256-cbc",
 | 
			
		||||
    "DEK-Info: AES-256-CBC",
 | 
			
		||||
    16,                         /* blocksize */
 | 
			
		||||
    16,                         /* initial value length */
 | 
			
		||||
    32,                         /* secret length -- 32*8 == 256bit */
 | 
			
		||||
    0,                          /* flags */
 | 
			
		||||
    &crypt_init,
 | 
			
		||||
    &crypt_encrypt,
 | 
			
		||||
    &crypt_dtor,
 | 
			
		||||
    _libssh2_cipher_aes256
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* rijndael-cbc@lysator.liu.se == aes256-cbc */
 | 
			
		||||
static const LIBSSH2_CRYPT_METHOD
 | 
			
		||||
    libssh2_crypt_method_rijndael_cbc_lysator_liu_se = {
 | 
			
		||||
    "rijndael-cbc@lysator.liu.se",
 | 
			
		||||
    "DEK-Info: AES-256-CBC",
 | 
			
		||||
    16,                         /* blocksize */
 | 
			
		||||
    16,                         /* initial value length */
 | 
			
		||||
    32,                         /* secret length -- 32*8 == 256bit */
 | 
			
		||||
    0,                          /* flags */
 | 
			
		||||
    &crypt_init,
 | 
			
		||||
    &crypt_encrypt,
 | 
			
		||||
    &crypt_dtor,
 | 
			
		||||
    _libssh2_cipher_aes256
 | 
			
		||||
};
 | 
			
		||||
#endif /* LIBSSH2_AES */
 | 
			
		||||
 | 
			
		||||
#if LIBSSH2_BLOWFISH
 | 
			
		||||
static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_blowfish_cbc = {
 | 
			
		||||
    "blowfish-cbc",
 | 
			
		||||
    "",
 | 
			
		||||
    8,                          /* blocksize */
 | 
			
		||||
    8,                          /* initial value length */
 | 
			
		||||
    16,                         /* secret length */
 | 
			
		||||
    0,                          /* flags */
 | 
			
		||||
    &crypt_init,
 | 
			
		||||
    &crypt_encrypt,
 | 
			
		||||
    &crypt_dtor,
 | 
			
		||||
    _libssh2_cipher_blowfish
 | 
			
		||||
};
 | 
			
		||||
#endif /* LIBSSH2_BLOWFISH */
 | 
			
		||||
 | 
			
		||||
#if LIBSSH2_RC4
 | 
			
		||||
static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_arcfour = {
 | 
			
		||||
    "arcfour",
 | 
			
		||||
    "DEK-Info: RC4",
 | 
			
		||||
    8,                          /* blocksize */
 | 
			
		||||
    8,                          /* initial value length */
 | 
			
		||||
    16,                         /* secret length */
 | 
			
		||||
    0,                          /* flags */
 | 
			
		||||
    &crypt_init,
 | 
			
		||||
    &crypt_encrypt,
 | 
			
		||||
    &crypt_dtor,
 | 
			
		||||
    _libssh2_cipher_arcfour
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
crypt_init_arcfour128(LIBSSH2_SESSION * session,
 | 
			
		||||
                      const LIBSSH2_CRYPT_METHOD * method,
 | 
			
		||||
                      unsigned char *iv, int *free_iv,
 | 
			
		||||
                      unsigned char *secret, int *free_secret,
 | 
			
		||||
                      int encrypt, void **abstract)
 | 
			
		||||
{
 | 
			
		||||
    int rc;
 | 
			
		||||
 | 
			
		||||
    rc = crypt_init(session, method, iv, free_iv, secret, free_secret,
 | 
			
		||||
                    encrypt, abstract);
 | 
			
		||||
    if(rc == 0) {
 | 
			
		||||
        struct crypt_ctx *cctx = *(struct crypt_ctx **) abstract;
 | 
			
		||||
        unsigned char block[8];
 | 
			
		||||
        size_t discard = 1536;
 | 
			
		||||
        for(; discard; discard -= 8)
 | 
			
		||||
            _libssh2_cipher_crypt(&cctx->h, cctx->algo, cctx->encrypt, block,
 | 
			
		||||
                                  method->blocksize);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return rc;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_arcfour128 = {
 | 
			
		||||
    "arcfour128",
 | 
			
		||||
    "",
 | 
			
		||||
    8,                          /* blocksize */
 | 
			
		||||
    8,                          /* initial value length */
 | 
			
		||||
    16,                         /* secret length */
 | 
			
		||||
    0,                          /* flags */
 | 
			
		||||
    &crypt_init_arcfour128,
 | 
			
		||||
    &crypt_encrypt,
 | 
			
		||||
    &crypt_dtor,
 | 
			
		||||
    _libssh2_cipher_arcfour
 | 
			
		||||
};
 | 
			
		||||
#endif /* LIBSSH2_RC4 */
 | 
			
		||||
 | 
			
		||||
#if LIBSSH2_CAST
 | 
			
		||||
static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_cast128_cbc = {
 | 
			
		||||
    "cast128-cbc",
 | 
			
		||||
    "",
 | 
			
		||||
    8,                          /* blocksize */
 | 
			
		||||
    8,                          /* initial value length */
 | 
			
		||||
    16,                         /* secret length */
 | 
			
		||||
    0,                          /* flags */
 | 
			
		||||
    &crypt_init,
 | 
			
		||||
    &crypt_encrypt,
 | 
			
		||||
    &crypt_dtor,
 | 
			
		||||
    _libssh2_cipher_cast5
 | 
			
		||||
};
 | 
			
		||||
#endif /* LIBSSH2_CAST */
 | 
			
		||||
 | 
			
		||||
#if LIBSSH2_3DES
 | 
			
		||||
static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_3des_cbc = {
 | 
			
		||||
    "3des-cbc",
 | 
			
		||||
    "DEK-Info: DES-EDE3-CBC",
 | 
			
		||||
    8,                          /* blocksize */
 | 
			
		||||
    8,                          /* initial value length */
 | 
			
		||||
    24,                         /* secret length */
 | 
			
		||||
    0,                          /* flags */
 | 
			
		||||
    &crypt_init,
 | 
			
		||||
    &crypt_encrypt,
 | 
			
		||||
    &crypt_dtor,
 | 
			
		||||
    _libssh2_cipher_3des
 | 
			
		||||
};
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/* These are the crypt methods that are available to be negotiated. Methods
 | 
			
		||||
   towards the start are chosen in preference to ones further down the list. */
 | 
			
		||||
static const LIBSSH2_CRYPT_METHOD *_libssh2_crypt_methods[] = {
 | 
			
		||||
#if LIBSSH2_AES_CTR
 | 
			
		||||
  &libssh2_crypt_method_aes256_ctr,
 | 
			
		||||
  &libssh2_crypt_method_aes192_ctr,
 | 
			
		||||
  &libssh2_crypt_method_aes128_ctr,
 | 
			
		||||
#endif /* LIBSSH2_AES */
 | 
			
		||||
#if LIBSSH2_AES
 | 
			
		||||
    &libssh2_crypt_method_aes256_cbc,
 | 
			
		||||
    &libssh2_crypt_method_rijndael_cbc_lysator_liu_se,  /* == aes256-cbc */
 | 
			
		||||
    &libssh2_crypt_method_aes192_cbc,
 | 
			
		||||
    &libssh2_crypt_method_aes128_cbc,
 | 
			
		||||
#endif /* LIBSSH2_AES */
 | 
			
		||||
#if LIBSSH2_BLOWFISH
 | 
			
		||||
    &libssh2_crypt_method_blowfish_cbc,
 | 
			
		||||
#endif /* LIBSSH2_BLOWFISH */
 | 
			
		||||
#if LIBSSH2_RC4
 | 
			
		||||
    &libssh2_crypt_method_arcfour128,
 | 
			
		||||
    &libssh2_crypt_method_arcfour,
 | 
			
		||||
#endif /* LIBSSH2_RC4 */
 | 
			
		||||
#if LIBSSH2_CAST
 | 
			
		||||
    &libssh2_crypt_method_cast128_cbc,
 | 
			
		||||
#endif /* LIBSSH2_CAST */
 | 
			
		||||
#if LIBSSH2_3DES
 | 
			
		||||
    &libssh2_crypt_method_3des_cbc,
 | 
			
		||||
#endif /*  LIBSSH2_DES */
 | 
			
		||||
#ifdef LIBSSH2_CRYPT_NONE
 | 
			
		||||
    &libssh2_crypt_method_none,
 | 
			
		||||
#endif
 | 
			
		||||
    NULL
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* Expose to kex.c */
 | 
			
		||||
const LIBSSH2_CRYPT_METHOD **
 | 
			
		||||
libssh2_crypt_methods(void)
 | 
			
		||||
{
 | 
			
		||||
    return _libssh2_crypt_methods;
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,338 @@
 | 
			
		|||
#if defined(ESP32)
 | 
			
		||||
#ifndef __LIBSSH2_CRYPTO_H
 | 
			
		||||
#define __LIBSSH2_CRYPTO_H
 | 
			
		||||
/* Copyright (C) 2009, 2010 Simon Josefsson
 | 
			
		||||
 * Copyright (C) 2006, 2007 The Written Word, Inc.  All rights reserved.
 | 
			
		||||
 * Copyright (C) 2010-2019 Daniel Stenberg
 | 
			
		||||
 *
 | 
			
		||||
 * Redistribution and use in source and binary forms,
 | 
			
		||||
 * with or without modification, are permitted provided
 | 
			
		||||
 * that the following conditions are met:
 | 
			
		||||
 *
 | 
			
		||||
 *   Redistributions of source code must retain the above
 | 
			
		||||
 *   copyright notice, this list of conditions and the
 | 
			
		||||
 *   following disclaimer.
 | 
			
		||||
 *
 | 
			
		||||
 *   Redistributions in binary form must reproduce the above
 | 
			
		||||
 *   copyright notice, this list of conditions and the following
 | 
			
		||||
 *   disclaimer in the documentation and/or other materials
 | 
			
		||||
 *   provided with the distribution.
 | 
			
		||||
 *
 | 
			
		||||
 *   Neither the name of the copyright holder nor the names
 | 
			
		||||
 *   of any other contributors may be used to endorse or
 | 
			
		||||
 *   promote products derived from this software without
 | 
			
		||||
 *   specific prior written permission.
 | 
			
		||||
 *
 | 
			
		||||
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
 | 
			
		||||
 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 | 
			
		||||
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 | 
			
		||||
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 | 
			
		||||
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 | 
			
		||||
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | 
			
		||||
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 | 
			
		||||
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 | 
			
		||||
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 | 
			
		||||
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 | 
			
		||||
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 | 
			
		||||
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
 | 
			
		||||
 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
 | 
			
		||||
 * OF SUCH DAMAGE.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#if defined(LIBSSH2_OPENSSL) || defined(LIBSSH2_WOLFSSL)
 | 
			
		||||
#include "openssl.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef LIBSSH2_LIBGCRYPT
 | 
			
		||||
#include "libgcrypt.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef LIBSSH2_WINCNG
 | 
			
		||||
#include "wincng.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef LIBSSH2_OS400QC3
 | 
			
		||||
#include "os400qc3.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef LIBSSH2_MBEDTLS
 | 
			
		||||
#include "mbedtls.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define LIBSSH2_ED25519_KEY_LEN 32
 | 
			
		||||
#define LIBSSH2_ED25519_PRIVATE_KEY_LEN 64
 | 
			
		||||
#define LIBSSH2_ED25519_SIG_LEN 64
 | 
			
		||||
 | 
			
		||||
#if LIBSSH2_RSA
 | 
			
		||||
int _libssh2_rsa_new(libssh2_rsa_ctx ** rsa,
 | 
			
		||||
                     const unsigned char *edata,
 | 
			
		||||
                     unsigned long elen,
 | 
			
		||||
                     const unsigned char *ndata,
 | 
			
		||||
                     unsigned long nlen,
 | 
			
		||||
                     const unsigned char *ddata,
 | 
			
		||||
                     unsigned long dlen,
 | 
			
		||||
                     const unsigned char *pdata,
 | 
			
		||||
                     unsigned long plen,
 | 
			
		||||
                     const unsigned char *qdata,
 | 
			
		||||
                     unsigned long qlen,
 | 
			
		||||
                     const unsigned char *e1data,
 | 
			
		||||
                     unsigned long e1len,
 | 
			
		||||
                     const unsigned char *e2data,
 | 
			
		||||
                     unsigned long e2len,
 | 
			
		||||
                     const unsigned char *coeffdata, unsigned long coefflen);
 | 
			
		||||
int _libssh2_rsa_new_private(libssh2_rsa_ctx ** rsa,
 | 
			
		||||
                             LIBSSH2_SESSION * session,
 | 
			
		||||
                             const char *filename,
 | 
			
		||||
                             unsigned const char *passphrase);
 | 
			
		||||
int _libssh2_rsa_sha1_verify(libssh2_rsa_ctx * rsa,
 | 
			
		||||
                             const unsigned char *sig,
 | 
			
		||||
                             unsigned long sig_len,
 | 
			
		||||
                             const unsigned char *m, unsigned long m_len);
 | 
			
		||||
int _libssh2_rsa_sha1_sign(LIBSSH2_SESSION * session,
 | 
			
		||||
                           libssh2_rsa_ctx * rsactx,
 | 
			
		||||
                           const unsigned char *hash,
 | 
			
		||||
                           size_t hash_len,
 | 
			
		||||
                           unsigned char **signature,
 | 
			
		||||
                           size_t *signature_len);
 | 
			
		||||
#if LIBSSH2_RSA_SHA2
 | 
			
		||||
int _libssh2_rsa_sha2_sign(LIBSSH2_SESSION * session,
 | 
			
		||||
                           libssh2_rsa_ctx * rsactx,
 | 
			
		||||
                           const unsigned char *hash,
 | 
			
		||||
                           size_t hash_len,
 | 
			
		||||
                           unsigned char **signature,
 | 
			
		||||
                           size_t *signature_len);
 | 
			
		||||
int _libssh2_rsa_sha2_verify(libssh2_rsa_ctx * rsa,
 | 
			
		||||
                             size_t hash_len,
 | 
			
		||||
                             const unsigned char *sig,
 | 
			
		||||
                             unsigned long sig_len,
 | 
			
		||||
                             const unsigned char *m, unsigned long m_len);
 | 
			
		||||
#endif
 | 
			
		||||
int _libssh2_rsa_new_private_frommemory(libssh2_rsa_ctx ** rsa,
 | 
			
		||||
                                        LIBSSH2_SESSION * session,
 | 
			
		||||
                                        const char *filedata,
 | 
			
		||||
                                        size_t filedata_len,
 | 
			
		||||
                                        unsigned const char *passphrase);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if LIBSSH2_DSA
 | 
			
		||||
int _libssh2_dsa_new(libssh2_dsa_ctx ** dsa,
 | 
			
		||||
                     const unsigned char *pdata,
 | 
			
		||||
                     unsigned long plen,
 | 
			
		||||
                     const unsigned char *qdata,
 | 
			
		||||
                     unsigned long qlen,
 | 
			
		||||
                     const unsigned char *gdata,
 | 
			
		||||
                     unsigned long glen,
 | 
			
		||||
                     const unsigned char *ydata,
 | 
			
		||||
                     unsigned long ylen,
 | 
			
		||||
                     const unsigned char *x, unsigned long x_len);
 | 
			
		||||
int _libssh2_dsa_new_private(libssh2_dsa_ctx ** dsa,
 | 
			
		||||
                             LIBSSH2_SESSION * session,
 | 
			
		||||
                             const char *filename,
 | 
			
		||||
                             unsigned const char *passphrase);
 | 
			
		||||
int _libssh2_dsa_sha1_verify(libssh2_dsa_ctx * dsactx,
 | 
			
		||||
                             const unsigned char *sig,
 | 
			
		||||
                             const unsigned char *m, unsigned long m_len);
 | 
			
		||||
int _libssh2_dsa_sha1_sign(libssh2_dsa_ctx * dsactx,
 | 
			
		||||
                           const unsigned char *hash,
 | 
			
		||||
                           unsigned long hash_len, unsigned char *sig);
 | 
			
		||||
int _libssh2_dsa_new_private_frommemory(libssh2_dsa_ctx ** dsa,
 | 
			
		||||
                                        LIBSSH2_SESSION * session,
 | 
			
		||||
                                        const char *filedata,
 | 
			
		||||
                                        size_t filedata_len,
 | 
			
		||||
                                        unsigned const char *passphrase);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if LIBSSH2_ECDSA
 | 
			
		||||
int
 | 
			
		||||
_libssh2_ecdsa_curve_name_with_octal_new(libssh2_ecdsa_ctx ** ecdsactx,
 | 
			
		||||
                                         const unsigned char *k,
 | 
			
		||||
                                         size_t k_len,
 | 
			
		||||
                                         libssh2_curve_type type);
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
_libssh2_ecdsa_new_private(libssh2_ecdsa_ctx ** ec_ctx,
 | 
			
		||||
                           LIBSSH2_SESSION * session,
 | 
			
		||||
                           const char *filename,
 | 
			
		||||
                           unsigned const char *passphrase);
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
_libssh2_ecdsa_new_private_sk(libssh2_ecdsa_ctx ** ec_ctx,
 | 
			
		||||
                              unsigned char *flags,
 | 
			
		||||
                              const char **application,
 | 
			
		||||
                              const unsigned char **key_handle,
 | 
			
		||||
                              size_t *handle_len,
 | 
			
		||||
                              LIBSSH2_SESSION * session,
 | 
			
		||||
                              const char *filename,
 | 
			
		||||
                              unsigned const char *passphrase);
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
_libssh2_ecdsa_verify(libssh2_ecdsa_ctx * ctx,
 | 
			
		||||
                      const unsigned char *r, size_t r_len,
 | 
			
		||||
                      const unsigned char *s, size_t s_len,
 | 
			
		||||
                      const unsigned char *m, size_t m_len);
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
_libssh2_ecdsa_create_key(LIBSSH2_SESSION *session,
 | 
			
		||||
                          _libssh2_ec_key **out_private_key,
 | 
			
		||||
                          unsigned char **out_public_key_octal,
 | 
			
		||||
                          size_t *out_public_key_octal_len,
 | 
			
		||||
                          libssh2_curve_type curve_type);
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
_libssh2_ecdh_gen_k(_libssh2_bn **k, _libssh2_ec_key *private_key,
 | 
			
		||||
                    const unsigned char *server_public_key,
 | 
			
		||||
                    size_t server_public_key_len);
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
_libssh2_ecdsa_sign(LIBSSH2_SESSION *session, libssh2_ecdsa_ctx *ec_ctx,
 | 
			
		||||
                    const unsigned char *hash, unsigned long hash_len,
 | 
			
		||||
                    unsigned char **signature, size_t *signature_len);
 | 
			
		||||
 | 
			
		||||
int _libssh2_ecdsa_new_private_frommemory(libssh2_ecdsa_ctx ** ec_ctx,
 | 
			
		||||
                                          LIBSSH2_SESSION * session,
 | 
			
		||||
                                          const char *filedata,
 | 
			
		||||
                                          size_t filedata_len,
 | 
			
		||||
                                          unsigned const char *passphrase);
 | 
			
		||||
 | 
			
		||||
int _libssh2_ecdsa_new_private_frommemory_sk(libssh2_ecdsa_ctx ** ec_ctx,
 | 
			
		||||
                                             unsigned char *flags,
 | 
			
		||||
                                             const char **application,
 | 
			
		||||
                                             const unsigned char **key_handle,
 | 
			
		||||
                                             size_t *handle_len,
 | 
			
		||||
                                             LIBSSH2_SESSION * session,
 | 
			
		||||
                                             const char *filedata,
 | 
			
		||||
                                             size_t filedata_len,
 | 
			
		||||
                                             unsigned const char *passphrase);
 | 
			
		||||
 | 
			
		||||
libssh2_curve_type
 | 
			
		||||
_libssh2_ecdsa_get_curve_type(libssh2_ecdsa_ctx *ec_ctx);
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
_libssh2_ecdsa_curve_type_from_name(const char *name,
 | 
			
		||||
                                    libssh2_curve_type *out_type);
 | 
			
		||||
 | 
			
		||||
#endif /* LIBSSH2_ECDSA */
 | 
			
		||||
 | 
			
		||||
#if LIBSSH2_ED25519
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
_libssh2_curve25519_new(LIBSSH2_SESSION *session, uint8_t **out_public_key,
 | 
			
		||||
                        uint8_t **out_private_key);
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
_libssh2_curve25519_gen_k(_libssh2_bn **k,
 | 
			
		||||
                          uint8_t private_key[LIBSSH2_ED25519_KEY_LEN],
 | 
			
		||||
                          uint8_t server_public_key[LIBSSH2_ED25519_KEY_LEN]);
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
_libssh2_ed25519_verify(libssh2_ed25519_ctx *ctx, const uint8_t *s,
 | 
			
		||||
                        size_t s_len, const uint8_t *m, size_t m_len);
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
_libssh2_ed25519_new_private(libssh2_ed25519_ctx **ed_ctx,
 | 
			
		||||
                            LIBSSH2_SESSION *session,
 | 
			
		||||
                            const char *filename, const uint8_t *passphrase);
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
_libssh2_ed25519_new_private_sk(libssh2_ed25519_ctx **ed_ctx,
 | 
			
		||||
                                unsigned char *flags,
 | 
			
		||||
                                const char **application,
 | 
			
		||||
                                const unsigned char **key_handle,
 | 
			
		||||
                                size_t *handle_len,
 | 
			
		||||
                                LIBSSH2_SESSION *session,
 | 
			
		||||
                                const char *filename,
 | 
			
		||||
                                const uint8_t *passphrase);
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
_libssh2_ed25519_new_public(libssh2_ed25519_ctx **ed_ctx,
 | 
			
		||||
                            LIBSSH2_SESSION *session,
 | 
			
		||||
                            const unsigned char *raw_pub_key,
 | 
			
		||||
                            const uint8_t key_len);
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
_libssh2_ed25519_sign(libssh2_ed25519_ctx *ctx, LIBSSH2_SESSION *session,
 | 
			
		||||
                      uint8_t **out_sig, size_t *out_sig_len,
 | 
			
		||||
                      const uint8_t *message, size_t message_len);
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
_libssh2_ed25519_new_private_frommemory(libssh2_ed25519_ctx **ed_ctx,
 | 
			
		||||
                                        LIBSSH2_SESSION *session,
 | 
			
		||||
                                        const char *filedata,
 | 
			
		||||
                                        size_t filedata_len,
 | 
			
		||||
                                        unsigned const char *passphrase);
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
_libssh2_ed25519_new_private_frommemory_sk(libssh2_ed25519_ctx **ed_ctx,
 | 
			
		||||
                                           unsigned char *flags,
 | 
			
		||||
                                           const char **application,
 | 
			
		||||
                                           const unsigned char **key_handle,
 | 
			
		||||
                                           size_t *handle_len,
 | 
			
		||||
                                           LIBSSH2_SESSION *session,
 | 
			
		||||
                                           const char *filedata,
 | 
			
		||||
                                           size_t filedata_len,
 | 
			
		||||
                                           unsigned const char *passphrase);
 | 
			
		||||
 | 
			
		||||
#endif /* LIBSSH2_ED25519 */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
int _libssh2_cipher_init(_libssh2_cipher_ctx * h,
 | 
			
		||||
                         _libssh2_cipher_type(algo),
 | 
			
		||||
                         unsigned char *iv,
 | 
			
		||||
                         unsigned char *secret, int encrypt);
 | 
			
		||||
 | 
			
		||||
int _libssh2_cipher_crypt(_libssh2_cipher_ctx * ctx,
 | 
			
		||||
                          _libssh2_cipher_type(algo),
 | 
			
		||||
                          int encrypt, unsigned char *block, size_t blocksize);
 | 
			
		||||
 | 
			
		||||
int _libssh2_pub_priv_keyfile(LIBSSH2_SESSION *session,
 | 
			
		||||
                              unsigned char **method,
 | 
			
		||||
                              size_t *method_len,
 | 
			
		||||
                              unsigned char **pubkeydata,
 | 
			
		||||
                              size_t *pubkeydata_len,
 | 
			
		||||
                              const char *privatekey,
 | 
			
		||||
                              const char *passphrase);
 | 
			
		||||
 | 
			
		||||
int _libssh2_pub_priv_keyfilememory(LIBSSH2_SESSION *session,
 | 
			
		||||
                                    unsigned char **method,
 | 
			
		||||
                                    size_t *method_len,
 | 
			
		||||
                                    unsigned char **pubkeydata,
 | 
			
		||||
                                    size_t *pubkeydata_len,
 | 
			
		||||
                                    const char *privatekeydata,
 | 
			
		||||
                                    size_t privatekeydata_len,
 | 
			
		||||
                                    const char *passphrase);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
int _libssh2_sk_pub_keyfilememory(LIBSSH2_SESSION *session,
 | 
			
		||||
                                  unsigned char **method,
 | 
			
		||||
                                  size_t *method_len,
 | 
			
		||||
                                  unsigned char **pubkeydata,
 | 
			
		||||
                                  size_t *pubkeydata_len,
 | 
			
		||||
                                  int *algorithm,
 | 
			
		||||
                                  unsigned char *flags,
 | 
			
		||||
                                  const char **application,
 | 
			
		||||
                                  const unsigned char **key_handle,
 | 
			
		||||
                                  size_t *handle_len,
 | 
			
		||||
                                  const char *privatekeydata,
 | 
			
		||||
                                  size_t privatekeydata_len,
 | 
			
		||||
                                  const char *passphrase);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @function _libssh2_supported_key_sign_algorithms
 | 
			
		||||
 * @abstract Returns supported algorithms used for upgrading public
 | 
			
		||||
 * key signing RFC 8332
 | 
			
		||||
 * @discussion Based on the incoming key_method value, this function
 | 
			
		||||
 * will return supported algorithms that can upgrade the key method
 | 
			
		||||
 * @related _libssh2_key_sign_algorithm()
 | 
			
		||||
 * @param key_method current key method, usually the default key sig method
 | 
			
		||||
 * @param key_method_len length of the key method buffer
 | 
			
		||||
 * @result comma seperated list of supported upgrade options per RFC 8332, if
 | 
			
		||||
 * there is no upgrade option return NULL
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
const char *
 | 
			
		||||
_libssh2_supported_key_sign_algorithms(LIBSSH2_SESSION *session,
 | 
			
		||||
                                       unsigned char *key_method,
 | 
			
		||||
                                       size_t key_method_len);
 | 
			
		||||
 | 
			
		||||
#endif /* __LIBSSH2_CRYPTO_H */
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,80 @@
 | 
			
		|||
#if defined(ESP32)
 | 
			
		||||
/* Copyright (c) 2010 Lars Nordin <Lars.Nordin@SDlabs.se>
 | 
			
		||||
 * Copyright (C) 2010 Simon Josefsson <simon@josefsson.org>
 | 
			
		||||
 * All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Redistribution and use in source and binary forms,
 | 
			
		||||
 * with or without modification, are permitted provided
 | 
			
		||||
 * that the following conditions are met:
 | 
			
		||||
 *
 | 
			
		||||
 *   Redistributions of source code must retain the above
 | 
			
		||||
 *   copyright notice, this list of conditions and the
 | 
			
		||||
 *   following disclaimer.
 | 
			
		||||
 *
 | 
			
		||||
 *   Redistributions in binary form must reproduce the above
 | 
			
		||||
 *   copyright notice, this list of conditions and the following
 | 
			
		||||
 *   disclaimer in the documentation and/or other materials
 | 
			
		||||
 *   provided with the distribution.
 | 
			
		||||
 *
 | 
			
		||||
 *   Neither the name of the copyright holder nor the names
 | 
			
		||||
 *   of any other contributors may be used to endorse or
 | 
			
		||||
 *   promote products derived from this software without
 | 
			
		||||
 *   specific prior written permission.
 | 
			
		||||
 *
 | 
			
		||||
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
 | 
			
		||||
 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 | 
			
		||||
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 | 
			
		||||
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 | 
			
		||||
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 | 
			
		||||
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | 
			
		||||
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 | 
			
		||||
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 | 
			
		||||
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 | 
			
		||||
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 | 
			
		||||
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 | 
			
		||||
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
 | 
			
		||||
 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
 | 
			
		||||
 * OF SUCH DAMAGE.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "libssh2_priv.h"
 | 
			
		||||
 | 
			
		||||
static int _libssh2_initialized = 0;
 | 
			
		||||
static int _libssh2_init_flags = 0;
 | 
			
		||||
 | 
			
		||||
LIBSSH2_API int
 | 
			
		||||
libssh2_init(int flags)
 | 
			
		||||
{
 | 
			
		||||
    if(_libssh2_initialized == 0 && !(flags & LIBSSH2_INIT_NO_CRYPTO)) {
 | 
			
		||||
        libssh2_crypto_init();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _libssh2_initialized++;
 | 
			
		||||
    _libssh2_init_flags |= flags;
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
LIBSSH2_API void
 | 
			
		||||
libssh2_exit(void)
 | 
			
		||||
{
 | 
			
		||||
    if(_libssh2_initialized == 0)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    _libssh2_initialized--;
 | 
			
		||||
 | 
			
		||||
    if(_libssh2_initialized == 0 &&
 | 
			
		||||
       !(_libssh2_init_flags & LIBSSH2_INIT_NO_CRYPTO)) {
 | 
			
		||||
        libssh2_crypto_exit();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
_libssh2_init_if_needed(void)
 | 
			
		||||
{
 | 
			
		||||
    if(_libssh2_initialized == 0)
 | 
			
		||||
        (void)libssh2_init (0);
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| 
						 | 
				
			
			@ -0,0 +1,102 @@
 | 
			
		|||
#if defined(ESP32)
 | 
			
		||||
/* Copyright (C) 2010  Simon Josefsson
 | 
			
		||||
 * Author: Simon Josefsson
 | 
			
		||||
 *
 | 
			
		||||
 * Redistribution and use in source and binary forms,
 | 
			
		||||
 * with or without modification, are permitted provided
 | 
			
		||||
 * that the following conditions are met:
 | 
			
		||||
 *
 | 
			
		||||
 *   Redistributions of source code must retain the above
 | 
			
		||||
 *   copyright notice, this list of conditions and the
 | 
			
		||||
 *   following disclaimer.
 | 
			
		||||
 *
 | 
			
		||||
 *   Redistributions in binary form must reproduce the above
 | 
			
		||||
 *   copyright notice, this list of conditions and the following
 | 
			
		||||
 *   disclaimer in the documentation and/or other materials
 | 
			
		||||
 *   provided with the distribution.
 | 
			
		||||
 *
 | 
			
		||||
 *   Neither the name of the copyright holder nor the names
 | 
			
		||||
 *   of any other contributors may be used to endorse or
 | 
			
		||||
 *   promote products derived from this software without
 | 
			
		||||
 *   specific prior written permission.
 | 
			
		||||
 *
 | 
			
		||||
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
 | 
			
		||||
 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 | 
			
		||||
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 | 
			
		||||
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 | 
			
		||||
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 | 
			
		||||
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | 
			
		||||
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 | 
			
		||||
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 | 
			
		||||
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 | 
			
		||||
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 | 
			
		||||
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 | 
			
		||||
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
 | 
			
		||||
 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
 | 
			
		||||
 * OF SUCH DAMAGE.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "libssh2_priv.h"
 | 
			
		||||
#include "transport.h" /* _libssh2_transport_write */
 | 
			
		||||
 | 
			
		||||
/* Keep-alive stuff. */
 | 
			
		||||
 | 
			
		||||
LIBSSH2_API void
 | 
			
		||||
libssh2_keepalive_config (LIBSSH2_SESSION *session,
 | 
			
		||||
                          int want_reply,
 | 
			
		||||
                          unsigned interval)
 | 
			
		||||
{
 | 
			
		||||
    if(interval == 1)
 | 
			
		||||
        session->keepalive_interval = 2;
 | 
			
		||||
    else
 | 
			
		||||
        session->keepalive_interval = interval;
 | 
			
		||||
    session->keepalive_want_reply = want_reply ? 1 : 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
LIBSSH2_API int
 | 
			
		||||
libssh2_keepalive_send (LIBSSH2_SESSION *session,
 | 
			
		||||
                        int *seconds_to_next)
 | 
			
		||||
{
 | 
			
		||||
    time_t now;
 | 
			
		||||
 | 
			
		||||
    if(!session->keepalive_interval) {
 | 
			
		||||
        if(seconds_to_next)
 | 
			
		||||
            *seconds_to_next = 0;
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    now = time(NULL);
 | 
			
		||||
 | 
			
		||||
    if(session->keepalive_last_sent + session->keepalive_interval <= now) {
 | 
			
		||||
        /* Format is
 | 
			
		||||
           "SSH_MSG_GLOBAL_REQUEST || 4-byte len || str || want-reply". */
 | 
			
		||||
        unsigned char keepalive_data[]
 | 
			
		||||
            = "\x50\x00\x00\x00\x15keepalive@libssh2.orgW";
 | 
			
		||||
        size_t len = sizeof(keepalive_data) - 1;
 | 
			
		||||
        int rc;
 | 
			
		||||
 | 
			
		||||
        keepalive_data[len - 1] =
 | 
			
		||||
            (unsigned char)session->keepalive_want_reply;
 | 
			
		||||
 | 
			
		||||
        rc = _libssh2_transport_send(session, keepalive_data, len, NULL, 0);
 | 
			
		||||
        /* Silently ignore PACKET_EAGAIN here: if the write buffer is
 | 
			
		||||
           already full, sending another keepalive is not useful. */
 | 
			
		||||
        if(rc && rc != LIBSSH2_ERROR_EAGAIN) {
 | 
			
		||||
            _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
 | 
			
		||||
                           "Unable to send keepalive message");
 | 
			
		||||
            return rc;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        session->keepalive_last_sent = now;
 | 
			
		||||
        if(seconds_to_next)
 | 
			
		||||
            *seconds_to_next = session->keepalive_interval;
 | 
			
		||||
    }
 | 
			
		||||
    else if(seconds_to_next) {
 | 
			
		||||
        *seconds_to_next = (int) (session->keepalive_last_sent - now)
 | 
			
		||||
            + session->keepalive_interval;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| 
						 | 
				
			
			@ -0,0 +1,240 @@
 | 
			
		|||
#if defined(ESP32)
 | 
			
		||||
#ifndef __LIBSSH2_LIBGCRYPT_H
 | 
			
		||||
#define __LIBSSH2_LIBGCRYPT_H
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2008, 2009, 2010 Simon Josefsson
 | 
			
		||||
 * Copyright (C) 2006, 2007, The Written Word, Inc.
 | 
			
		||||
 * All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Redistribution and use in source and binary forms,
 | 
			
		||||
 * with or without modification, are permitted provided
 | 
			
		||||
 * that the following conditions are met:
 | 
			
		||||
 *
 | 
			
		||||
 *   Redistributions of source code must retain the above
 | 
			
		||||
 *   copyright notice, this list of conditions and the
 | 
			
		||||
 *   following disclaimer.
 | 
			
		||||
 *
 | 
			
		||||
 *   Redistributions in binary form must reproduce the above
 | 
			
		||||
 *   copyright notice, this list of conditions and the following
 | 
			
		||||
 *   disclaimer in the documentation and/or other materials
 | 
			
		||||
 *   provided with the distribution.
 | 
			
		||||
 *
 | 
			
		||||
 *   Neither the name of the copyright holder nor the names
 | 
			
		||||
 *   of any other contributors may be used to endorse or
 | 
			
		||||
 *   promote products derived from this software without
 | 
			
		||||
 *   specific prior written permission.
 | 
			
		||||
 *
 | 
			
		||||
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
 | 
			
		||||
 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 | 
			
		||||
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 | 
			
		||||
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 | 
			
		||||
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 | 
			
		||||
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | 
			
		||||
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 | 
			
		||||
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 | 
			
		||||
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 | 
			
		||||
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 | 
			
		||||
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 | 
			
		||||
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
 | 
			
		||||
 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
 | 
			
		||||
 * OF SUCH DAMAGE.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <gcrypt.h>
 | 
			
		||||
 | 
			
		||||
#define LIBSSH2_MD5 1
 | 
			
		||||
 | 
			
		||||
#define LIBSSH2_HMAC_RIPEMD 1
 | 
			
		||||
#define LIBSSH2_HMAC_SHA256 1
 | 
			
		||||
#define LIBSSH2_HMAC_SHA512 1
 | 
			
		||||
 | 
			
		||||
#define LIBSSH2_AES 1
 | 
			
		||||
#define LIBSSH2_AES_CTR 1
 | 
			
		||||
#define LIBSSH2_BLOWFISH 1
 | 
			
		||||
#define LIBSSH2_RC4 1
 | 
			
		||||
#define LIBSSH2_CAST 1
 | 
			
		||||
#define LIBSSH2_3DES 1
 | 
			
		||||
 | 
			
		||||
#define LIBSSH2_RSA 1
 | 
			
		||||
#define LIBSSH2_RSA_SHA2 0
 | 
			
		||||
#define LIBSSH2_DSA 1
 | 
			
		||||
#define LIBSSH2_ECDSA 0
 | 
			
		||||
#define LIBSSH2_ED25519 0
 | 
			
		||||
 | 
			
		||||
#define MD5_DIGEST_LENGTH 16
 | 
			
		||||
#define SHA_DIGEST_LENGTH 20
 | 
			
		||||
#define SHA256_DIGEST_LENGTH 32
 | 
			
		||||
#define SHA384_DIGEST_LENGTH 48
 | 
			
		||||
#define SHA512_DIGEST_LENGTH 64
 | 
			
		||||
 | 
			
		||||
#define EC_MAX_POINT_LEN ((528 * 2 / 8) + 1)
 | 
			
		||||
 | 
			
		||||
#define _libssh2_random(buf, len)                \
 | 
			
		||||
  (gcry_randomize ((buf), (len), GCRY_STRONG_RANDOM), 0)
 | 
			
		||||
 | 
			
		||||
#define libssh2_prepare_iovec(vec, len)  /* Empty. */
 | 
			
		||||
 | 
			
		||||
#define libssh2_sha1_ctx gcry_md_hd_t
 | 
			
		||||
 | 
			
		||||
/* returns 0 in case of failure */
 | 
			
		||||
#define libssh2_sha1_init(ctx) \
 | 
			
		||||
  (GPG_ERR_NO_ERROR == gcry_md_open(ctx,  GCRY_MD_SHA1, 0))
 | 
			
		||||
#define libssh2_sha1_update(ctx, data, len) \
 | 
			
		||||
  gcry_md_write(ctx, (unsigned char *) data, len)
 | 
			
		||||
#define libssh2_sha1_final(ctx, out) \
 | 
			
		||||
  memcpy(out, gcry_md_read(ctx, 0), SHA_DIGEST_LENGTH), gcry_md_close(ctx)
 | 
			
		||||
#define libssh2_sha1(message, len, out) \
 | 
			
		||||
  gcry_md_hash_buffer(GCRY_MD_SHA1, out, message, len)
 | 
			
		||||
 | 
			
		||||
#define libssh2_sha256_ctx gcry_md_hd_t
 | 
			
		||||
 | 
			
		||||
#define libssh2_sha256_init(ctx) \
 | 
			
		||||
  (GPG_ERR_NO_ERROR == gcry_md_open(ctx,  GCRY_MD_SHA256, 0))
 | 
			
		||||
#define libssh2_sha256_update(ctx, data, len) \
 | 
			
		||||
  gcry_md_write(ctx, (unsigned char *) data, len)
 | 
			
		||||
#define libssh2_sha256_final(ctx, out) \
 | 
			
		||||
  memcpy(out, gcry_md_read(ctx, 0), SHA256_DIGEST_LENGTH), gcry_md_close(ctx)
 | 
			
		||||
#define libssh2_sha256(message, len, out) \
 | 
			
		||||
  gcry_md_hash_buffer(GCRY_MD_SHA256, out, message, len)
 | 
			
		||||
 | 
			
		||||
#define libssh2_sha384_ctx gcry_md_hd_t
 | 
			
		||||
 | 
			
		||||
#define libssh2_sha384_init(ctx) \
 | 
			
		||||
  (GPG_ERR_NO_ERROR == gcry_md_open(ctx,  GCRY_MD_SHA384, 0))
 | 
			
		||||
#define libssh2_sha384_update(ctx, data, len) \
 | 
			
		||||
  gcry_md_write(ctx, (unsigned char *) data, len)
 | 
			
		||||
#define libssh2_sha384_final(ctx, out) \
 | 
			
		||||
  memcpy(out, gcry_md_read(ctx, 0), SHA384_DIGEST_LENGTH), gcry_md_close(ctx)
 | 
			
		||||
#define libssh2_sha384(message, len, out) \
 | 
			
		||||
  gcry_md_hash_buffer(GCRY_MD_SHA384, out, message, len)
 | 
			
		||||
 | 
			
		||||
#define libssh2_sha512_ctx gcry_md_hd_t
 | 
			
		||||
 | 
			
		||||
#define libssh2_sha512_init(ctx) \
 | 
			
		||||
  (GPG_ERR_NO_ERROR == gcry_md_open(ctx,  GCRY_MD_SHA512, 0))
 | 
			
		||||
#define libssh2_sha512_update(ctx, data, len) \
 | 
			
		||||
  gcry_md_write(ctx, (unsigned char *) data, len)
 | 
			
		||||
#define libssh2_sha512_final(ctx, out) \
 | 
			
		||||
  memcpy(out, gcry_md_read(ctx, 0), SHA512_DIGEST_LENGTH), gcry_md_close(ctx)
 | 
			
		||||
#define libssh2_sha512(message, len, out) \
 | 
			
		||||
  gcry_md_hash_buffer(GCRY_MD_SHA512, out, message, len)
 | 
			
		||||
 | 
			
		||||
#define libssh2_md5_ctx gcry_md_hd_t
 | 
			
		||||
 | 
			
		||||
/* returns 0 in case of failure */
 | 
			
		||||
#define libssh2_md5_init(ctx) \
 | 
			
		||||
  (GPG_ERR_NO_ERROR == gcry_md_open(ctx,  GCRY_MD_MD5, 0))
 | 
			
		||||
 | 
			
		||||
#define libssh2_md5_update(ctx, data, len) \
 | 
			
		||||
  gcry_md_write(ctx, (unsigned char *) data, len)
 | 
			
		||||
#define libssh2_md5_final(ctx, out) \
 | 
			
		||||
  memcpy(out, gcry_md_read(ctx, 0), MD5_DIGEST_LENGTH), gcry_md_close(ctx)
 | 
			
		||||
#define libssh2_md5(message, len, out) \
 | 
			
		||||
  gcry_md_hash_buffer(GCRY_MD_MD5, out, message, len)
 | 
			
		||||
 | 
			
		||||
#define libssh2_hmac_ctx gcry_md_hd_t
 | 
			
		||||
#define libssh2_hmac_ctx_init(ctx)
 | 
			
		||||
#define libssh2_hmac_sha1_init(ctx, key, keylen) \
 | 
			
		||||
  gcry_md_open(ctx, GCRY_MD_SHA1, GCRY_MD_FLAG_HMAC), \
 | 
			
		||||
    gcry_md_setkey(*ctx, key, keylen)
 | 
			
		||||
#define libssh2_hmac_md5_init(ctx, key, keylen) \
 | 
			
		||||
  gcry_md_open(ctx, GCRY_MD_MD5, GCRY_MD_FLAG_HMAC), \
 | 
			
		||||
    gcry_md_setkey(*ctx, key, keylen)
 | 
			
		||||
#define libssh2_hmac_ripemd160_init(ctx, key, keylen) \
 | 
			
		||||
  gcry_md_open(ctx, GCRY_MD_RMD160, GCRY_MD_FLAG_HMAC), \
 | 
			
		||||
    gcry_md_setkey(*ctx, key, keylen)
 | 
			
		||||
#define libssh2_hmac_sha256_init(ctx, key, keylen) \
 | 
			
		||||
  gcry_md_open(ctx, GCRY_MD_SHA256, GCRY_MD_FLAG_HMAC), \
 | 
			
		||||
    gcry_md_setkey(*ctx, key, keylen)
 | 
			
		||||
#define libssh2_hmac_sha512_init(ctx, key, keylen) \
 | 
			
		||||
  gcry_md_open(ctx, GCRY_MD_SHA512, GCRY_MD_FLAG_HMAC), \
 | 
			
		||||
    gcry_md_setkey(*ctx, key, keylen)
 | 
			
		||||
#define libssh2_hmac_update(ctx, data, datalen) \
 | 
			
		||||
  gcry_md_write(ctx, (unsigned char *) data, datalen)
 | 
			
		||||
#define libssh2_hmac_final(ctx, data) \
 | 
			
		||||
  memcpy(data, gcry_md_read(ctx, 0), \
 | 
			
		||||
      gcry_md_get_algo_dlen(gcry_md_get_algo(ctx)))
 | 
			
		||||
#define libssh2_hmac_cleanup(ctx) gcry_md_close (*ctx);
 | 
			
		||||
 | 
			
		||||
#define libssh2_crypto_init() gcry_control (GCRYCTL_DISABLE_SECMEM)
 | 
			
		||||
#define libssh2_crypto_exit()
 | 
			
		||||
 | 
			
		||||
#define libssh2_rsa_ctx struct gcry_sexp
 | 
			
		||||
 | 
			
		||||
#define _libssh2_rsa_free(rsactx)  gcry_sexp_release (rsactx)
 | 
			
		||||
 | 
			
		||||
#define libssh2_dsa_ctx struct gcry_sexp
 | 
			
		||||
 | 
			
		||||
#define _libssh2_dsa_free(dsactx)  gcry_sexp_release (dsactx)
 | 
			
		||||
 | 
			
		||||
#if LIBSSH2_ECDSA
 | 
			
		||||
#else
 | 
			
		||||
#define _libssh2_ec_key void
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define _libssh2_cipher_type(name) int name
 | 
			
		||||
#define _libssh2_cipher_ctx gcry_cipher_hd_t
 | 
			
		||||
 | 
			
		||||
#define _libssh2_gcry_ciphermode(c,m) ((c << 8) | m)
 | 
			
		||||
#define _libssh2_gcry_cipher(c) (c >> 8)
 | 
			
		||||
#define _libssh2_gcry_mode(m) (m & 0xFF)
 | 
			
		||||
 | 
			
		||||
#define _libssh2_cipher_aes256ctr \
 | 
			
		||||
  _libssh2_gcry_ciphermode(GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CTR)
 | 
			
		||||
#define _libssh2_cipher_aes192ctr \
 | 
			
		||||
  _libssh2_gcry_ciphermode(GCRY_CIPHER_AES192, GCRY_CIPHER_MODE_CTR)
 | 
			
		||||
#define _libssh2_cipher_aes128ctr \
 | 
			
		||||
  _libssh2_gcry_ciphermode(GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_CTR)
 | 
			
		||||
#define _libssh2_cipher_aes256 \
 | 
			
		||||
  _libssh2_gcry_ciphermode(GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CBC)
 | 
			
		||||
#define _libssh2_cipher_aes192 \
 | 
			
		||||
  _libssh2_gcry_ciphermode(GCRY_CIPHER_AES192, GCRY_CIPHER_MODE_CBC)
 | 
			
		||||
#define _libssh2_cipher_aes128 \
 | 
			
		||||
  _libssh2_gcry_ciphermode(GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_CBC)
 | 
			
		||||
#define _libssh2_cipher_blowfish \
 | 
			
		||||
  _libssh2_gcry_ciphermode(GCRY_CIPHER_BLOWFISH, GCRY_CIPHER_MODE_CBC)
 | 
			
		||||
#define _libssh2_cipher_arcfour \
 | 
			
		||||
  _libssh2_gcry_ciphermode(GCRY_CIPHER_ARCFOUR, GCRY_CIPHER_MODE_STREAM)
 | 
			
		||||
#define _libssh2_cipher_cast5 \
 | 
			
		||||
  _libssh2_gcry_ciphermode(GCRY_CIPHER_CAST5, GCRY_CIPHER_MODE_CBC)
 | 
			
		||||
#define _libssh2_cipher_3des \
 | 
			
		||||
  _libssh2_gcry_ciphermode(GCRY_CIPHER_3DES, GCRY_CIPHER_MODE_CBC)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#define _libssh2_cipher_dtor(ctx) gcry_cipher_close(*(ctx))
 | 
			
		||||
 | 
			
		||||
#define _libssh2_bn struct gcry_mpi
 | 
			
		||||
#define _libssh2_bn_ctx int
 | 
			
		||||
#define _libssh2_bn_ctx_new() 0
 | 
			
		||||
#define _libssh2_bn_ctx_free(bnctx) ((void)0)
 | 
			
		||||
#define _libssh2_bn_init() gcry_mpi_new(0)
 | 
			
		||||
#define _libssh2_bn_init_from_bin() NULL /* because gcry_mpi_scan() creates a
 | 
			
		||||
                                            new bignum */
 | 
			
		||||
#define _libssh2_bn_set_word(bn, val) gcry_mpi_set_ui(bn, val)
 | 
			
		||||
#define _libssh2_bn_from_bin(bn, len, val)                      \
 | 
			
		||||
    gcry_mpi_scan(&((bn)), GCRYMPI_FMT_USG, val, len, NULL)
 | 
			
		||||
#define _libssh2_bn_to_bin(bn, val)                                     \
 | 
			
		||||
    gcry_mpi_print(GCRYMPI_FMT_USG, val, _libssh2_bn_bytes(bn), NULL, bn)
 | 
			
		||||
#define _libssh2_bn_bytes(bn)                                           \
 | 
			
		||||
    (gcry_mpi_get_nbits (bn) / 8 +                                      \
 | 
			
		||||
     ((gcry_mpi_get_nbits (bn) % 8 == 0) ? 0 : 1))
 | 
			
		||||
#define _libssh2_bn_bits(bn) gcry_mpi_get_nbits (bn)
 | 
			
		||||
#define _libssh2_bn_free(bn) gcry_mpi_release(bn)
 | 
			
		||||
 | 
			
		||||
#define _libssh2_dh_ctx struct gcry_mpi *
 | 
			
		||||
#define libssh2_dh_init(dhctx) _libssh2_dh_init(dhctx)
 | 
			
		||||
#define libssh2_dh_key_pair(dhctx, public, g, p, group_order, bnctx) \
 | 
			
		||||
        _libssh2_dh_key_pair(dhctx, public, g, p, group_order)
 | 
			
		||||
#define libssh2_dh_secret(dhctx, secret, f, p, bnctx) \
 | 
			
		||||
        _libssh2_dh_secret(dhctx, secret, f, p)
 | 
			
		||||
#define libssh2_dh_dtor(dhctx) _libssh2_dh_dtor(dhctx)
 | 
			
		||||
extern void _libssh2_dh_init(_libssh2_dh_ctx *dhctx);
 | 
			
		||||
extern int _libssh2_dh_key_pair(_libssh2_dh_ctx *dhctx, _libssh2_bn *public,
 | 
			
		||||
                                _libssh2_bn *g, _libssh2_bn *p,
 | 
			
		||||
                                int group_order);
 | 
			
		||||
extern int _libssh2_dh_secret(_libssh2_dh_ctx *dhctx, _libssh2_bn *secret,
 | 
			
		||||
                              _libssh2_bn *f, _libssh2_bn *p);
 | 
			
		||||
extern void _libssh2_dh_dtor(_libssh2_dh_ctx *dhctx);
 | 
			
		||||
 | 
			
		||||
#endif /* __LIBSSH2_LIBGCRYPT_H */
 | 
			
		||||
#endif
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| 
						 | 
				
			
			@ -0,0 +1,75 @@
 | 
			
		|||
#if defined(ESP32)
 | 
			
		||||
/* Copyright (c) 2014 Alexander Lamaison <alexander.lamaison@gmail.com>
 | 
			
		||||
 *
 | 
			
		||||
 * Redistribution and use in source and binary forms,
 | 
			
		||||
 * with or without modification, are permitted provided
 | 
			
		||||
 * that the following conditions are met:
 | 
			
		||||
 *
 | 
			
		||||
 *   Redistributions of source code must retain the above
 | 
			
		||||
 *   copyright notice, this list of conditions and the
 | 
			
		||||
 *   following disclaimer.
 | 
			
		||||
 *
 | 
			
		||||
 *   Redistributions in binary form must reproduce the above
 | 
			
		||||
 *   copyright notice, this list of conditions and the following
 | 
			
		||||
 *   disclaimer in the documentation and/or other materials
 | 
			
		||||
 *   provided with the distribution.
 | 
			
		||||
 *
 | 
			
		||||
 *   Neither the name of the copyright holder nor the names
 | 
			
		||||
 *   of any other contributors may be used to endorse or
 | 
			
		||||
 *   promote products derived from this software without
 | 
			
		||||
 *   specific prior written permission.
 | 
			
		||||
 *
 | 
			
		||||
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
 | 
			
		||||
 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 | 
			
		||||
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 | 
			
		||||
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 | 
			
		||||
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 | 
			
		||||
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | 
			
		||||
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 | 
			
		||||
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 | 
			
		||||
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 | 
			
		||||
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 | 
			
		||||
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 | 
			
		||||
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
 | 
			
		||||
 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
 | 
			
		||||
 * OF SUCH DAMAGE.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/* Headers */
 | 
			
		||||
#define LIBSSH2_MBEDTLS
 | 
			
		||||
#define HAVE_O_NONBLOCK
 | 
			
		||||
#define HAVE_UNISTD_H
 | 
			
		||||
#define HAVE_INTTYPES_H
 | 
			
		||||
#define HAVE_STDLIB_H
 | 
			
		||||
#define HAVE_SYS_SELECT_H
 | 
			
		||||
#define HAVE_SYS_SOCKET_H
 | 
			
		||||
#define HAVE_SYS_TIME_H
 | 
			
		||||
#define HAVE_ARPA_INET_H
 | 
			
		||||
#define HAVE_NETINET_IN_H
 | 
			
		||||
 | 
			
		||||
/* Functions */
 | 
			
		||||
#define HAVE_STRCASECMP
 | 
			
		||||
#define HAVE__STRICMP
 | 
			
		||||
#define HAVE_SNPRINTF
 | 
			
		||||
#define HAVE__SNPRINTF
 | 
			
		||||
 | 
			
		||||
/* Workaround for platforms without POSIX strcasecmp (e.g. Windows) */
 | 
			
		||||
#ifndef HAVE_STRCASECMP
 | 
			
		||||
# ifdef HAVE__STRICMP
 | 
			
		||||
# define strcasecmp _stricmp
 | 
			
		||||
# define HAVE_STRCASECMP
 | 
			
		||||
# endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/* Symbols */
 | 
			
		||||
#define HAVE___FUNC__
 | 
			
		||||
#define HAVE___FUNCTION__
 | 
			
		||||
 | 
			
		||||
/* Workaround for platforms without C90 __func__ */
 | 
			
		||||
#ifndef HAVE___FUNC__
 | 
			
		||||
# ifdef HAVE___FUNCTION__
 | 
			
		||||
# define __func__ __FUNCTION__
 | 
			
		||||
# define HAVE___FUNC__
 | 
			
		||||
# endif
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| 
						 | 
				
			
			@ -0,0 +1,124 @@
 | 
			
		|||
#if defined(ESP32)
 | 
			
		||||
/* Copyright (c) 2004-2006, Sara Golemon <sarag@libssh2.org>
 | 
			
		||||
 * All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Redistribution and use in source and binary forms,
 | 
			
		||||
 * with or without modification, are permitted provided
 | 
			
		||||
 * that the following conditions are met:
 | 
			
		||||
 *
 | 
			
		||||
 *   Redistributions of source code must retain the above
 | 
			
		||||
 *   copyright notice, this list of conditions and the
 | 
			
		||||
 *   following disclaimer.
 | 
			
		||||
 *
 | 
			
		||||
 *   Redistributions in binary form must reproduce the above
 | 
			
		||||
 *   copyright notice, this list of conditions and the following
 | 
			
		||||
 *   disclaimer in the documentation and/or other materials
 | 
			
		||||
 *   provided with the distribution.
 | 
			
		||||
 *
 | 
			
		||||
 *   Neither the name of the copyright holder nor the names
 | 
			
		||||
 *   of any other contributors may be used to endorse or
 | 
			
		||||
 *   promote products derived from this software without
 | 
			
		||||
 *   specific prior written permission.
 | 
			
		||||
 *
 | 
			
		||||
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
 | 
			
		||||
 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 | 
			
		||||
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 | 
			
		||||
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 | 
			
		||||
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 | 
			
		||||
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | 
			
		||||
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 | 
			
		||||
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 | 
			
		||||
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 | 
			
		||||
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 | 
			
		||||
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 | 
			
		||||
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
 | 
			
		||||
 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
 | 
			
		||||
 * OF SUCH DAMAGE.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/* Note: This include file is only needed for using the
 | 
			
		||||
 * publickey SUBSYSTEM which is not the same as publickey
 | 
			
		||||
 * authentication.  For authentication you only need libssh2.h
 | 
			
		||||
 *
 | 
			
		||||
 * For more information on the publickey subsystem,
 | 
			
		||||
 * refer to IETF draft: secsh-publickey
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef LIBSSH2_PUBLICKEY_H
 | 
			
		||||
#define LIBSSH2_PUBLICKEY_H 1
 | 
			
		||||
 | 
			
		||||
#include "libssh2.h"
 | 
			
		||||
 | 
			
		||||
typedef struct _LIBSSH2_PUBLICKEY               LIBSSH2_PUBLICKEY;
 | 
			
		||||
 | 
			
		||||
typedef struct _libssh2_publickey_attribute {
 | 
			
		||||
    const char *name;
 | 
			
		||||
    unsigned long name_len;
 | 
			
		||||
    const char *value;
 | 
			
		||||
    unsigned long value_len;
 | 
			
		||||
    char mandatory;
 | 
			
		||||
} libssh2_publickey_attribute;
 | 
			
		||||
 | 
			
		||||
typedef struct _libssh2_publickey_list {
 | 
			
		||||
    unsigned char *packet; /* For freeing */
 | 
			
		||||
 | 
			
		||||
    const unsigned char *name;
 | 
			
		||||
    unsigned long name_len;
 | 
			
		||||
    const unsigned char *blob;
 | 
			
		||||
    unsigned long blob_len;
 | 
			
		||||
    unsigned long num_attrs;
 | 
			
		||||
    libssh2_publickey_attribute *attrs; /* free me */
 | 
			
		||||
} libssh2_publickey_list;
 | 
			
		||||
 | 
			
		||||
/* Generally use the first macro here, but if both name and value are string
 | 
			
		||||
   literals, you can use _fast() to take advantage of preprocessing */
 | 
			
		||||
#define libssh2_publickey_attribute(name, value, mandatory) \
 | 
			
		||||
  { (name), strlen(name), (value), strlen(value), (mandatory) },
 | 
			
		||||
#define libssh2_publickey_attribute_fast(name, value, mandatory) \
 | 
			
		||||
  { (name), sizeof(name) - 1, (value), sizeof(value) - 1, (mandatory) },
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/* Publickey Subsystem */
 | 
			
		||||
LIBSSH2_API LIBSSH2_PUBLICKEY *
 | 
			
		||||
libssh2_publickey_init(LIBSSH2_SESSION *session);
 | 
			
		||||
 | 
			
		||||
LIBSSH2_API int
 | 
			
		||||
libssh2_publickey_add_ex(LIBSSH2_PUBLICKEY *pkey,
 | 
			
		||||
                         const unsigned char *name,
 | 
			
		||||
                         unsigned long name_len,
 | 
			
		||||
                         const unsigned char *blob,
 | 
			
		||||
                         unsigned long blob_len, char overwrite,
 | 
			
		||||
                         unsigned long num_attrs,
 | 
			
		||||
                         const libssh2_publickey_attribute attrs[]);
 | 
			
		||||
#define libssh2_publickey_add(pkey, name, blob, blob_len, overwrite,    \
 | 
			
		||||
                              num_attrs, attrs)                         \
 | 
			
		||||
  libssh2_publickey_add_ex((pkey), (name), strlen(name), (blob), (blob_len), \
 | 
			
		||||
                           (overwrite), (num_attrs), (attrs))
 | 
			
		||||
 | 
			
		||||
LIBSSH2_API int libssh2_publickey_remove_ex(LIBSSH2_PUBLICKEY *pkey,
 | 
			
		||||
                                            const unsigned char *name,
 | 
			
		||||
                                            unsigned long name_len,
 | 
			
		||||
                                            const unsigned char *blob,
 | 
			
		||||
                                            unsigned long blob_len);
 | 
			
		||||
#define libssh2_publickey_remove(pkey, name, blob, blob_len) \
 | 
			
		||||
  libssh2_publickey_remove_ex((pkey), (name), strlen(name), (blob), (blob_len))
 | 
			
		||||
 | 
			
		||||
LIBSSH2_API int
 | 
			
		||||
libssh2_publickey_list_fetch(LIBSSH2_PUBLICKEY *pkey,
 | 
			
		||||
                             unsigned long *num_keys,
 | 
			
		||||
                             libssh2_publickey_list **pkey_list);
 | 
			
		||||
LIBSSH2_API void
 | 
			
		||||
libssh2_publickey_list_free(LIBSSH2_PUBLICKEY *pkey,
 | 
			
		||||
                            libssh2_publickey_list *pkey_list);
 | 
			
		||||
 | 
			
		||||
LIBSSH2_API int libssh2_publickey_shutdown(LIBSSH2_PUBLICKEY *pkey);
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
} /* extern "C" */
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif /* ifndef: LIBSSH2_PUBLICKEY_H */
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,353 @@
 | 
			
		|||
#if defined(ESP32)
 | 
			
		||||
/* Copyright (c) 2004-2008, Sara Golemon <sarag@libssh2.org>
 | 
			
		||||
 * All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Redistribution and use in source and binary forms,
 | 
			
		||||
 * with or without modification, are permitted provided
 | 
			
		||||
 * that the following conditions are met:
 | 
			
		||||
 *
 | 
			
		||||
 *   Redistributions of source code must retain the above
 | 
			
		||||
 *   copyright notice, this list of conditions and the
 | 
			
		||||
 *   following disclaimer.
 | 
			
		||||
 *
 | 
			
		||||
 *   Redistributions in binary form must reproduce the above
 | 
			
		||||
 *   copyright notice, this list of conditions and the following
 | 
			
		||||
 *   disclaimer in the documentation and/or other materials
 | 
			
		||||
 *   provided with the distribution.
 | 
			
		||||
 *
 | 
			
		||||
 *   Neither the name of the copyright holder nor the names
 | 
			
		||||
 *   of any other contributors may be used to endorse or
 | 
			
		||||
 *   promote products derived from this software without
 | 
			
		||||
 *   specific prior written permission.
 | 
			
		||||
 *
 | 
			
		||||
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
 | 
			
		||||
 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 | 
			
		||||
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 | 
			
		||||
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 | 
			
		||||
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 | 
			
		||||
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | 
			
		||||
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 | 
			
		||||
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 | 
			
		||||
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 | 
			
		||||
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 | 
			
		||||
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 | 
			
		||||
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
 | 
			
		||||
 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
 | 
			
		||||
 * OF SUCH DAMAGE.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef LIBSSH2_SFTP_H
 | 
			
		||||
#define LIBSSH2_SFTP_H 1
 | 
			
		||||
 | 
			
		||||
#include "libssh2.h"
 | 
			
		||||
 | 
			
		||||
#ifndef WIN32
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/* Note: Version 6 was documented at the time of writing
 | 
			
		||||
 * However it was marked as "DO NOT IMPLEMENT" due to pending changes
 | 
			
		||||
 *
 | 
			
		||||
 * Let's start with Version 3 (The version found in OpenSSH) and go from there
 | 
			
		||||
 */
 | 
			
		||||
#define LIBSSH2_SFTP_VERSION        3
 | 
			
		||||
 | 
			
		||||
typedef struct _LIBSSH2_SFTP                LIBSSH2_SFTP;
 | 
			
		||||
typedef struct _LIBSSH2_SFTP_HANDLE         LIBSSH2_SFTP_HANDLE;
 | 
			
		||||
typedef struct _LIBSSH2_SFTP_ATTRIBUTES     LIBSSH2_SFTP_ATTRIBUTES;
 | 
			
		||||
typedef struct _LIBSSH2_SFTP_STATVFS        LIBSSH2_SFTP_STATVFS;
 | 
			
		||||
 | 
			
		||||
/* Flags for open_ex() */
 | 
			
		||||
#define LIBSSH2_SFTP_OPENFILE           0
 | 
			
		||||
#define LIBSSH2_SFTP_OPENDIR            1
 | 
			
		||||
 | 
			
		||||
/* Flags for rename_ex() */
 | 
			
		||||
#define LIBSSH2_SFTP_RENAME_OVERWRITE   0x00000001
 | 
			
		||||
#define LIBSSH2_SFTP_RENAME_ATOMIC      0x00000002
 | 
			
		||||
#define LIBSSH2_SFTP_RENAME_NATIVE      0x00000004
 | 
			
		||||
 | 
			
		||||
/* Flags for stat_ex() */
 | 
			
		||||
#define LIBSSH2_SFTP_STAT               0
 | 
			
		||||
#define LIBSSH2_SFTP_LSTAT              1
 | 
			
		||||
#define LIBSSH2_SFTP_SETSTAT            2
 | 
			
		||||
 | 
			
		||||
/* Flags for symlink_ex() */
 | 
			
		||||
#define LIBSSH2_SFTP_SYMLINK            0
 | 
			
		||||
#define LIBSSH2_SFTP_READLINK           1
 | 
			
		||||
#define LIBSSH2_SFTP_REALPATH           2
 | 
			
		||||
 | 
			
		||||
/* Flags for sftp_mkdir() */
 | 
			
		||||
#define LIBSSH2_SFTP_DEFAULT_MODE      -1
 | 
			
		||||
 | 
			
		||||
/* SFTP attribute flag bits */
 | 
			
		||||
#define LIBSSH2_SFTP_ATTR_SIZE              0x00000001
 | 
			
		||||
#define LIBSSH2_SFTP_ATTR_UIDGID            0x00000002
 | 
			
		||||
#define LIBSSH2_SFTP_ATTR_PERMISSIONS       0x00000004
 | 
			
		||||
#define LIBSSH2_SFTP_ATTR_ACMODTIME         0x00000008
 | 
			
		||||
#define LIBSSH2_SFTP_ATTR_EXTENDED          0x80000000
 | 
			
		||||
 | 
			
		||||
/* SFTP statvfs flag bits */
 | 
			
		||||
#define LIBSSH2_SFTP_ST_RDONLY              0x00000001
 | 
			
		||||
#define LIBSSH2_SFTP_ST_NOSUID              0x00000002
 | 
			
		||||
 | 
			
		||||
struct _LIBSSH2_SFTP_ATTRIBUTES {
 | 
			
		||||
    /* If flags & ATTR_* bit is set, then the value in this struct will be
 | 
			
		||||
     * meaningful Otherwise it should be ignored
 | 
			
		||||
     */
 | 
			
		||||
    unsigned long flags;
 | 
			
		||||
 | 
			
		||||
    libssh2_uint64_t filesize;
 | 
			
		||||
    unsigned long uid, gid;
 | 
			
		||||
    unsigned long permissions;
 | 
			
		||||
    unsigned long atime, mtime;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct _LIBSSH2_SFTP_STATVFS {
 | 
			
		||||
    libssh2_uint64_t  f_bsize;    /* file system block size */
 | 
			
		||||
    libssh2_uint64_t  f_frsize;   /* fragment size */
 | 
			
		||||
    libssh2_uint64_t  f_blocks;   /* size of fs in f_frsize units */
 | 
			
		||||
    libssh2_uint64_t  f_bfree;    /* # free blocks */
 | 
			
		||||
    libssh2_uint64_t  f_bavail;   /* # free blocks for non-root */
 | 
			
		||||
    libssh2_uint64_t  f_files;    /* # inodes */
 | 
			
		||||
    libssh2_uint64_t  f_ffree;    /* # free inodes */
 | 
			
		||||
    libssh2_uint64_t  f_favail;   /* # free inodes for non-root */
 | 
			
		||||
    libssh2_uint64_t  f_fsid;     /* file system ID */
 | 
			
		||||
    libssh2_uint64_t  f_flag;     /* mount flags */
 | 
			
		||||
    libssh2_uint64_t  f_namemax;  /* maximum filename length */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* SFTP filetypes */
 | 
			
		||||
#define LIBSSH2_SFTP_TYPE_REGULAR           1
 | 
			
		||||
#define LIBSSH2_SFTP_TYPE_DIRECTORY         2
 | 
			
		||||
#define LIBSSH2_SFTP_TYPE_SYMLINK           3
 | 
			
		||||
#define LIBSSH2_SFTP_TYPE_SPECIAL           4
 | 
			
		||||
#define LIBSSH2_SFTP_TYPE_UNKNOWN           5
 | 
			
		||||
#define LIBSSH2_SFTP_TYPE_SOCKET            6
 | 
			
		||||
#define LIBSSH2_SFTP_TYPE_CHAR_DEVICE       7
 | 
			
		||||
#define LIBSSH2_SFTP_TYPE_BLOCK_DEVICE      8
 | 
			
		||||
#define LIBSSH2_SFTP_TYPE_FIFO              9
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Reproduce the POSIX file modes here for systems that are not POSIX
 | 
			
		||||
 * compliant.
 | 
			
		||||
 *
 | 
			
		||||
 * These is used in "permissions" of "struct _LIBSSH2_SFTP_ATTRIBUTES"
 | 
			
		||||
 */
 | 
			
		||||
/* File type */
 | 
			
		||||
#define LIBSSH2_SFTP_S_IFMT         0170000     /* type of file mask */
 | 
			
		||||
#define LIBSSH2_SFTP_S_IFIFO        0010000     /* named pipe (fifo) */
 | 
			
		||||
#define LIBSSH2_SFTP_S_IFCHR        0020000     /* character special */
 | 
			
		||||
#define LIBSSH2_SFTP_S_IFDIR        0040000     /* directory */
 | 
			
		||||
#define LIBSSH2_SFTP_S_IFBLK        0060000     /* block special */
 | 
			
		||||
#define LIBSSH2_SFTP_S_IFREG        0100000     /* regular */
 | 
			
		||||
#define LIBSSH2_SFTP_S_IFLNK        0120000     /* symbolic link */
 | 
			
		||||
#define LIBSSH2_SFTP_S_IFSOCK       0140000     /* socket */
 | 
			
		||||
 | 
			
		||||
/* File mode */
 | 
			
		||||
/* Read, write, execute/search by owner */
 | 
			
		||||
#define LIBSSH2_SFTP_S_IRWXU        0000700     /* RWX mask for owner */
 | 
			
		||||
#define LIBSSH2_SFTP_S_IRUSR        0000400     /* R for owner */
 | 
			
		||||
#define LIBSSH2_SFTP_S_IWUSR        0000200     /* W for owner */
 | 
			
		||||
#define LIBSSH2_SFTP_S_IXUSR        0000100     /* X for owner */
 | 
			
		||||
/* Read, write, execute/search by group */
 | 
			
		||||
#define LIBSSH2_SFTP_S_IRWXG        0000070     /* RWX mask for group */
 | 
			
		||||
#define LIBSSH2_SFTP_S_IRGRP        0000040     /* R for group */
 | 
			
		||||
#define LIBSSH2_SFTP_S_IWGRP        0000020     /* W for group */
 | 
			
		||||
#define LIBSSH2_SFTP_S_IXGRP        0000010     /* X for group */
 | 
			
		||||
/* Read, write, execute/search by others */
 | 
			
		||||
#define LIBSSH2_SFTP_S_IRWXO        0000007     /* RWX mask for other */
 | 
			
		||||
#define LIBSSH2_SFTP_S_IROTH        0000004     /* R for other */
 | 
			
		||||
#define LIBSSH2_SFTP_S_IWOTH        0000002     /* W for other */
 | 
			
		||||
#define LIBSSH2_SFTP_S_IXOTH        0000001     /* X for other */
 | 
			
		||||
 | 
			
		||||
/* macros to check for specific file types, added in 1.2.5 */
 | 
			
		||||
#define LIBSSH2_SFTP_S_ISLNK(m) \
 | 
			
		||||
  (((m) & LIBSSH2_SFTP_S_IFMT) == LIBSSH2_SFTP_S_IFLNK)
 | 
			
		||||
#define LIBSSH2_SFTP_S_ISREG(m) \
 | 
			
		||||
  (((m) & LIBSSH2_SFTP_S_IFMT) == LIBSSH2_SFTP_S_IFREG)
 | 
			
		||||
#define LIBSSH2_SFTP_S_ISDIR(m) \
 | 
			
		||||
  (((m) & LIBSSH2_SFTP_S_IFMT) == LIBSSH2_SFTP_S_IFDIR)
 | 
			
		||||
#define LIBSSH2_SFTP_S_ISCHR(m) \
 | 
			
		||||
  (((m) & LIBSSH2_SFTP_S_IFMT) == LIBSSH2_SFTP_S_IFCHR)
 | 
			
		||||
#define LIBSSH2_SFTP_S_ISBLK(m) \
 | 
			
		||||
  (((m) & LIBSSH2_SFTP_S_IFMT) == LIBSSH2_SFTP_S_IFBLK)
 | 
			
		||||
#define LIBSSH2_SFTP_S_ISFIFO(m) \
 | 
			
		||||
  (((m) & LIBSSH2_SFTP_S_IFMT) == LIBSSH2_SFTP_S_IFIFO)
 | 
			
		||||
#define LIBSSH2_SFTP_S_ISSOCK(m) \
 | 
			
		||||
  (((m) & LIBSSH2_SFTP_S_IFMT) == LIBSSH2_SFTP_S_IFSOCK)
 | 
			
		||||
 | 
			
		||||
/* SFTP File Transfer Flags -- (e.g. flags parameter to sftp_open())
 | 
			
		||||
 * Danger will robinson... APPEND doesn't have any effect on OpenSSH servers */
 | 
			
		||||
#define LIBSSH2_FXF_READ                        0x00000001
 | 
			
		||||
#define LIBSSH2_FXF_WRITE                       0x00000002
 | 
			
		||||
#define LIBSSH2_FXF_APPEND                      0x00000004
 | 
			
		||||
#define LIBSSH2_FXF_CREAT                       0x00000008
 | 
			
		||||
#define LIBSSH2_FXF_TRUNC                       0x00000010
 | 
			
		||||
#define LIBSSH2_FXF_EXCL                        0x00000020
 | 
			
		||||
 | 
			
		||||
/* SFTP Status Codes (returned by libssh2_sftp_last_error() ) */
 | 
			
		||||
#define LIBSSH2_FX_OK                       0UL
 | 
			
		||||
#define LIBSSH2_FX_EOF                      1UL
 | 
			
		||||
#define LIBSSH2_FX_NO_SUCH_FILE             2UL
 | 
			
		||||
#define LIBSSH2_FX_PERMISSION_DENIED        3UL
 | 
			
		||||
#define LIBSSH2_FX_FAILURE                  4UL
 | 
			
		||||
#define LIBSSH2_FX_BAD_MESSAGE              5UL
 | 
			
		||||
#define LIBSSH2_FX_NO_CONNECTION            6UL
 | 
			
		||||
#define LIBSSH2_FX_CONNECTION_LOST          7UL
 | 
			
		||||
#define LIBSSH2_FX_OP_UNSUPPORTED           8UL
 | 
			
		||||
#define LIBSSH2_FX_INVALID_HANDLE           9UL
 | 
			
		||||
#define LIBSSH2_FX_NO_SUCH_PATH             10UL
 | 
			
		||||
#define LIBSSH2_FX_FILE_ALREADY_EXISTS      11UL
 | 
			
		||||
#define LIBSSH2_FX_WRITE_PROTECT            12UL
 | 
			
		||||
#define LIBSSH2_FX_NO_MEDIA                 13UL
 | 
			
		||||
#define LIBSSH2_FX_NO_SPACE_ON_FILESYSTEM   14UL
 | 
			
		||||
#define LIBSSH2_FX_QUOTA_EXCEEDED           15UL
 | 
			
		||||
#define LIBSSH2_FX_UNKNOWN_PRINCIPLE        16UL /* Initial mis-spelling */
 | 
			
		||||
#define LIBSSH2_FX_UNKNOWN_PRINCIPAL        16UL
 | 
			
		||||
#define LIBSSH2_FX_LOCK_CONFlICT            17UL /* Initial mis-spelling */
 | 
			
		||||
#define LIBSSH2_FX_LOCK_CONFLICT            17UL
 | 
			
		||||
#define LIBSSH2_FX_DIR_NOT_EMPTY            18UL
 | 
			
		||||
#define LIBSSH2_FX_NOT_A_DIRECTORY          19UL
 | 
			
		||||
#define LIBSSH2_FX_INVALID_FILENAME         20UL
 | 
			
		||||
#define LIBSSH2_FX_LINK_LOOP                21UL
 | 
			
		||||
 | 
			
		||||
/* Returned by any function that would block during a read/write operation */
 | 
			
		||||
#define LIBSSH2SFTP_EAGAIN LIBSSH2_ERROR_EAGAIN
 | 
			
		||||
 | 
			
		||||
/* SFTP API */
 | 
			
		||||
LIBSSH2_API LIBSSH2_SFTP *libssh2_sftp_init(LIBSSH2_SESSION *session);
 | 
			
		||||
LIBSSH2_API int libssh2_sftp_shutdown(LIBSSH2_SFTP *sftp);
 | 
			
		||||
LIBSSH2_API unsigned long libssh2_sftp_last_error(LIBSSH2_SFTP *sftp);
 | 
			
		||||
LIBSSH2_API LIBSSH2_CHANNEL *libssh2_sftp_get_channel(LIBSSH2_SFTP *sftp);
 | 
			
		||||
 | 
			
		||||
/* File / Directory Ops */
 | 
			
		||||
LIBSSH2_API LIBSSH2_SFTP_HANDLE *
 | 
			
		||||
libssh2_sftp_open_ex(LIBSSH2_SFTP *sftp,
 | 
			
		||||
                     const char *filename,
 | 
			
		||||
                     unsigned int filename_len,
 | 
			
		||||
                     unsigned long flags,
 | 
			
		||||
                     long mode, int open_type);
 | 
			
		||||
#define libssh2_sftp_open(sftp, filename, flags, mode)                  \
 | 
			
		||||
    libssh2_sftp_open_ex((sftp), (filename), strlen(filename), (flags), \
 | 
			
		||||
                         (mode), LIBSSH2_SFTP_OPENFILE)
 | 
			
		||||
#define libssh2_sftp_opendir(sftp, path) \
 | 
			
		||||
    libssh2_sftp_open_ex((sftp), (path), strlen(path), 0, 0, \
 | 
			
		||||
                         LIBSSH2_SFTP_OPENDIR)
 | 
			
		||||
 | 
			
		||||
LIBSSH2_API ssize_t libssh2_sftp_read(LIBSSH2_SFTP_HANDLE *handle,
 | 
			
		||||
                                      char *buffer, size_t buffer_maxlen);
 | 
			
		||||
 | 
			
		||||
LIBSSH2_API int libssh2_sftp_readdir_ex(LIBSSH2_SFTP_HANDLE *handle, \
 | 
			
		||||
                                        char *buffer, size_t buffer_maxlen,
 | 
			
		||||
                                        char *longentry,
 | 
			
		||||
                                        size_t longentry_maxlen,
 | 
			
		||||
                                        LIBSSH2_SFTP_ATTRIBUTES *attrs);
 | 
			
		||||
#define libssh2_sftp_readdir(handle, buffer, buffer_maxlen, attrs)      \
 | 
			
		||||
    libssh2_sftp_readdir_ex((handle), (buffer), (buffer_maxlen), NULL, 0, \
 | 
			
		||||
                            (attrs))
 | 
			
		||||
 | 
			
		||||
LIBSSH2_API ssize_t libssh2_sftp_write(LIBSSH2_SFTP_HANDLE *handle,
 | 
			
		||||
                                       const char *buffer, size_t count);
 | 
			
		||||
LIBSSH2_API int libssh2_sftp_fsync(LIBSSH2_SFTP_HANDLE *handle);
 | 
			
		||||
 | 
			
		||||
LIBSSH2_API int libssh2_sftp_close_handle(LIBSSH2_SFTP_HANDLE *handle);
 | 
			
		||||
#define libssh2_sftp_close(handle) libssh2_sftp_close_handle(handle)
 | 
			
		||||
#define libssh2_sftp_closedir(handle) libssh2_sftp_close_handle(handle)
 | 
			
		||||
 | 
			
		||||
LIBSSH2_API void libssh2_sftp_seek(LIBSSH2_SFTP_HANDLE *handle, size_t offset);
 | 
			
		||||
LIBSSH2_API void libssh2_sftp_seek64(LIBSSH2_SFTP_HANDLE *handle,
 | 
			
		||||
                                     libssh2_uint64_t offset);
 | 
			
		||||
#define libssh2_sftp_rewind(handle) libssh2_sftp_seek64((handle), 0)
 | 
			
		||||
 | 
			
		||||
LIBSSH2_API size_t libssh2_sftp_tell(LIBSSH2_SFTP_HANDLE *handle);
 | 
			
		||||
LIBSSH2_API libssh2_uint64_t libssh2_sftp_tell64(LIBSSH2_SFTP_HANDLE *handle);
 | 
			
		||||
 | 
			
		||||
LIBSSH2_API int libssh2_sftp_fstat_ex(LIBSSH2_SFTP_HANDLE *handle,
 | 
			
		||||
                                      LIBSSH2_SFTP_ATTRIBUTES *attrs,
 | 
			
		||||
                                      int setstat);
 | 
			
		||||
#define libssh2_sftp_fstat(handle, attrs) \
 | 
			
		||||
    libssh2_sftp_fstat_ex((handle), (attrs), 0)
 | 
			
		||||
#define libssh2_sftp_fsetstat(handle, attrs) \
 | 
			
		||||
    libssh2_sftp_fstat_ex((handle), (attrs), 1)
 | 
			
		||||
 | 
			
		||||
/* Miscellaneous Ops */
 | 
			
		||||
LIBSSH2_API int libssh2_sftp_rename_ex(LIBSSH2_SFTP *sftp,
 | 
			
		||||
                                       const char *source_filename,
 | 
			
		||||
                                       unsigned int srouce_filename_len,
 | 
			
		||||
                                       const char *dest_filename,
 | 
			
		||||
                                       unsigned int dest_filename_len,
 | 
			
		||||
                                       long flags);
 | 
			
		||||
#define libssh2_sftp_rename(sftp, sourcefile, destfile) \
 | 
			
		||||
    libssh2_sftp_rename_ex((sftp), (sourcefile), strlen(sourcefile), \
 | 
			
		||||
                           (destfile), strlen(destfile),                \
 | 
			
		||||
                           LIBSSH2_SFTP_RENAME_OVERWRITE | \
 | 
			
		||||
                           LIBSSH2_SFTP_RENAME_ATOMIC | \
 | 
			
		||||
                           LIBSSH2_SFTP_RENAME_NATIVE)
 | 
			
		||||
 | 
			
		||||
LIBSSH2_API int libssh2_sftp_unlink_ex(LIBSSH2_SFTP *sftp,
 | 
			
		||||
                                       const char *filename,
 | 
			
		||||
                                       unsigned int filename_len);
 | 
			
		||||
#define libssh2_sftp_unlink(sftp, filename) \
 | 
			
		||||
    libssh2_sftp_unlink_ex((sftp), (filename), strlen(filename))
 | 
			
		||||
 | 
			
		||||
LIBSSH2_API int libssh2_sftp_fstatvfs(LIBSSH2_SFTP_HANDLE *handle,
 | 
			
		||||
                                      LIBSSH2_SFTP_STATVFS *st);
 | 
			
		||||
 | 
			
		||||
LIBSSH2_API int libssh2_sftp_statvfs(LIBSSH2_SFTP *sftp,
 | 
			
		||||
                                     const char *path,
 | 
			
		||||
                                     size_t path_len,
 | 
			
		||||
                                     LIBSSH2_SFTP_STATVFS *st);
 | 
			
		||||
 | 
			
		||||
LIBSSH2_API int libssh2_sftp_mkdir_ex(LIBSSH2_SFTP *sftp,
 | 
			
		||||
                                      const char *path,
 | 
			
		||||
                                      unsigned int path_len, long mode);
 | 
			
		||||
#define libssh2_sftp_mkdir(sftp, path, mode) \
 | 
			
		||||
    libssh2_sftp_mkdir_ex((sftp), (path), strlen(path), (mode))
 | 
			
		||||
 | 
			
		||||
LIBSSH2_API int libssh2_sftp_rmdir_ex(LIBSSH2_SFTP *sftp,
 | 
			
		||||
                                      const char *path,
 | 
			
		||||
                                      unsigned int path_len);
 | 
			
		||||
#define libssh2_sftp_rmdir(sftp, path) \
 | 
			
		||||
    libssh2_sftp_rmdir_ex((sftp), (path), strlen(path))
 | 
			
		||||
 | 
			
		||||
LIBSSH2_API int libssh2_sftp_stat_ex(LIBSSH2_SFTP *sftp,
 | 
			
		||||
                                     const char *path,
 | 
			
		||||
                                     unsigned int path_len,
 | 
			
		||||
                                     int stat_type,
 | 
			
		||||
                                     LIBSSH2_SFTP_ATTRIBUTES *attrs);
 | 
			
		||||
#define libssh2_sftp_stat(sftp, path, attrs) \
 | 
			
		||||
    libssh2_sftp_stat_ex((sftp), (path), strlen(path), LIBSSH2_SFTP_STAT, \
 | 
			
		||||
                         (attrs))
 | 
			
		||||
#define libssh2_sftp_lstat(sftp, path, attrs) \
 | 
			
		||||
    libssh2_sftp_stat_ex((sftp), (path), strlen(path), LIBSSH2_SFTP_LSTAT, \
 | 
			
		||||
                         (attrs))
 | 
			
		||||
#define libssh2_sftp_setstat(sftp, path, attrs) \
 | 
			
		||||
    libssh2_sftp_stat_ex((sftp), (path), strlen(path), LIBSSH2_SFTP_SETSTAT, \
 | 
			
		||||
                         (attrs))
 | 
			
		||||
 | 
			
		||||
LIBSSH2_API int libssh2_sftp_symlink_ex(LIBSSH2_SFTP *sftp,
 | 
			
		||||
                                        const char *path,
 | 
			
		||||
                                        unsigned int path_len,
 | 
			
		||||
                                        char *target,
 | 
			
		||||
                                        unsigned int target_len,
 | 
			
		||||
                                        int link_type);
 | 
			
		||||
#define libssh2_sftp_symlink(sftp, orig, linkpath) \
 | 
			
		||||
    libssh2_sftp_symlink_ex((sftp), (orig), strlen(orig), (linkpath), \
 | 
			
		||||
                            strlen(linkpath), LIBSSH2_SFTP_SYMLINK)
 | 
			
		||||
#define libssh2_sftp_readlink(sftp, path, target, maxlen) \
 | 
			
		||||
    libssh2_sftp_symlink_ex((sftp), (path), strlen(path), (target), (maxlen), \
 | 
			
		||||
    LIBSSH2_SFTP_READLINK)
 | 
			
		||||
#define libssh2_sftp_realpath(sftp, path, target, maxlen) \
 | 
			
		||||
    libssh2_sftp_symlink_ex((sftp), (path), strlen(path), (target), (maxlen), \
 | 
			
		||||
                            LIBSSH2_SFTP_REALPATH)
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
} /* extern "C" */
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif /* LIBSSH2_SFTP_H */
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,416 @@
 | 
			
		|||
#if defined(ESP32)
 | 
			
		||||
/* Copyright (c) 2004-2007, Sara Golemon <sarag@libssh2.org>
 | 
			
		||||
 * All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Redistribution and use in source and binary forms,
 | 
			
		||||
 * with or without modification, are permitted provided
 | 
			
		||||
 * that the following conditions are met:
 | 
			
		||||
 *
 | 
			
		||||
 *   Redistributions of source code must retain the above
 | 
			
		||||
 *   copyright notice, this list of conditions and the
 | 
			
		||||
 *   following disclaimer.
 | 
			
		||||
 *
 | 
			
		||||
 *   Redistributions in binary form must reproduce the above
 | 
			
		||||
 *   copyright notice, this list of conditions and the following
 | 
			
		||||
 *   disclaimer in the documentation and/or other materials
 | 
			
		||||
 *   provided with the distribution.
 | 
			
		||||
 *
 | 
			
		||||
 *   Neither the name of the copyright holder nor the names
 | 
			
		||||
 *   of any other contributors may be used to endorse or
 | 
			
		||||
 *   promote products derived from this software without
 | 
			
		||||
 *   specific prior written permission.
 | 
			
		||||
 *
 | 
			
		||||
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
 | 
			
		||||
 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 | 
			
		||||
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 | 
			
		||||
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 | 
			
		||||
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 | 
			
		||||
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | 
			
		||||
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 | 
			
		||||
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 | 
			
		||||
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 | 
			
		||||
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 | 
			
		||||
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 | 
			
		||||
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
 | 
			
		||||
 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
 | 
			
		||||
 * OF SUCH DAMAGE.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "libssh2_priv.h"
 | 
			
		||||
#include "mac.h"
 | 
			
		||||
 | 
			
		||||
#ifdef LIBSSH2_MAC_NONE
 | 
			
		||||
/* mac_none_MAC
 | 
			
		||||
 * Minimalist MAC: No MAC
 | 
			
		||||
 */
 | 
			
		||||
static int
 | 
			
		||||
mac_none_MAC(LIBSSH2_SESSION * session, unsigned char *buf,
 | 
			
		||||
             uint32_t seqno, const unsigned char *packet,
 | 
			
		||||
             uint32_t packet_len, const unsigned char *addtl,
 | 
			
		||||
             uint32_t addtl_len, void **abstract)
 | 
			
		||||
{
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static LIBSSH2_MAC_METHOD mac_method_none = {
 | 
			
		||||
    "none",
 | 
			
		||||
    0,
 | 
			
		||||
    0,
 | 
			
		||||
    NULL,
 | 
			
		||||
    mac_none_MAC,
 | 
			
		||||
    NULL
 | 
			
		||||
};
 | 
			
		||||
#endif /* LIBSSH2_MAC_NONE */
 | 
			
		||||
 | 
			
		||||
/* mac_method_common_init
 | 
			
		||||
 * Initialize simple mac methods
 | 
			
		||||
 */
 | 
			
		||||
static int
 | 
			
		||||
mac_method_common_init(LIBSSH2_SESSION * session, unsigned char *key,
 | 
			
		||||
                       int *free_key, void **abstract)
 | 
			
		||||
{
 | 
			
		||||
    *abstract = key;
 | 
			
		||||
    *free_key = 0;
 | 
			
		||||
    (void) session;
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* mac_method_common_dtor
 | 
			
		||||
 * Cleanup simple mac methods
 | 
			
		||||
 */
 | 
			
		||||
static int
 | 
			
		||||
mac_method_common_dtor(LIBSSH2_SESSION * session, void **abstract)
 | 
			
		||||
{
 | 
			
		||||
    if(*abstract) {
 | 
			
		||||
        LIBSSH2_FREE(session, *abstract);
 | 
			
		||||
    }
 | 
			
		||||
    *abstract = NULL;
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#if LIBSSH2_HMAC_SHA512
 | 
			
		||||
/* mac_method_hmac_sha512_hash
 | 
			
		||||
 * Calculate hash using full sha512 value
 | 
			
		||||
 */
 | 
			
		||||
static int
 | 
			
		||||
mac_method_hmac_sha2_512_hash(LIBSSH2_SESSION * session,
 | 
			
		||||
                          unsigned char *buf, uint32_t seqno,
 | 
			
		||||
                          const unsigned char *packet,
 | 
			
		||||
                          uint32_t packet_len,
 | 
			
		||||
                          const unsigned char *addtl,
 | 
			
		||||
                          uint32_t addtl_len, void **abstract)
 | 
			
		||||
{
 | 
			
		||||
    libssh2_hmac_ctx ctx;
 | 
			
		||||
    unsigned char seqno_buf[4];
 | 
			
		||||
    (void) session;
 | 
			
		||||
 | 
			
		||||
    _libssh2_htonu32(seqno_buf, seqno);
 | 
			
		||||
 | 
			
		||||
    libssh2_hmac_ctx_init(ctx);
 | 
			
		||||
    libssh2_hmac_sha512_init(&ctx, *abstract, 64);
 | 
			
		||||
    libssh2_hmac_update(ctx, seqno_buf, 4);
 | 
			
		||||
    libssh2_hmac_update(ctx, packet, packet_len);
 | 
			
		||||
    if(addtl && addtl_len) {
 | 
			
		||||
        libssh2_hmac_update(ctx, addtl, addtl_len);
 | 
			
		||||
    }
 | 
			
		||||
    libssh2_hmac_final(ctx, buf);
 | 
			
		||||
    libssh2_hmac_cleanup(&ctx);
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static const LIBSSH2_MAC_METHOD mac_method_hmac_sha2_512 = {
 | 
			
		||||
    "hmac-sha2-512",
 | 
			
		||||
    64,
 | 
			
		||||
    64,
 | 
			
		||||
    mac_method_common_init,
 | 
			
		||||
    mac_method_hmac_sha2_512_hash,
 | 
			
		||||
    mac_method_common_dtor,
 | 
			
		||||
};
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#if LIBSSH2_HMAC_SHA256
 | 
			
		||||
/* mac_method_hmac_sha256_hash
 | 
			
		||||
 * Calculate hash using full sha256 value
 | 
			
		||||
 */
 | 
			
		||||
static int
 | 
			
		||||
mac_method_hmac_sha2_256_hash(LIBSSH2_SESSION * session,
 | 
			
		||||
                          unsigned char *buf, uint32_t seqno,
 | 
			
		||||
                          const unsigned char *packet,
 | 
			
		||||
                          uint32_t packet_len,
 | 
			
		||||
                          const unsigned char *addtl,
 | 
			
		||||
                          uint32_t addtl_len, void **abstract)
 | 
			
		||||
{
 | 
			
		||||
    libssh2_hmac_ctx ctx;
 | 
			
		||||
    unsigned char seqno_buf[4];
 | 
			
		||||
    (void) session;
 | 
			
		||||
 | 
			
		||||
    _libssh2_htonu32(seqno_buf, seqno);
 | 
			
		||||
 | 
			
		||||
    libssh2_hmac_ctx_init(ctx);
 | 
			
		||||
    libssh2_hmac_sha256_init(&ctx, *abstract, 32);
 | 
			
		||||
    libssh2_hmac_update(ctx, seqno_buf, 4);
 | 
			
		||||
    libssh2_hmac_update(ctx, packet, packet_len);
 | 
			
		||||
    if(addtl && addtl_len) {
 | 
			
		||||
        libssh2_hmac_update(ctx, addtl, addtl_len);
 | 
			
		||||
    }
 | 
			
		||||
    libssh2_hmac_final(ctx, buf);
 | 
			
		||||
    libssh2_hmac_cleanup(&ctx);
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static const LIBSSH2_MAC_METHOD mac_method_hmac_sha2_256 = {
 | 
			
		||||
    "hmac-sha2-256",
 | 
			
		||||
    32,
 | 
			
		||||
    32,
 | 
			
		||||
    mac_method_common_init,
 | 
			
		||||
    mac_method_hmac_sha2_256_hash,
 | 
			
		||||
    mac_method_common_dtor,
 | 
			
		||||
};
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* mac_method_hmac_sha1_hash
 | 
			
		||||
 * Calculate hash using full sha1 value
 | 
			
		||||
 */
 | 
			
		||||
static int
 | 
			
		||||
mac_method_hmac_sha1_hash(LIBSSH2_SESSION * session,
 | 
			
		||||
                          unsigned char *buf, uint32_t seqno,
 | 
			
		||||
                          const unsigned char *packet,
 | 
			
		||||
                          uint32_t packet_len,
 | 
			
		||||
                          const unsigned char *addtl,
 | 
			
		||||
                          uint32_t addtl_len, void **abstract)
 | 
			
		||||
{
 | 
			
		||||
    libssh2_hmac_ctx ctx;
 | 
			
		||||
    unsigned char seqno_buf[4];
 | 
			
		||||
    (void) session;
 | 
			
		||||
 | 
			
		||||
    _libssh2_htonu32(seqno_buf, seqno);
 | 
			
		||||
 | 
			
		||||
    libssh2_hmac_ctx_init(ctx);
 | 
			
		||||
    libssh2_hmac_sha1_init(&ctx, *abstract, 20);
 | 
			
		||||
    libssh2_hmac_update(ctx, seqno_buf, 4);
 | 
			
		||||
    libssh2_hmac_update(ctx, packet, packet_len);
 | 
			
		||||
    if(addtl && addtl_len) {
 | 
			
		||||
        libssh2_hmac_update(ctx, addtl, addtl_len);
 | 
			
		||||
    }
 | 
			
		||||
    libssh2_hmac_final(ctx, buf);
 | 
			
		||||
    libssh2_hmac_cleanup(&ctx);
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static const LIBSSH2_MAC_METHOD mac_method_hmac_sha1 = {
 | 
			
		||||
    "hmac-sha1",
 | 
			
		||||
    20,
 | 
			
		||||
    20,
 | 
			
		||||
    mac_method_common_init,
 | 
			
		||||
    mac_method_hmac_sha1_hash,
 | 
			
		||||
    mac_method_common_dtor,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* mac_method_hmac_sha1_96_hash
 | 
			
		||||
 * Calculate hash using first 96 bits of sha1 value
 | 
			
		||||
 */
 | 
			
		||||
static int
 | 
			
		||||
mac_method_hmac_sha1_96_hash(LIBSSH2_SESSION * session,
 | 
			
		||||
                             unsigned char *buf, uint32_t seqno,
 | 
			
		||||
                             const unsigned char *packet,
 | 
			
		||||
                             uint32_t packet_len,
 | 
			
		||||
                             const unsigned char *addtl,
 | 
			
		||||
                             uint32_t addtl_len, void **abstract)
 | 
			
		||||
{
 | 
			
		||||
    unsigned char temp[SHA_DIGEST_LENGTH];
 | 
			
		||||
 | 
			
		||||
    mac_method_hmac_sha1_hash(session, temp, seqno, packet, packet_len,
 | 
			
		||||
                              addtl, addtl_len, abstract);
 | 
			
		||||
    memcpy(buf, (char *) temp, 96 / 8);
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static const LIBSSH2_MAC_METHOD mac_method_hmac_sha1_96 = {
 | 
			
		||||
    "hmac-sha1-96",
 | 
			
		||||
    12,
 | 
			
		||||
    20,
 | 
			
		||||
    mac_method_common_init,
 | 
			
		||||
    mac_method_hmac_sha1_96_hash,
 | 
			
		||||
    mac_method_common_dtor,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#if LIBSSH2_MD5
 | 
			
		||||
/* mac_method_hmac_md5_hash
 | 
			
		||||
 * Calculate hash using full md5 value
 | 
			
		||||
 */
 | 
			
		||||
static int
 | 
			
		||||
mac_method_hmac_md5_hash(LIBSSH2_SESSION * session, unsigned char *buf,
 | 
			
		||||
                         uint32_t seqno,
 | 
			
		||||
                         const unsigned char *packet,
 | 
			
		||||
                         uint32_t packet_len,
 | 
			
		||||
                         const unsigned char *addtl,
 | 
			
		||||
                         uint32_t addtl_len, void **abstract)
 | 
			
		||||
{
 | 
			
		||||
    libssh2_hmac_ctx ctx;
 | 
			
		||||
    unsigned char seqno_buf[4];
 | 
			
		||||
    (void) session;
 | 
			
		||||
 | 
			
		||||
    _libssh2_htonu32(seqno_buf, seqno);
 | 
			
		||||
 | 
			
		||||
    libssh2_hmac_ctx_init(ctx);
 | 
			
		||||
    libssh2_hmac_md5_init(&ctx, *abstract, 16);
 | 
			
		||||
    libssh2_hmac_update(ctx, seqno_buf, 4);
 | 
			
		||||
    libssh2_hmac_update(ctx, packet, packet_len);
 | 
			
		||||
    if(addtl && addtl_len) {
 | 
			
		||||
        libssh2_hmac_update(ctx, addtl, addtl_len);
 | 
			
		||||
    }
 | 
			
		||||
    libssh2_hmac_final(ctx, buf);
 | 
			
		||||
    libssh2_hmac_cleanup(&ctx);
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static const LIBSSH2_MAC_METHOD mac_method_hmac_md5 = {
 | 
			
		||||
    "hmac-md5",
 | 
			
		||||
    16,
 | 
			
		||||
    16,
 | 
			
		||||
    mac_method_common_init,
 | 
			
		||||
    mac_method_hmac_md5_hash,
 | 
			
		||||
    mac_method_common_dtor,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* mac_method_hmac_md5_96_hash
 | 
			
		||||
 * Calculate hash using first 96 bits of md5 value
 | 
			
		||||
 */
 | 
			
		||||
static int
 | 
			
		||||
mac_method_hmac_md5_96_hash(LIBSSH2_SESSION * session,
 | 
			
		||||
                            unsigned char *buf, uint32_t seqno,
 | 
			
		||||
                            const unsigned char *packet,
 | 
			
		||||
                            uint32_t packet_len,
 | 
			
		||||
                            const unsigned char *addtl,
 | 
			
		||||
                            uint32_t addtl_len, void **abstract)
 | 
			
		||||
{
 | 
			
		||||
    unsigned char temp[MD5_DIGEST_LENGTH];
 | 
			
		||||
    mac_method_hmac_md5_hash(session, temp, seqno, packet, packet_len,
 | 
			
		||||
                             addtl, addtl_len, abstract);
 | 
			
		||||
    memcpy(buf, (char *) temp, 96 / 8);
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static const LIBSSH2_MAC_METHOD mac_method_hmac_md5_96 = {
 | 
			
		||||
    "hmac-md5-96",
 | 
			
		||||
    12,
 | 
			
		||||
    16,
 | 
			
		||||
    mac_method_common_init,
 | 
			
		||||
    mac_method_hmac_md5_96_hash,
 | 
			
		||||
    mac_method_common_dtor,
 | 
			
		||||
};
 | 
			
		||||
#endif /* LIBSSH2_MD5 */
 | 
			
		||||
 | 
			
		||||
#if LIBSSH2_HMAC_RIPEMD
 | 
			
		||||
/* mac_method_hmac_ripemd160_hash
 | 
			
		||||
 * Calculate hash using ripemd160 value
 | 
			
		||||
 */
 | 
			
		||||
static int
 | 
			
		||||
mac_method_hmac_ripemd160_hash(LIBSSH2_SESSION * session,
 | 
			
		||||
                               unsigned char *buf, uint32_t seqno,
 | 
			
		||||
                               const unsigned char *packet,
 | 
			
		||||
                               uint32_t packet_len,
 | 
			
		||||
                               const unsigned char *addtl,
 | 
			
		||||
                               uint32_t addtl_len,
 | 
			
		||||
                               void **abstract)
 | 
			
		||||
{
 | 
			
		||||
    libssh2_hmac_ctx ctx;
 | 
			
		||||
    unsigned char seqno_buf[4];
 | 
			
		||||
    (void) session;
 | 
			
		||||
 | 
			
		||||
    _libssh2_htonu32(seqno_buf, seqno);
 | 
			
		||||
 | 
			
		||||
    libssh2_hmac_ctx_init(ctx);
 | 
			
		||||
    libssh2_hmac_ripemd160_init(&ctx, *abstract, 20);
 | 
			
		||||
    libssh2_hmac_update(ctx, seqno_buf, 4);
 | 
			
		||||
    libssh2_hmac_update(ctx, packet, packet_len);
 | 
			
		||||
    if(addtl && addtl_len) {
 | 
			
		||||
        libssh2_hmac_update(ctx, addtl, addtl_len);
 | 
			
		||||
    }
 | 
			
		||||
    libssh2_hmac_final(ctx, buf);
 | 
			
		||||
    libssh2_hmac_cleanup(&ctx);
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static const LIBSSH2_MAC_METHOD mac_method_hmac_ripemd160 = {
 | 
			
		||||
    "hmac-ripemd160",
 | 
			
		||||
    20,
 | 
			
		||||
    20,
 | 
			
		||||
    mac_method_common_init,
 | 
			
		||||
    mac_method_hmac_ripemd160_hash,
 | 
			
		||||
    mac_method_common_dtor,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const LIBSSH2_MAC_METHOD mac_method_hmac_ripemd160_openssh_com = {
 | 
			
		||||
    "hmac-ripemd160@openssh.com",
 | 
			
		||||
    20,
 | 
			
		||||
    20,
 | 
			
		||||
    mac_method_common_init,
 | 
			
		||||
    mac_method_hmac_ripemd160_hash,
 | 
			
		||||
    mac_method_common_dtor,
 | 
			
		||||
};
 | 
			
		||||
#endif /* LIBSSH2_HMAC_RIPEMD */
 | 
			
		||||
 | 
			
		||||
static const LIBSSH2_MAC_METHOD *mac_methods[] = {
 | 
			
		||||
#if LIBSSH2_HMAC_SHA256
 | 
			
		||||
    &mac_method_hmac_sha2_256,
 | 
			
		||||
#endif
 | 
			
		||||
#if LIBSSH2_HMAC_SHA512
 | 
			
		||||
    &mac_method_hmac_sha2_512,
 | 
			
		||||
#endif
 | 
			
		||||
    &mac_method_hmac_sha1,
 | 
			
		||||
    &mac_method_hmac_sha1_96,
 | 
			
		||||
#if LIBSSH2_MD5
 | 
			
		||||
    &mac_method_hmac_md5,
 | 
			
		||||
    &mac_method_hmac_md5_96,
 | 
			
		||||
#endif
 | 
			
		||||
#if LIBSSH2_HMAC_RIPEMD
 | 
			
		||||
    &mac_method_hmac_ripemd160,
 | 
			
		||||
    &mac_method_hmac_ripemd160_openssh_com,
 | 
			
		||||
#endif /* LIBSSH2_HMAC_RIPEMD */
 | 
			
		||||
#ifdef LIBSSH2_MAC_NONE
 | 
			
		||||
    &mac_method_none,
 | 
			
		||||
#endif /* LIBSSH2_MAC_NONE */
 | 
			
		||||
    NULL
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const LIBSSH2_MAC_METHOD **
 | 
			
		||||
_libssh2_mac_methods(void)
 | 
			
		||||
{
 | 
			
		||||
    return mac_methods;
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,68 @@
 | 
			
		|||
#if defined(ESP32)
 | 
			
		||||
#ifndef __LIBSSH2_MAC_H
 | 
			
		||||
#define __LIBSSH2_MAC_H
 | 
			
		||||
/* Copyright (C) 2009-2010 by Daniel Stenberg
 | 
			
		||||
 *
 | 
			
		||||
 * Redistribution and use in source and binary forms,
 | 
			
		||||
 * with or without modification, are permitted provided
 | 
			
		||||
 * that the following conditions are met:
 | 
			
		||||
 *
 | 
			
		||||
 *   Redistributions of source code must retain the above
 | 
			
		||||
 *   copyright notice, this list of conditions and the
 | 
			
		||||
 *   following disclaimer.
 | 
			
		||||
 *
 | 
			
		||||
 *   Redistributions in binary form must reproduce the above
 | 
			
		||||
 *   copyright notice, this list of conditions and the following
 | 
			
		||||
 *   disclaimer in the documentation and/or other materials
 | 
			
		||||
 *   provided with the distribution.
 | 
			
		||||
 *
 | 
			
		||||
 *   Neither the name of the copyright holder nor the names
 | 
			
		||||
 *   of any other contributors may be used to endorse or
 | 
			
		||||
 *   promote products derived from this software without
 | 
			
		||||
 *   specific prior written permission.
 | 
			
		||||
 *
 | 
			
		||||
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
 | 
			
		||||
 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 | 
			
		||||
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 | 
			
		||||
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 | 
			
		||||
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 | 
			
		||||
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | 
			
		||||
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 | 
			
		||||
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 | 
			
		||||
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 | 
			
		||||
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 | 
			
		||||
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 | 
			
		||||
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
 | 
			
		||||
 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
 | 
			
		||||
 * OF SUCH DAMAGE.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "libssh2_priv.h"
 | 
			
		||||
 | 
			
		||||
struct _LIBSSH2_MAC_METHOD
 | 
			
		||||
{
 | 
			
		||||
    const char *name;
 | 
			
		||||
 | 
			
		||||
    /* The length of a given MAC packet */
 | 
			
		||||
    int mac_len;
 | 
			
		||||
 | 
			
		||||
    /* integrity key length */
 | 
			
		||||
    int key_len;
 | 
			
		||||
 | 
			
		||||
    /* Message Authentication Code Hashing algo */
 | 
			
		||||
    int (*init) (LIBSSH2_SESSION * session, unsigned char *key, int *free_key,
 | 
			
		||||
                 void **abstract);
 | 
			
		||||
    int (*hash) (LIBSSH2_SESSION * session, unsigned char *buf,
 | 
			
		||||
                 uint32_t seqno, const unsigned char *packet,
 | 
			
		||||
                 uint32_t packet_len, const unsigned char *addtl,
 | 
			
		||||
                 uint32_t addtl_len, void **abstract);
 | 
			
		||||
    int (*dtor) (LIBSSH2_SESSION * session, void **abstract);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
typedef struct _LIBSSH2_MAC_METHOD LIBSSH2_MAC_METHOD;
 | 
			
		||||
 | 
			
		||||
const LIBSSH2_MAC_METHOD **_libssh2_mac_methods(void);
 | 
			
		||||
 | 
			
		||||
#endif /* __LIBSSH2_MAC_H */
 | 
			
		||||
#endif
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| 
						 | 
				
			
			@ -0,0 +1,611 @@
 | 
			
		|||
#if defined(ESP32)
 | 
			
		||||
#ifndef __LIBSSH2_MBEDTLS_H
 | 
			
		||||
#define __LIBSSH2_MBEDTLS_H
 | 
			
		||||
/* Copyright (c) 2016, Art <https://github.com/wildart>
 | 
			
		||||
 * All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Redistribution and use in source and binary forms,
 | 
			
		||||
 * with or without modification, are permitted provided
 | 
			
		||||
 * that the following conditions are met:
 | 
			
		||||
 *
 | 
			
		||||
 *   Redistributions of source code must retain the above
 | 
			
		||||
 *   copyright notice, this list of conditions and the
 | 
			
		||||
 *   following disclaimer.
 | 
			
		||||
 *
 | 
			
		||||
 *   Redistributions in binary form must reproduce the above
 | 
			
		||||
 *   copyright notice, this list of conditions and the following
 | 
			
		||||
 *   disclaimer in the documentation and/or other materials
 | 
			
		||||
 *   provided with the distribution.
 | 
			
		||||
 *
 | 
			
		||||
 *   Neither the name of the copyright holder nor the names
 | 
			
		||||
 *   of any other contributors may be used to endorse or
 | 
			
		||||
 *   promote products derived from this software without
 | 
			
		||||
 *   specific prior written permission.
 | 
			
		||||
 *
 | 
			
		||||
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
 | 
			
		||||
 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 | 
			
		||||
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 | 
			
		||||
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 | 
			
		||||
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 | 
			
		||||
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | 
			
		||||
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 | 
			
		||||
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 | 
			
		||||
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 | 
			
		||||
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 | 
			
		||||
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 | 
			
		||||
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
 | 
			
		||||
 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
 | 
			
		||||
 * OF SUCH DAMAGE.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
 | 
			
		||||
#include <mbedtls/platform.h>
 | 
			
		||||
#include <mbedtls/md.h>
 | 
			
		||||
#include <mbedtls/rsa.h>
 | 
			
		||||
#include <mbedtls/bignum.h>
 | 
			
		||||
#include <mbedtls/cipher.h>
 | 
			
		||||
#ifdef MBEDTLS_ECDH_C
 | 
			
		||||
# include <mbedtls/ecdh.h>
 | 
			
		||||
#endif
 | 
			
		||||
#ifdef MBEDTLS_ECDSA_C
 | 
			
		||||
# include <mbedtls/ecdsa.h>
 | 
			
		||||
#endif
 | 
			
		||||
#include <mbedtls/entropy.h>
 | 
			
		||||
#include <mbedtls/ctr_drbg.h>
 | 
			
		||||
#include <mbedtls/pk.h>
 | 
			
		||||
#include <mbedtls/error.h>
 | 
			
		||||
 | 
			
		||||
/* Define which features are supported. */
 | 
			
		||||
#define LIBSSH2_MD5             1
 | 
			
		||||
 | 
			
		||||
#define LIBSSH2_HMAC_RIPEMD     1
 | 
			
		||||
#define LIBSSH2_HMAC_SHA256     1
 | 
			
		||||
#define LIBSSH2_HMAC_SHA512     1
 | 
			
		||||
 | 
			
		||||
#define LIBSSH2_AES             1
 | 
			
		||||
#define LIBSSH2_AES_CTR         1
 | 
			
		||||
#ifdef MBEDTLS_CIPHER_BLOWFISH_CBC
 | 
			
		||||
# define LIBSSH2_BLOWFISH       1
 | 
			
		||||
#else
 | 
			
		||||
# define LIBSSH2_BLOWFISH       0
 | 
			
		||||
#endif
 | 
			
		||||
#ifdef MBEDTLS_CIPHER_ARC4_128
 | 
			
		||||
# define LIBSSH2_RC4            1
 | 
			
		||||
#else
 | 
			
		||||
# define LIBSSH2_RC4            0
 | 
			
		||||
#endif
 | 
			
		||||
#define LIBSSH2_CAST            0
 | 
			
		||||
#define LIBSSH2_3DES            1
 | 
			
		||||
 | 
			
		||||
#define LIBSSH2_RSA             1
 | 
			
		||||
#define LIBSSH2_RSA_SHA2        1
 | 
			
		||||
#define LIBSSH2_DSA             0
 | 
			
		||||
#ifdef MBEDTLS_ECDSA_C
 | 
			
		||||
# define LIBSSH2_ECDSA          1
 | 
			
		||||
#else
 | 
			
		||||
# define LIBSSH2_ECDSA          0
 | 
			
		||||
#endif
 | 
			
		||||
#define LIBSSH2_ED25519         0
 | 
			
		||||
 | 
			
		||||
#define MD5_DIGEST_LENGTH      16
 | 
			
		||||
#define SHA_DIGEST_LENGTH      20
 | 
			
		||||
#define SHA256_DIGEST_LENGTH   32
 | 
			
		||||
#define SHA384_DIGEST_LENGTH   48
 | 
			
		||||
#define SHA512_DIGEST_LENGTH   64
 | 
			
		||||
 | 
			
		||||
#define EC_MAX_POINT_LEN ((528 * 2 / 8) + 1)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*******************************************************************/
 | 
			
		||||
/*
 | 
			
		||||
 * mbedTLS backend: Generic functions
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#define libssh2_crypto_init() \
 | 
			
		||||
  _libssh2_mbedtls_init()
 | 
			
		||||
#define libssh2_crypto_exit() \
 | 
			
		||||
  _libssh2_mbedtls_free()
 | 
			
		||||
 | 
			
		||||
#define _libssh2_random(buf, len) \
 | 
			
		||||
  _libssh2_mbedtls_random(buf, len)
 | 
			
		||||
 | 
			
		||||
#define libssh2_prepare_iovec(vec, len)  /* Empty. */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*******************************************************************/
 | 
			
		||||
/*
 | 
			
		||||
 * mbedTLS backend: HMAC functions
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#define libssh2_hmac_ctx    mbedtls_md_context_t
 | 
			
		||||
 | 
			
		||||
#define libssh2_hmac_ctx_init(ctx)
 | 
			
		||||
#define libssh2_hmac_cleanup(pctx) \
 | 
			
		||||
  mbedtls_md_free(pctx)
 | 
			
		||||
#define libssh2_hmac_update(ctx, data, datalen) \
 | 
			
		||||
  mbedtls_md_hmac_update(&ctx, (unsigned char *) data, datalen)
 | 
			
		||||
#define libssh2_hmac_final(ctx, hash) \
 | 
			
		||||
  mbedtls_md_hmac_finish(&ctx, hash)
 | 
			
		||||
 | 
			
		||||
#define libssh2_hmac_sha1_init(pctx, key, keylen) \
 | 
			
		||||
  _libssh2_mbedtls_hash_init(pctx, MBEDTLS_MD_SHA1, key, keylen)
 | 
			
		||||
#define libssh2_hmac_md5_init(pctx, key, keylen) \
 | 
			
		||||
  _libssh2_mbedtls_hash_init(pctx, MBEDTLS_MD_MD5, key, keylen)
 | 
			
		||||
#define libssh2_hmac_ripemd160_init(pctx, key, keylen) \
 | 
			
		||||
  _libssh2_mbedtls_hash_init(pctx, MBEDTLS_MD_RIPEMD160, key, keylen)
 | 
			
		||||
#define libssh2_hmac_sha256_init(pctx, key, keylen) \
 | 
			
		||||
  _libssh2_mbedtls_hash_init(pctx, MBEDTLS_MD_SHA256, key, keylen)
 | 
			
		||||
#define libssh2_hmac_sha384_init(pctx, key, keylen) \
 | 
			
		||||
  _libssh2_mbedtls_hash_init(pctx, MBEDTLS_MD_SHA384, key, keylen)
 | 
			
		||||
#define libssh2_hmac_sha512_init(pctx, key, keylen) \
 | 
			
		||||
  _libssh2_mbedtls_hash_init(pctx, MBEDTLS_MD_SHA512, key, keylen)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*******************************************************************/
 | 
			
		||||
/*
 | 
			
		||||
 * mbedTLS backend: SHA1 functions
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#define libssh2_sha1_ctx      mbedtls_md_context_t
 | 
			
		||||
 | 
			
		||||
#define libssh2_sha1_init(pctx) \
 | 
			
		||||
  _libssh2_mbedtls_hash_init(pctx, MBEDTLS_MD_SHA1, NULL, 0)
 | 
			
		||||
#define libssh2_sha1_update(ctx, data, datalen) \
 | 
			
		||||
  mbedtls_md_update(&ctx, (unsigned char *) data, datalen)
 | 
			
		||||
#define libssh2_sha1_final(ctx, hash) \
 | 
			
		||||
  _libssh2_mbedtls_hash_final(&ctx, hash)
 | 
			
		||||
#define libssh2_sha1(data, datalen, hash) \
 | 
			
		||||
  _libssh2_mbedtls_hash(data, datalen, MBEDTLS_MD_SHA1, hash)
 | 
			
		||||
 | 
			
		||||
/*******************************************************************/
 | 
			
		||||
/*
 | 
			
		||||
 * mbedTLS backend: SHA256 functions
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#define libssh2_sha256_ctx      mbedtls_md_context_t
 | 
			
		||||
 | 
			
		||||
#define libssh2_sha256_init(pctx) \
 | 
			
		||||
  _libssh2_mbedtls_hash_init(pctx, MBEDTLS_MD_SHA256, NULL, 0)
 | 
			
		||||
#define libssh2_sha256_update(ctx, data, datalen) \
 | 
			
		||||
  mbedtls_md_update(&ctx, (unsigned char *) data, datalen)
 | 
			
		||||
#define libssh2_sha256_final(ctx, hash) \
 | 
			
		||||
  _libssh2_mbedtls_hash_final(&ctx, hash)
 | 
			
		||||
#define libssh2_sha256(data, datalen, hash) \
 | 
			
		||||
  _libssh2_mbedtls_hash(data, datalen, MBEDTLS_MD_SHA256, hash)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*******************************************************************/
 | 
			
		||||
/*
 | 
			
		||||
 * mbedTLS backend: SHA384 functions
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#define libssh2_sha384_ctx      mbedtls_md_context_t
 | 
			
		||||
 | 
			
		||||
#define libssh2_sha384_init(pctx) \
 | 
			
		||||
  _libssh2_mbedtls_hash_init(pctx, MBEDTLS_MD_SHA384, NULL, 0)
 | 
			
		||||
#define libssh2_sha384_update(ctx, data, datalen) \
 | 
			
		||||
  mbedtls_md_update(&ctx, (unsigned char *) data, datalen)
 | 
			
		||||
#define libssh2_sha384_final(ctx, hash) \
 | 
			
		||||
  _libssh2_mbedtls_hash_final(&ctx, hash)
 | 
			
		||||
#define libssh2_sha384(data, datalen, hash) \
 | 
			
		||||
  _libssh2_mbedtls_hash(data, datalen, MBEDTLS_MD_SHA384, hash)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*******************************************************************/
 | 
			
		||||
/*
 | 
			
		||||
 * mbedTLS backend: SHA512 functions
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#define libssh2_sha512_ctx      mbedtls_md_context_t
 | 
			
		||||
 | 
			
		||||
#define libssh2_sha512_init(pctx) \
 | 
			
		||||
  _libssh2_mbedtls_hash_init(pctx, MBEDTLS_MD_SHA512, NULL, 0)
 | 
			
		||||
#define libssh2_sha512_update(ctx, data, datalen) \
 | 
			
		||||
  mbedtls_md_update(&ctx, (unsigned char *) data, datalen)
 | 
			
		||||
#define libssh2_sha512_final(ctx, hash) \
 | 
			
		||||
  _libssh2_mbedtls_hash_final(&ctx, hash)
 | 
			
		||||
#define libssh2_sha512(data, datalen, hash) \
 | 
			
		||||
  _libssh2_mbedtls_hash(data, datalen, MBEDTLS_MD_SHA512, hash)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*******************************************************************/
 | 
			
		||||
/*
 | 
			
		||||
 * mbedTLS backend: MD5 functions
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#define libssh2_md5_ctx      mbedtls_md_context_t
 | 
			
		||||
 | 
			
		||||
#define libssh2_md5_init(pctx) \
 | 
			
		||||
  _libssh2_mbedtls_hash_init(pctx, MBEDTLS_MD_MD5, NULL, 0)
 | 
			
		||||
#define libssh2_md5_update(ctx, data, datalen) \
 | 
			
		||||
  mbedtls_md_update(&ctx, (unsigned char *) data, datalen)
 | 
			
		||||
#define libssh2_md5_final(ctx, hash) \
 | 
			
		||||
  _libssh2_mbedtls_hash_final(&ctx, hash)
 | 
			
		||||
#define libssh2_md5(data, datalen, hash) \
 | 
			
		||||
  _libssh2_mbedtls_hash(data, datalen, MBEDTLS_MD_MD5, hash)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*******************************************************************/
 | 
			
		||||
/*
 | 
			
		||||
 * mbedTLS backend: RSA functions
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#define libssh2_rsa_ctx  mbedtls_rsa_context
 | 
			
		||||
 | 
			
		||||
#define _libssh2_rsa_new(rsactx, e, e_len, n, n_len, \
 | 
			
		||||
                         d, d_len, p, p_len, q, q_len, \
 | 
			
		||||
                         e1, e1_len, e2, e2_len, c, c_len) \
 | 
			
		||||
  _libssh2_mbedtls_rsa_new(rsactx, e, e_len, n, n_len, \
 | 
			
		||||
                          d, d_len, p, p_len, q, q_len, \
 | 
			
		||||
                          e1, e1_len, e2, e2_len, c, c_len)
 | 
			
		||||
 | 
			
		||||
#define _libssh2_rsa_new_private(rsactx, s, filename, passphrase) \
 | 
			
		||||
  _libssh2_mbedtls_rsa_new_private(rsactx, s, filename, passphrase)
 | 
			
		||||
 | 
			
		||||
#define _libssh2_rsa_new_private_frommemory(rsactx, s, filedata, \
 | 
			
		||||
                                            filedata_len, passphrase) \
 | 
			
		||||
  _libssh2_mbedtls_rsa_new_private_frommemory(rsactx, s, filedata, \
 | 
			
		||||
                                             filedata_len, passphrase)
 | 
			
		||||
 | 
			
		||||
#define _libssh2_rsa_sha1_sign(s, rsactx, hash, hash_len, sig, sig_len) \
 | 
			
		||||
  _libssh2_mbedtls_rsa_sha1_sign(s, rsactx, hash, hash_len, sig, sig_len)
 | 
			
		||||
 | 
			
		||||
#define _libssh2_rsa_sha2_sign(s, rsactx, hash, hash_len, sig, sig_len) \
 | 
			
		||||
  _libssh2_mbedtls_rsa_sha2_sign(s, rsactx, hash, hash_len, sig, sig_len)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#define _libssh2_rsa_sha1_verify(rsactx, sig, sig_len, m, m_len) \
 | 
			
		||||
  _libssh2_mbedtls_rsa_sha1_verify(rsactx, sig, sig_len, m, m_len)
 | 
			
		||||
 | 
			
		||||
#define _libssh2_rsa_sha2_verify(rsactx, hash_len, sig, sig_len, m, m_len) \
 | 
			
		||||
  _libssh2_mbedtls_rsa_sha2_verify(rsactx, hash_len, sig, sig_len, m, m_len)
 | 
			
		||||
 | 
			
		||||
#define _libssh2_rsa_free(rsactx) \
 | 
			
		||||
  _libssh2_mbedtls_rsa_free(rsactx)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*******************************************************************/
 | 
			
		||||
/*
 | 
			
		||||
 * mbedTLS backend: ECDSA structures
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#if LIBSSH2_ECDSA
 | 
			
		||||
 | 
			
		||||
typedef enum {
 | 
			
		||||
#ifdef MBEDTLS_ECP_DP_SECP256R1_ENABLED
 | 
			
		||||
    LIBSSH2_EC_CURVE_NISTP256 = MBEDTLS_ECP_DP_SECP256R1,
 | 
			
		||||
#else
 | 
			
		||||
    LIBSSH2_EC_CURVE_NISTP256 = MBEDTLS_ECP_DP_NONE,
 | 
			
		||||
#endif
 | 
			
		||||
#ifdef MBEDTLS_ECP_DP_SECP384R1_ENABLED
 | 
			
		||||
    LIBSSH2_EC_CURVE_NISTP384 = MBEDTLS_ECP_DP_SECP384R1,
 | 
			
		||||
#else
 | 
			
		||||
    LIBSSH2_EC_CURVE_NISTP384 = MBEDTLS_ECP_DP_NONE,
 | 
			
		||||
#endif
 | 
			
		||||
#ifdef MBEDTLS_ECP_DP_SECP521R1_ENABLED
 | 
			
		||||
    LIBSSH2_EC_CURVE_NISTP521 = MBEDTLS_ECP_DP_SECP521R1
 | 
			
		||||
#else
 | 
			
		||||
    LIBSSH2_EC_CURVE_NISTP521 = MBEDTLS_ECP_DP_NONE,
 | 
			
		||||
#endif
 | 
			
		||||
} libssh2_curve_type;
 | 
			
		||||
 | 
			
		||||
# define _libssh2_ec_key mbedtls_ecp_keypair
 | 
			
		||||
#else
 | 
			
		||||
# define _libssh2_ec_key void
 | 
			
		||||
#endif /* LIBSSH2_ECDSA */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*******************************************************************/
 | 
			
		||||
/*
 | 
			
		||||
 * mbedTLS backend: ECDSA functions
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#if LIBSSH2_ECDSA
 | 
			
		||||
 | 
			
		||||
#define libssh2_ecdsa_ctx mbedtls_ecdsa_context
 | 
			
		||||
 | 
			
		||||
#define _libssh2_ecdsa_create_key(session, privkey, pubkey_octal, \
 | 
			
		||||
                                  pubkey_octal_len, curve) \
 | 
			
		||||
  _libssh2_mbedtls_ecdsa_create_key(session, privkey, pubkey_octal, \
 | 
			
		||||
                                    pubkey_octal_len, curve)
 | 
			
		||||
 | 
			
		||||
#define _libssh2_ecdsa_curve_name_with_octal_new(ctx, k, k_len, curve) \
 | 
			
		||||
  _libssh2_mbedtls_ecdsa_curve_name_with_octal_new(ctx, k, k_len, curve)
 | 
			
		||||
 | 
			
		||||
#define _libssh2_ecdh_gen_k(k, privkey, server_pubkey, server_pubkey_len) \
 | 
			
		||||
  _libssh2_mbedtls_ecdh_gen_k(k, privkey, server_pubkey, server_pubkey_len)
 | 
			
		||||
 | 
			
		||||
#define _libssh2_ecdsa_verify(ctx, r, r_len, s, s_len, m, m_len) \
 | 
			
		||||
  _libssh2_mbedtls_ecdsa_verify(ctx, r, r_len, s, s_len, m, m_len)
 | 
			
		||||
 | 
			
		||||
#define _libssh2_ecdsa_new_private(ctx, session, filename, passphrase) \
 | 
			
		||||
  _libssh2_mbedtls_ecdsa_new_private(ctx, session, filename, passphrase)
 | 
			
		||||
 | 
			
		||||
#define _libssh2_ecdsa_new_private_frommemory(ctx, session, filedata, \
 | 
			
		||||
                                              filedata_len, passphrase) \
 | 
			
		||||
  _libssh2_mbedtls_ecdsa_new_private_frommemory(ctx, session, filedata, \
 | 
			
		||||
                                                filedata_len, passphrase)
 | 
			
		||||
 | 
			
		||||
#define _libssh2_ecdsa_sign(session, ctx, hash, hash_len, sign, sign_len) \
 | 
			
		||||
  _libssh2_mbedtls_ecdsa_sign(session, ctx, hash, hash_len, sign, sign_len)
 | 
			
		||||
 | 
			
		||||
#define _libssh2_ecdsa_get_curve_type(ctx) \
 | 
			
		||||
  _libssh2_mbedtls_ecdsa_get_curve_type(ctx)
 | 
			
		||||
 | 
			
		||||
#define _libssh2_ecdsa_free(ctx) \
 | 
			
		||||
  _libssh2_mbedtls_ecdsa_free(ctx)
 | 
			
		||||
 | 
			
		||||
#endif /* LIBSSH2_ECDSA */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*******************************************************************/
 | 
			
		||||
/*
 | 
			
		||||
 * mbedTLS backend: Key functions
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#define _libssh2_pub_priv_keyfile(s, m, m_len, p, p_len, pk, pw) \
 | 
			
		||||
  _libssh2_mbedtls_pub_priv_keyfile(s, m, m_len, p, p_len, pk, pw)
 | 
			
		||||
#define _libssh2_pub_priv_keyfilememory(s, m, m_len, p, p_len, \
 | 
			
		||||
                                                     pk, pk_len, pw) \
 | 
			
		||||
  _libssh2_mbedtls_pub_priv_keyfilememory(s, m, m_len, p, p_len, \
 | 
			
		||||
                                                      pk, pk_len, pw)
 | 
			
		||||
#define _libssh2_sk_pub_keyfilememory(s, m, m_len, p, p_len, alg, app, \
 | 
			
		||||
                                      f, kh, kh_len, pk, pk_len, pw) \
 | 
			
		||||
  _libssh2_mbedtls_sk_pub_keyfilememory(s, m, m_len, p, p_len, alg, app, \
 | 
			
		||||
                                        f, kh, kh_len, pk, pk_len, pw)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*******************************************************************/
 | 
			
		||||
/*
 | 
			
		||||
 * mbedTLS backend: Cipher Context structure
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#define _libssh2_cipher_ctx         mbedtls_cipher_context_t
 | 
			
		||||
 | 
			
		||||
#define _libssh2_cipher_type(algo)  mbedtls_cipher_type_t algo
 | 
			
		||||
 | 
			
		||||
#define _libssh2_cipher_aes256ctr MBEDTLS_CIPHER_AES_256_CTR
 | 
			
		||||
#define _libssh2_cipher_aes192ctr MBEDTLS_CIPHER_AES_192_CTR
 | 
			
		||||
#define _libssh2_cipher_aes128ctr MBEDTLS_CIPHER_AES_128_CTR
 | 
			
		||||
#define _libssh2_cipher_aes256    MBEDTLS_CIPHER_AES_256_CBC
 | 
			
		||||
#define _libssh2_cipher_aes192    MBEDTLS_CIPHER_AES_192_CBC
 | 
			
		||||
#define _libssh2_cipher_aes128    MBEDTLS_CIPHER_AES_128_CBC
 | 
			
		||||
#ifdef MBEDTLS_CIPHER_BLOWFISH_CBC
 | 
			
		||||
#define _libssh2_cipher_blowfish  MBEDTLS_CIPHER_BLOWFISH_CBC
 | 
			
		||||
#endif
 | 
			
		||||
#ifdef MBEDTLS_CIPHER_ARC4_128
 | 
			
		||||
#define _libssh2_cipher_arcfour   MBEDTLS_CIPHER_ARC4_128
 | 
			
		||||
#endif
 | 
			
		||||
#define _libssh2_cipher_3des      MBEDTLS_CIPHER_DES_EDE3_CBC
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*******************************************************************/
 | 
			
		||||
/*
 | 
			
		||||
 * mbedTLS backend: Cipher functions
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#define _libssh2_cipher_init(ctx, type, iv, secret, encrypt) \
 | 
			
		||||
  _libssh2_mbedtls_cipher_init(ctx, type, iv, secret, encrypt)
 | 
			
		||||
#define _libssh2_cipher_crypt(ctx, type, encrypt, block, blocklen) \
 | 
			
		||||
  _libssh2_mbedtls_cipher_crypt(ctx, type, encrypt, block, blocklen)
 | 
			
		||||
#define _libssh2_cipher_dtor(ctx) \
 | 
			
		||||
  _libssh2_mbedtls_cipher_dtor(ctx)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*******************************************************************/
 | 
			
		||||
/*
 | 
			
		||||
 * mbedTLS backend: BigNumber Support
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#define _libssh2_bn_ctx int /* not used */
 | 
			
		||||
#define _libssh2_bn_ctx_new() 0 /* not used */
 | 
			
		||||
#define _libssh2_bn_ctx_free(bnctx) ((void)0) /* not used */
 | 
			
		||||
 | 
			
		||||
#define _libssh2_bn mbedtls_mpi
 | 
			
		||||
 | 
			
		||||
#define _libssh2_bn_init() \
 | 
			
		||||
  _libssh2_mbedtls_bignum_init()
 | 
			
		||||
#define _libssh2_bn_init_from_bin() \
 | 
			
		||||
  _libssh2_mbedtls_bignum_init()
 | 
			
		||||
#define _libssh2_bn_set_word(bn, word) \
 | 
			
		||||
  mbedtls_mpi_lset(bn, word)
 | 
			
		||||
#define _libssh2_bn_from_bin(bn, len, bin) \
 | 
			
		||||
  mbedtls_mpi_read_binary(bn, bin, len)
 | 
			
		||||
#define _libssh2_bn_to_bin(bn, bin) \
 | 
			
		||||
  mbedtls_mpi_write_binary(bn, bin, mbedtls_mpi_size(bn))
 | 
			
		||||
#define _libssh2_bn_bytes(bn) \
 | 
			
		||||
  mbedtls_mpi_size(bn)
 | 
			
		||||
#define _libssh2_bn_bits(bn) \
 | 
			
		||||
  mbedtls_mpi_bitlen(bn)
 | 
			
		||||
#define _libssh2_bn_free(bn) \
 | 
			
		||||
  _libssh2_mbedtls_bignum_free(bn)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*******************************************************************/
 | 
			
		||||
/*
 | 
			
		||||
 * mbedTLS backend: Diffie-Hellman support.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#define _libssh2_dh_ctx mbedtls_mpi *
 | 
			
		||||
#define libssh2_dh_init(dhctx) _libssh2_dh_init(dhctx)
 | 
			
		||||
#define libssh2_dh_key_pair(dhctx, public, g, p, group_order, bnctx) \
 | 
			
		||||
        _libssh2_dh_key_pair(dhctx, public, g, p, group_order)
 | 
			
		||||
#define libssh2_dh_secret(dhctx, secret, f, p, bnctx) \
 | 
			
		||||
        _libssh2_dh_secret(dhctx, secret, f, p)
 | 
			
		||||
#define libssh2_dh_dtor(dhctx) _libssh2_dh_dtor(dhctx)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*******************************************************************/
 | 
			
		||||
/*
 | 
			
		||||
 * mbedTLS backend: forward declarations
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
_libssh2_mbedtls_init(void);
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
_libssh2_mbedtls_free(void);
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
_libssh2_mbedtls_random(unsigned char *buf, int len);
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
_libssh2_mbedtls_cipher_init(_libssh2_cipher_ctx *ctx,
 | 
			
		||||
                            _libssh2_cipher_type(type),
 | 
			
		||||
                            unsigned char *iv,
 | 
			
		||||
                            unsigned char *secret,
 | 
			
		||||
                            int encrypt);
 | 
			
		||||
int
 | 
			
		||||
_libssh2_mbedtls_cipher_crypt(_libssh2_cipher_ctx *ctx,
 | 
			
		||||
                             _libssh2_cipher_type(type),
 | 
			
		||||
                             int encrypt,
 | 
			
		||||
                             unsigned char *block,
 | 
			
		||||
                             size_t blocklen);
 | 
			
		||||
void
 | 
			
		||||
_libssh2_mbedtls_cipher_dtor(_libssh2_cipher_ctx *ctx);
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
_libssh2_mbedtls_hash_init(mbedtls_md_context_t *ctx,
 | 
			
		||||
                          mbedtls_md_type_t mdtype,
 | 
			
		||||
                          const unsigned char *key, unsigned long keylen);
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
_libssh2_mbedtls_hash_final(mbedtls_md_context_t *ctx, unsigned char *hash);
 | 
			
		||||
int
 | 
			
		||||
_libssh2_mbedtls_hash(const unsigned char *data, unsigned long datalen,
 | 
			
		||||
                      mbedtls_md_type_t mdtype, unsigned char *hash);
 | 
			
		||||
 | 
			
		||||
_libssh2_bn *
 | 
			
		||||
_libssh2_mbedtls_bignum_init(void);
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
_libssh2_mbedtls_bignum_free(_libssh2_bn *bn);
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
_libssh2_mbedtls_rsa_new(libssh2_rsa_ctx **rsa,
 | 
			
		||||
                        const unsigned char *edata,
 | 
			
		||||
                        unsigned long elen,
 | 
			
		||||
                        const unsigned char *ndata,
 | 
			
		||||
                        unsigned long nlen,
 | 
			
		||||
                        const unsigned char *ddata,
 | 
			
		||||
                        unsigned long dlen,
 | 
			
		||||
                        const unsigned char *pdata,
 | 
			
		||||
                        unsigned long plen,
 | 
			
		||||
                        const unsigned char *qdata,
 | 
			
		||||
                        unsigned long qlen,
 | 
			
		||||
                        const unsigned char *e1data,
 | 
			
		||||
                        unsigned long e1len,
 | 
			
		||||
                        const unsigned char *e2data,
 | 
			
		||||
                        unsigned long e2len,
 | 
			
		||||
                        const unsigned char *coeffdata,
 | 
			
		||||
                        unsigned long coefflen);
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
_libssh2_mbedtls_rsa_new_private(libssh2_rsa_ctx **rsa,
 | 
			
		||||
                                LIBSSH2_SESSION *session,
 | 
			
		||||
                                const char *filename,
 | 
			
		||||
                                const unsigned char *passphrase);
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
_libssh2_mbedtls_rsa_new_private_frommemory(libssh2_rsa_ctx **rsa,
 | 
			
		||||
                                           LIBSSH2_SESSION *session,
 | 
			
		||||
                                           const char *filedata,
 | 
			
		||||
                                           size_t filedata_len,
 | 
			
		||||
                                           unsigned const char *passphrase);
 | 
			
		||||
int
 | 
			
		||||
_libssh2_mbedtls_rsa_sha1_verify(libssh2_rsa_ctx *rsa,
 | 
			
		||||
                                const unsigned char *sig,
 | 
			
		||||
                                unsigned long sig_len,
 | 
			
		||||
                                const unsigned char *m,
 | 
			
		||||
                                unsigned long m_len);
 | 
			
		||||
int
 | 
			
		||||
_libssh2_mbedtls_rsa_sha1_sign(LIBSSH2_SESSION *session,
 | 
			
		||||
                              libssh2_rsa_ctx *rsa,
 | 
			
		||||
                              const unsigned char *hash,
 | 
			
		||||
                              size_t hash_len,
 | 
			
		||||
                              unsigned char **signature,
 | 
			
		||||
                              size_t *signature_len);
 | 
			
		||||
void
 | 
			
		||||
_libssh2_mbedtls_rsa_free(libssh2_rsa_ctx *rsa);
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
_libssh2_mbedtls_pub_priv_keyfile(LIBSSH2_SESSION *session,
 | 
			
		||||
                                 unsigned char **method,
 | 
			
		||||
                                 size_t *method_len,
 | 
			
		||||
                                 unsigned char **pubkeydata,
 | 
			
		||||
                                 size_t *pubkeydata_len,
 | 
			
		||||
                                 const char *privatekey,
 | 
			
		||||
                                 const char *passphrase);
 | 
			
		||||
int
 | 
			
		||||
_libssh2_mbedtls_pub_priv_keyfilememory(LIBSSH2_SESSION *session,
 | 
			
		||||
                                       unsigned char **method,
 | 
			
		||||
                                       size_t *method_len,
 | 
			
		||||
                                       unsigned char **pubkeydata,
 | 
			
		||||
                                       size_t *pubkeydata_len,
 | 
			
		||||
                                       const char *privatekeydata,
 | 
			
		||||
                                       size_t privatekeydata_len,
 | 
			
		||||
                                       const char *passphrase);
 | 
			
		||||
#if LIBSSH2_ECDSA
 | 
			
		||||
int
 | 
			
		||||
_libssh2_mbedtls_ecdsa_create_key(LIBSSH2_SESSION *session,
 | 
			
		||||
                                  _libssh2_ec_key **privkey,
 | 
			
		||||
                                  unsigned char **pubkey_octal,
 | 
			
		||||
                                  size_t *pubkey_octal_len,
 | 
			
		||||
                                  libssh2_curve_type curve);
 | 
			
		||||
int
 | 
			
		||||
_libssh2_mbedtls_ecdsa_curve_name_with_octal_new(libssh2_ecdsa_ctx **ctx,
 | 
			
		||||
                                                 const unsigned char *k,
 | 
			
		||||
                                                 size_t k_len,
 | 
			
		||||
                                                 libssh2_curve_type curve);
 | 
			
		||||
int
 | 
			
		||||
_libssh2_mbedtls_ecdh_gen_k(_libssh2_bn **k,
 | 
			
		||||
                            _libssh2_ec_key *privkey,
 | 
			
		||||
                            const unsigned char *server_pubkey,
 | 
			
		||||
                            size_t server_pubkey_len);
 | 
			
		||||
int
 | 
			
		||||
_libssh2_mbedtls_ecdsa_verify(libssh2_ecdsa_ctx *ctx,
 | 
			
		||||
                              const unsigned char *r, size_t r_len,
 | 
			
		||||
                              const unsigned char *s, size_t s_len,
 | 
			
		||||
                              const unsigned char *m, size_t m_len);
 | 
			
		||||
int
 | 
			
		||||
_libssh2_mbedtls_ecdsa_new_private(libssh2_ecdsa_ctx **ctx,
 | 
			
		||||
                                  LIBSSH2_SESSION *session,
 | 
			
		||||
                                  const char *filename,
 | 
			
		||||
                                  const unsigned char *passphrase);
 | 
			
		||||
int
 | 
			
		||||
_libssh2_mbedtls_ecdsa_new_private_frommemory(libssh2_ecdsa_ctx **ctx,
 | 
			
		||||
                                              LIBSSH2_SESSION *session,
 | 
			
		||||
                                              const char *filedata,
 | 
			
		||||
                                              size_t filedata_len,
 | 
			
		||||
                                              const unsigned char *passphrase);
 | 
			
		||||
int
 | 
			
		||||
_libssh2_mbedtls_ecdsa_sign(LIBSSH2_SESSION *session,
 | 
			
		||||
                            libssh2_ecdsa_ctx *ctx,
 | 
			
		||||
                            const unsigned char *hash,
 | 
			
		||||
                            unsigned long hash_len,
 | 
			
		||||
                            unsigned char **signature,
 | 
			
		||||
                            size_t *signature_len);
 | 
			
		||||
libssh2_curve_type
 | 
			
		||||
_libssh2_mbedtls_ecdsa_key_get_curve_type(libssh2_ecdsa_ctx *ctx);
 | 
			
		||||
int
 | 
			
		||||
_libssh2_mbedtls_ecdsa_curve_type_from_name(const char *name,
 | 
			
		||||
                                            libssh2_curve_type *type);
 | 
			
		||||
void
 | 
			
		||||
_libssh2_mbedtls_ecdsa_free(libssh2_ecdsa_ctx *ctx);
 | 
			
		||||
#endif /* LIBSSH2_ECDSA */
 | 
			
		||||
 | 
			
		||||
extern void
 | 
			
		||||
_libssh2_dh_init(_libssh2_dh_ctx *dhctx);
 | 
			
		||||
extern int
 | 
			
		||||
_libssh2_dh_key_pair(_libssh2_dh_ctx *dhctx, _libssh2_bn *public,
 | 
			
		||||
                    _libssh2_bn *g, _libssh2_bn *p, int group_order);
 | 
			
		||||
extern int
 | 
			
		||||
_libssh2_dh_secret(_libssh2_dh_ctx *dhctx, _libssh2_bn *secret,
 | 
			
		||||
                  _libssh2_bn *f, _libssh2_bn *p);
 | 
			
		||||
extern void
 | 
			
		||||
_libssh2_dh_dtor(_libssh2_dh_ctx *dhctx);
 | 
			
		||||
 | 
			
		||||
#endif /* __LIBSSH2_MBEDTLS_H */
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,932 @@
 | 
			
		|||
#if defined(ESP32)
 | 
			
		||||
/* Copyright (c) 2004-2007 Sara Golemon <sarag@libssh2.org>
 | 
			
		||||
 * Copyright (c) 2009-2019 by Daniel Stenberg
 | 
			
		||||
 * Copyright (c) 2010  Simon Josefsson
 | 
			
		||||
 * All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Redistribution and use in source and binary forms,
 | 
			
		||||
 * with or without modification, are permitted provided
 | 
			
		||||
 * that the following conditions are met:
 | 
			
		||||
 *
 | 
			
		||||
 *   Redistributions of source code must retain the above
 | 
			
		||||
 *   copyright notice, this list of conditions and the
 | 
			
		||||
 *   following disclaimer.
 | 
			
		||||
 *
 | 
			
		||||
 *   Redistributions in binary form must reproduce the above
 | 
			
		||||
 *   copyright notice, this list of conditions and the following
 | 
			
		||||
 *   disclaimer in the documentation and/or other materials
 | 
			
		||||
 *   provided with the distribution.
 | 
			
		||||
 *
 | 
			
		||||
 *   Neither the name of the copyright holder nor the names
 | 
			
		||||
 *   of any other contributors may be used to endorse or
 | 
			
		||||
 *   promote products derived from this software without
 | 
			
		||||
 *   specific prior written permission.
 | 
			
		||||
 *
 | 
			
		||||
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
 | 
			
		||||
 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 | 
			
		||||
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 | 
			
		||||
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 | 
			
		||||
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 | 
			
		||||
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | 
			
		||||
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 | 
			
		||||
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 | 
			
		||||
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 | 
			
		||||
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 | 
			
		||||
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 | 
			
		||||
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
 | 
			
		||||
 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
 | 
			
		||||
 * OF SUCH DAMAGE.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "libssh2_priv.h"
 | 
			
		||||
#include "misc.h"
 | 
			
		||||
#include "blf.h"
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_STDLIB_H
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_UNISTD_H
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_SYS_TIME_H
 | 
			
		||||
#include <sys/time.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef WIN32
 | 
			
		||||
#include <windows.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
 | 
			
		||||
int _libssh2_error_flags(LIBSSH2_SESSION* session, int errcode,
 | 
			
		||||
                         const char *errmsg, int errflags)
 | 
			
		||||
{
 | 
			
		||||
    if(session == NULL) {
 | 
			
		||||
        if(errmsg != NULL)
 | 
			
		||||
            fprintf(stderr, "Session is NULL, error: %s\n", errmsg);
 | 
			
		||||
        return errcode;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if(session->err_flags & LIBSSH2_ERR_FLAG_DUP)
 | 
			
		||||
        LIBSSH2_FREE(session, (char *)session->err_msg);
 | 
			
		||||
 | 
			
		||||
    session->err_code = errcode;
 | 
			
		||||
    session->err_flags = 0;
 | 
			
		||||
 | 
			
		||||
    if((errmsg != NULL) && ((errflags & LIBSSH2_ERR_FLAG_DUP) != 0)) {
 | 
			
		||||
        size_t len = strlen(errmsg);
 | 
			
		||||
        char *copy = LIBSSH2_ALLOC(session, len + 1);
 | 
			
		||||
        if(copy) {
 | 
			
		||||
            memcpy(copy, errmsg, len + 1);
 | 
			
		||||
            session->err_flags = LIBSSH2_ERR_FLAG_DUP;
 | 
			
		||||
            session->err_msg = copy;
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
            /* Out of memory: this code path is very unlikely */
 | 
			
		||||
            session->err_msg = "former error forgotten (OOM)";
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
        session->err_msg = errmsg;
 | 
			
		||||
 | 
			
		||||
#ifdef LIBSSH2DEBUG
 | 
			
		||||
    if((errcode == LIBSSH2_ERROR_EAGAIN) && !session->api_block_mode)
 | 
			
		||||
        /* if this is EAGAIN and we're in non-blocking mode, don't generate
 | 
			
		||||
           a debug output for this */
 | 
			
		||||
        return errcode;
 | 
			
		||||
    _libssh2_debug(session, LIBSSH2_TRACE_ERROR, "%d - %s", session->err_code,
 | 
			
		||||
                   session->err_msg);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    return errcode;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int _libssh2_error(LIBSSH2_SESSION* session, int errcode, const char *errmsg)
 | 
			
		||||
{
 | 
			
		||||
    return _libssh2_error_flags(session, errcode, errmsg, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef WIN32
 | 
			
		||||
static int wsa2errno(void)
 | 
			
		||||
{
 | 
			
		||||
    switch(WSAGetLastError()) {
 | 
			
		||||
    case WSAEWOULDBLOCK:
 | 
			
		||||
        return EAGAIN;
 | 
			
		||||
 | 
			
		||||
    case WSAENOTSOCK:
 | 
			
		||||
        return EBADF;
 | 
			
		||||
 | 
			
		||||
    case WSAEINTR:
 | 
			
		||||
        return EINTR;
 | 
			
		||||
 | 
			
		||||
    default:
 | 
			
		||||
        /* It is most important to ensure errno does not stay at EAGAIN
 | 
			
		||||
         * when a different error occurs so just set errno to a generic
 | 
			
		||||
         * error */
 | 
			
		||||
        return EIO;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/* _libssh2_recv
 | 
			
		||||
 *
 | 
			
		||||
 * Replacement for the standard recv, return -errno on failure.
 | 
			
		||||
 */
 | 
			
		||||
ssize_t
 | 
			
		||||
_libssh2_recv(libssh2_socket_t sock, void *buffer, size_t length,
 | 
			
		||||
              int flags, void **abstract)
 | 
			
		||||
{
 | 
			
		||||
    ssize_t rc;
 | 
			
		||||
 | 
			
		||||
    (void) abstract;
 | 
			
		||||
 | 
			
		||||
    rc = recv(sock, buffer, length, flags);
 | 
			
		||||
#ifdef WIN32
 | 
			
		||||
    if(rc < 0)
 | 
			
		||||
        return -wsa2errno();
 | 
			
		||||
#else
 | 
			
		||||
    if(rc < 0) {
 | 
			
		||||
        /* Sometimes the first recv() function call sets errno to ENOENT on
 | 
			
		||||
           Solaris and HP-UX */
 | 
			
		||||
        if(errno == ENOENT)
 | 
			
		||||
            return -EAGAIN;
 | 
			
		||||
#ifdef EWOULDBLOCK /* For VMS and other special unixes */
 | 
			
		||||
        else if(errno == EWOULDBLOCK)
 | 
			
		||||
          return -EAGAIN;
 | 
			
		||||
#endif
 | 
			
		||||
        else
 | 
			
		||||
            return -errno;
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
    return rc;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* _libssh2_send
 | 
			
		||||
 *
 | 
			
		||||
 * Replacement for the standard send, return -errno on failure.
 | 
			
		||||
 */
 | 
			
		||||
ssize_t
 | 
			
		||||
_libssh2_send(libssh2_socket_t sock, const void *buffer, size_t length,
 | 
			
		||||
              int flags, void **abstract)
 | 
			
		||||
{
 | 
			
		||||
    ssize_t rc;
 | 
			
		||||
 | 
			
		||||
    (void) abstract;
 | 
			
		||||
 | 
			
		||||
    rc = send(sock, buffer, length, flags);
 | 
			
		||||
#ifdef WIN32
 | 
			
		||||
    if(rc < 0)
 | 
			
		||||
        return -wsa2errno();
 | 
			
		||||
#else
 | 
			
		||||
    if(rc < 0) {
 | 
			
		||||
#ifdef EWOULDBLOCK /* For VMS and other special unixes */
 | 
			
		||||
      if(errno == EWOULDBLOCK)
 | 
			
		||||
        return -EAGAIN;
 | 
			
		||||
#endif
 | 
			
		||||
      return -errno;
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
    return rc;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* libssh2_ntohu32
 | 
			
		||||
 */
 | 
			
		||||
unsigned int
 | 
			
		||||
_libssh2_ntohu32(const unsigned char *buf)
 | 
			
		||||
{
 | 
			
		||||
    return (((unsigned int)buf[0] << 24)
 | 
			
		||||
           | ((unsigned int)buf[1] << 16)
 | 
			
		||||
           | ((unsigned int)buf[2] << 8)
 | 
			
		||||
           | ((unsigned int)buf[3]));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* _libssh2_ntohu64
 | 
			
		||||
 */
 | 
			
		||||
libssh2_uint64_t
 | 
			
		||||
_libssh2_ntohu64(const unsigned char *buf)
 | 
			
		||||
{
 | 
			
		||||
    unsigned long msl, lsl;
 | 
			
		||||
 | 
			
		||||
    msl = ((libssh2_uint64_t)buf[0] << 24) | ((libssh2_uint64_t)buf[1] << 16)
 | 
			
		||||
        | ((libssh2_uint64_t)buf[2] << 8) | (libssh2_uint64_t)buf[3];
 | 
			
		||||
    lsl = ((libssh2_uint64_t)buf[4] << 24) | ((libssh2_uint64_t)buf[5] << 16)
 | 
			
		||||
        | ((libssh2_uint64_t)buf[6] << 8) | (libssh2_uint64_t)buf[7];
 | 
			
		||||
 | 
			
		||||
    return ((libssh2_uint64_t)msl <<32) | lsl;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* _libssh2_htonu32
 | 
			
		||||
 */
 | 
			
		||||
void
 | 
			
		||||
_libssh2_htonu32(unsigned char *buf, uint32_t value)
 | 
			
		||||
{
 | 
			
		||||
    buf[0] = (value >> 24) & 0xFF;
 | 
			
		||||
    buf[1] = (value >> 16) & 0xFF;
 | 
			
		||||
    buf[2] = (value >> 8) & 0xFF;
 | 
			
		||||
    buf[3] = value & 0xFF;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* _libssh2_store_u32
 | 
			
		||||
 */
 | 
			
		||||
void _libssh2_store_u32(unsigned char **buf, uint32_t value)
 | 
			
		||||
{
 | 
			
		||||
    _libssh2_htonu32(*buf, value);
 | 
			
		||||
    *buf += sizeof(uint32_t);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* _libssh2_store_str
 | 
			
		||||
 */
 | 
			
		||||
void _libssh2_store_str(unsigned char **buf, const char *str, size_t len)
 | 
			
		||||
{
 | 
			
		||||
    _libssh2_store_u32(buf, (uint32_t)len);
 | 
			
		||||
    if(len) {
 | 
			
		||||
        memcpy(*buf, str, len);
 | 
			
		||||
        *buf += len;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* _libssh2_store_bignum2_bytes
 | 
			
		||||
 */
 | 
			
		||||
void _libssh2_store_bignum2_bytes(unsigned char **buf,
 | 
			
		||||
                                  const unsigned char *bytes,
 | 
			
		||||
                                  size_t len)
 | 
			
		||||
{
 | 
			
		||||
    int extraByte = 0;
 | 
			
		||||
    const unsigned char *p;
 | 
			
		||||
    for(p = bytes; len > 0 && *p == 0; --len, ++p) {}
 | 
			
		||||
 | 
			
		||||
    extraByte = (len > 0 && (p[0] & 0x80) != 0);
 | 
			
		||||
    _libssh2_store_u32(buf, len + extraByte);
 | 
			
		||||
 | 
			
		||||
    if(extraByte) {
 | 
			
		||||
        *buf[0] = 0;
 | 
			
		||||
        *buf += 1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if(len > 0) {
 | 
			
		||||
        memcpy(*buf, p, len);
 | 
			
		||||
        *buf += len;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Base64 Conversion */
 | 
			
		||||
 | 
			
		||||
static const short base64_reverse_table[256] = {
 | 
			
		||||
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
 | 
			
		||||
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
 | 
			
		||||
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
 | 
			
		||||
    52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
 | 
			
		||||
    -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
 | 
			
		||||
    15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
 | 
			
		||||
    -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
 | 
			
		||||
    41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
 | 
			
		||||
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
 | 
			
		||||
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
 | 
			
		||||
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
 | 
			
		||||
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
 | 
			
		||||
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
 | 
			
		||||
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
 | 
			
		||||
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
 | 
			
		||||
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* libssh2_base64_decode
 | 
			
		||||
 *
 | 
			
		||||
 * Decode a base64 chunk and store it into a newly alloc'd buffer
 | 
			
		||||
 */
 | 
			
		||||
LIBSSH2_API int
 | 
			
		||||
libssh2_base64_decode(LIBSSH2_SESSION *session, char **data,
 | 
			
		||||
                      unsigned int *datalen, const char *src,
 | 
			
		||||
                      unsigned int src_len)
 | 
			
		||||
{
 | 
			
		||||
    unsigned char *s, *d;
 | 
			
		||||
    short v;
 | 
			
		||||
    int i = 0, len = 0;
 | 
			
		||||
 | 
			
		||||
    *data = LIBSSH2_ALLOC(session, (3 * src_len / 4) + 1);
 | 
			
		||||
    d = (unsigned char *) *data;
 | 
			
		||||
    if(!d) {
 | 
			
		||||
        return _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
 | 
			
		||||
                              "Unable to allocate memory for base64 decoding");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for(s = (unsigned char *) src; ((char *) s) < (src + src_len); s++) {
 | 
			
		||||
        v = base64_reverse_table[*s];
 | 
			
		||||
        if(v < 0)
 | 
			
		||||
            continue;
 | 
			
		||||
        switch(i % 4) {
 | 
			
		||||
        case 0:
 | 
			
		||||
            d[len] = (unsigned char)(v << 2);
 | 
			
		||||
            break;
 | 
			
		||||
        case 1:
 | 
			
		||||
            d[len++] |= v >> 4;
 | 
			
		||||
            d[len] = (unsigned char)(v << 4);
 | 
			
		||||
            break;
 | 
			
		||||
        case 2:
 | 
			
		||||
            d[len++] |= v >> 2;
 | 
			
		||||
            d[len] = (unsigned char)(v << 6);
 | 
			
		||||
            break;
 | 
			
		||||
        case 3:
 | 
			
		||||
            d[len++] |= v;
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        i++;
 | 
			
		||||
    }
 | 
			
		||||
    if((i % 4) == 1) {
 | 
			
		||||
        /* Invalid -- We have a byte which belongs exclusively to a partial
 | 
			
		||||
           octet */
 | 
			
		||||
        LIBSSH2_FREE(session, *data);
 | 
			
		||||
        *data = NULL;
 | 
			
		||||
        return _libssh2_error(session, LIBSSH2_ERROR_INVAL, "Invalid base64");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    *datalen = len;
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* ---- Base64 Encoding/Decoding Table --- */
 | 
			
		||||
static const char table64[]=
 | 
			
		||||
  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * _libssh2_base64_encode()
 | 
			
		||||
 *
 | 
			
		||||
 * Returns the length of the newly created base64 string. The third argument
 | 
			
		||||
 * is a pointer to an allocated area holding the base64 data. If something
 | 
			
		||||
 * went wrong, 0 is returned.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
size_t _libssh2_base64_encode(LIBSSH2_SESSION *session,
 | 
			
		||||
                              const char *inp, size_t insize, char **outptr)
 | 
			
		||||
{
 | 
			
		||||
    unsigned char ibuf[3];
 | 
			
		||||
    unsigned char obuf[4];
 | 
			
		||||
    int i;
 | 
			
		||||
    int inputparts;
 | 
			
		||||
    char *output;
 | 
			
		||||
    char *base64data;
 | 
			
		||||
    const char *indata = inp;
 | 
			
		||||
 | 
			
		||||
    *outptr = NULL; /* set to NULL in case of failure before we reach the
 | 
			
		||||
                       end */
 | 
			
		||||
 | 
			
		||||
    if(0 == insize)
 | 
			
		||||
        insize = strlen(indata);
 | 
			
		||||
 | 
			
		||||
    base64data = output = LIBSSH2_ALLOC(session, insize * 4 / 3 + 4);
 | 
			
		||||
    if(NULL == output)
 | 
			
		||||
        return 0;
 | 
			
		||||
 | 
			
		||||
    while(insize > 0) {
 | 
			
		||||
        for(i = inputparts = 0; i < 3; i++) {
 | 
			
		||||
            if(insize > 0) {
 | 
			
		||||
                inputparts++;
 | 
			
		||||
                ibuf[i] = *indata;
 | 
			
		||||
                indata++;
 | 
			
		||||
                insize--;
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
                ibuf[i] = 0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        obuf[0] = (unsigned char)  ((ibuf[0] & 0xFC) >> 2);
 | 
			
		||||
        obuf[1] = (unsigned char) (((ibuf[0] & 0x03) << 4) | \
 | 
			
		||||
                                   ((ibuf[1] & 0xF0) >> 4));
 | 
			
		||||
        obuf[2] = (unsigned char) (((ibuf[1] & 0x0F) << 2) | \
 | 
			
		||||
                                   ((ibuf[2] & 0xC0) >> 6));
 | 
			
		||||
        obuf[3] = (unsigned char)   (ibuf[2] & 0x3F);
 | 
			
		||||
 | 
			
		||||
        switch(inputparts) {
 | 
			
		||||
        case 1: /* only one byte read */
 | 
			
		||||
            snprintf(output, 5, "%c%c==",
 | 
			
		||||
                     table64[obuf[0]],
 | 
			
		||||
                     table64[obuf[1]]);
 | 
			
		||||
            break;
 | 
			
		||||
        case 2: /* two bytes read */
 | 
			
		||||
            snprintf(output, 5, "%c%c%c=",
 | 
			
		||||
                     table64[obuf[0]],
 | 
			
		||||
                     table64[obuf[1]],
 | 
			
		||||
                     table64[obuf[2]]);
 | 
			
		||||
            break;
 | 
			
		||||
        default:
 | 
			
		||||
            snprintf(output, 5, "%c%c%c%c",
 | 
			
		||||
                     table64[obuf[0]],
 | 
			
		||||
                     table64[obuf[1]],
 | 
			
		||||
                     table64[obuf[2]],
 | 
			
		||||
                     table64[obuf[3]]);
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        output += 4;
 | 
			
		||||
    }
 | 
			
		||||
    *output = 0;
 | 
			
		||||
    *outptr = base64data; /* make it return the actual data memory */
 | 
			
		||||
 | 
			
		||||
    return strlen(base64data); /* return the length of the new data */
 | 
			
		||||
}
 | 
			
		||||
/* ---- End of Base64 Encoding ---- */
 | 
			
		||||
 | 
			
		||||
LIBSSH2_API void
 | 
			
		||||
libssh2_free(LIBSSH2_SESSION *session, void *ptr)
 | 
			
		||||
{
 | 
			
		||||
    LIBSSH2_FREE(session, ptr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef LIBSSH2DEBUG
 | 
			
		||||
#include <stdarg.h>
 | 
			
		||||
 | 
			
		||||
LIBSSH2_API int
 | 
			
		||||
libssh2_trace(LIBSSH2_SESSION * session, int bitmask)
 | 
			
		||||
{
 | 
			
		||||
    session->showmask = bitmask;
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
LIBSSH2_API int
 | 
			
		||||
libssh2_trace_sethandler(LIBSSH2_SESSION *session, void *handler_context,
 | 
			
		||||
                         libssh2_trace_handler_func callback)
 | 
			
		||||
{
 | 
			
		||||
    session->tracehandler = callback;
 | 
			
		||||
    session->tracehandler_context = handler_context;
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
_libssh2_debug(LIBSSH2_SESSION * session, int context, const char *format, ...)
 | 
			
		||||
{
 | 
			
		||||
    char buffer[1536];
 | 
			
		||||
    int len, msglen, buflen = sizeof(buffer);
 | 
			
		||||
    va_list vargs;
 | 
			
		||||
    struct timeval now;
 | 
			
		||||
    static int firstsec;
 | 
			
		||||
    static const char *const contexts[] = {
 | 
			
		||||
        "Unknown",
 | 
			
		||||
        "Transport",
 | 
			
		||||
        "Key Ex",
 | 
			
		||||
        "Userauth",
 | 
			
		||||
        "Conn",
 | 
			
		||||
        "SCP",
 | 
			
		||||
        "SFTP",
 | 
			
		||||
        "Failure Event",
 | 
			
		||||
        "Publickey",
 | 
			
		||||
        "Socket",
 | 
			
		||||
    };
 | 
			
		||||
    const char *contexttext = contexts[0];
 | 
			
		||||
    unsigned int contextindex;
 | 
			
		||||
 | 
			
		||||
    if(!(session->showmask & context)) {
 | 
			
		||||
        /* no such output asked for */
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Find the first matching context string for this message */
 | 
			
		||||
    for(contextindex = 0; contextindex < ARRAY_SIZE(contexts);
 | 
			
		||||
         contextindex++) {
 | 
			
		||||
        if((context & (1 << contextindex)) != 0) {
 | 
			
		||||
            contexttext = contexts[contextindex];
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _libssh2_gettimeofday(&now, NULL);
 | 
			
		||||
    if(!firstsec) {
 | 
			
		||||
        firstsec = now.tv_sec;
 | 
			
		||||
    }
 | 
			
		||||
    now.tv_sec -= firstsec;
 | 
			
		||||
 | 
			
		||||
    len = snprintf(buffer, buflen, "[libssh2] %d.%06d %s: ",
 | 
			
		||||
                   (int)now.tv_sec, (int)now.tv_usec, contexttext);
 | 
			
		||||
 | 
			
		||||
    if(len >= buflen)
 | 
			
		||||
        msglen = buflen - 1;
 | 
			
		||||
    else {
 | 
			
		||||
        buflen -= len;
 | 
			
		||||
        msglen = len;
 | 
			
		||||
        va_start(vargs, format);
 | 
			
		||||
        len = vsnprintf(buffer + msglen, buflen, format, vargs);
 | 
			
		||||
        va_end(vargs);
 | 
			
		||||
        msglen += len < buflen ? len : buflen - 1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if(session->tracehandler)
 | 
			
		||||
        (session->tracehandler)(session, session->tracehandler_context, buffer,
 | 
			
		||||
                                msglen);
 | 
			
		||||
    else
 | 
			
		||||
        fprintf(stderr, "%s\n", buffer);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#else
 | 
			
		||||
LIBSSH2_API int
 | 
			
		||||
libssh2_trace(LIBSSH2_SESSION * session, int bitmask)
 | 
			
		||||
{
 | 
			
		||||
    (void) session;
 | 
			
		||||
    (void) bitmask;
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
LIBSSH2_API int
 | 
			
		||||
libssh2_trace_sethandler(LIBSSH2_SESSION *session, void *handler_context,
 | 
			
		||||
                         libssh2_trace_handler_func callback)
 | 
			
		||||
{
 | 
			
		||||
    (void) session;
 | 
			
		||||
    (void) handler_context;
 | 
			
		||||
    (void) callback;
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/* init the list head */
 | 
			
		||||
void _libssh2_list_init(struct list_head *head)
 | 
			
		||||
{
 | 
			
		||||
    head->first = head->last = NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* add a node to the list */
 | 
			
		||||
void _libssh2_list_add(struct list_head *head,
 | 
			
		||||
                       struct list_node *entry)
 | 
			
		||||
{
 | 
			
		||||
    /* store a pointer to the head */
 | 
			
		||||
    entry->head = head;
 | 
			
		||||
 | 
			
		||||
    /* we add this entry at the "top" so it has no next */
 | 
			
		||||
    entry->next = NULL;
 | 
			
		||||
 | 
			
		||||
    /* make our prev point to what the head thinks is last */
 | 
			
		||||
    entry->prev = head->last;
 | 
			
		||||
 | 
			
		||||
    /* and make head's last be us now */
 | 
			
		||||
    head->last = entry;
 | 
			
		||||
 | 
			
		||||
    /* make sure our 'prev' node points to us next */
 | 
			
		||||
    if(entry->prev)
 | 
			
		||||
        entry->prev->next = entry;
 | 
			
		||||
    else
 | 
			
		||||
        head->first = entry;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* return the "first" node in the list this head points to */
 | 
			
		||||
void *_libssh2_list_first(struct list_head *head)
 | 
			
		||||
{
 | 
			
		||||
    return head->first;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* return the next node in the list */
 | 
			
		||||
void *_libssh2_list_next(struct list_node *node)
 | 
			
		||||
{
 | 
			
		||||
    return node->next;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* return the prev node in the list */
 | 
			
		||||
void *_libssh2_list_prev(struct list_node *node)
 | 
			
		||||
{
 | 
			
		||||
    return node->prev;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* remove this node from the list */
 | 
			
		||||
void _libssh2_list_remove(struct list_node *entry)
 | 
			
		||||
{
 | 
			
		||||
    if(entry->prev)
 | 
			
		||||
        entry->prev->next = entry->next;
 | 
			
		||||
    else
 | 
			
		||||
        entry->head->first = entry->next;
 | 
			
		||||
 | 
			
		||||
    if(entry->next)
 | 
			
		||||
        entry->next->prev = entry->prev;
 | 
			
		||||
    else
 | 
			
		||||
        entry->head->last = entry->prev;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#if 0
 | 
			
		||||
/* insert a node before the given 'after' entry */
 | 
			
		||||
void _libssh2_list_insert(struct list_node *after, /* insert before this */
 | 
			
		||||
                          struct list_node *entry)
 | 
			
		||||
{
 | 
			
		||||
    /* 'after' is next to 'entry' */
 | 
			
		||||
    bentry->next = after;
 | 
			
		||||
 | 
			
		||||
    /* entry's prev is then made to be the prev after current has */
 | 
			
		||||
    entry->prev = after->prev;
 | 
			
		||||
 | 
			
		||||
    /* the node that is now before 'entry' was previously before 'after'
 | 
			
		||||
       and must be made to point to 'entry' correctly */
 | 
			
		||||
    if(entry->prev)
 | 
			
		||||
        entry->prev->next = entry;
 | 
			
		||||
    else
 | 
			
		||||
      /* there was no node before this, so we make sure we point the head
 | 
			
		||||
         pointer to this node */
 | 
			
		||||
      after->head->first = entry;
 | 
			
		||||
 | 
			
		||||
    /* after's prev entry points back to entry */
 | 
			
		||||
    after->prev = entry;
 | 
			
		||||
 | 
			
		||||
    /* after's next entry is still the same as before */
 | 
			
		||||
 | 
			
		||||
    /* entry's head is the same as after's */
 | 
			
		||||
    entry->head = after->head;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/* this define is defined in misc.h for the correct platforms */
 | 
			
		||||
#ifdef LIBSSH2_GETTIMEOFDAY_WIN32
 | 
			
		||||
/*
 | 
			
		||||
 * gettimeofday
 | 
			
		||||
 * Implementation according to:
 | 
			
		||||
 * The Open Group Base Specifications Issue 6
 | 
			
		||||
 * IEEE Std 1003.1, 2004 Edition
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 *  THIS SOFTWARE IS NOT COPYRIGHTED
 | 
			
		||||
 *
 | 
			
		||||
 *  This source code is offered for use in the public domain. You may
 | 
			
		||||
 *  use, modify or distribute it freely.
 | 
			
		||||
 *
 | 
			
		||||
 *  This code is distributed in the hope that it will be useful but
 | 
			
		||||
 *  WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY
 | 
			
		||||
 *  DISCLAIMED. This includes but is not limited to warranties of
 | 
			
		||||
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 | 
			
		||||
 *
 | 
			
		||||
 *  Contributed by:
 | 
			
		||||
 *  Danny Smith <dannysmith@users.sourceforge.net>
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/* Offset between 1/1/1601 and 1/1/1970 in 100 nanosec units */
 | 
			
		||||
#define _W32_FT_OFFSET (116444736000000000)
 | 
			
		||||
 | 
			
		||||
int __cdecl _libssh2_gettimeofday(struct timeval *tp, void *tzp)
 | 
			
		||||
{
 | 
			
		||||
    union {
 | 
			
		||||
        unsigned __int64 ns100; /*time since 1 Jan 1601 in 100ns units */
 | 
			
		||||
        FILETIME ft;
 | 
			
		||||
    } _now;
 | 
			
		||||
    (void)tzp;
 | 
			
		||||
    if(tp) {
 | 
			
		||||
        GetSystemTimeAsFileTime(&_now.ft);
 | 
			
		||||
        tp->tv_usec = (long)((_now.ns100 / 10) % 1000000);
 | 
			
		||||
        tp->tv_sec = (long)((_now.ns100 - _W32_FT_OFFSET) / 10000000);
 | 
			
		||||
    }
 | 
			
		||||
    /* Always return 0 as per Open Group Base Specifications Issue 6.
 | 
			
		||||
       Do not set errno on error.  */
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
void *_libssh2_calloc(LIBSSH2_SESSION* session, size_t size)
 | 
			
		||||
{
 | 
			
		||||
    void *p = LIBSSH2_ALLOC(session, size);
 | 
			
		||||
    if(p) {
 | 
			
		||||
        memset(p, 0, size);
 | 
			
		||||
    }
 | 
			
		||||
    return p;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* XOR operation on buffers input1 and input2, result in output.
 | 
			
		||||
   It is safe to use an input buffer as the output buffer. */
 | 
			
		||||
void _libssh2_xor_data(unsigned char *output,
 | 
			
		||||
                       const unsigned char *input1,
 | 
			
		||||
                       const unsigned char *input2,
 | 
			
		||||
                       size_t length)
 | 
			
		||||
{
 | 
			
		||||
    size_t i;
 | 
			
		||||
 | 
			
		||||
    for(i = 0; i < length; i++)
 | 
			
		||||
        *output++ = *input1++ ^ *input2++;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Increments an AES CTR buffer to prepare it for use with the
 | 
			
		||||
   next AES block. */
 | 
			
		||||
void _libssh2_aes_ctr_increment(unsigned char *ctr,
 | 
			
		||||
                                size_t length)
 | 
			
		||||
{
 | 
			
		||||
    unsigned char *pc;
 | 
			
		||||
    unsigned int val, carry;
 | 
			
		||||
 | 
			
		||||
    pc = ctr + length - 1;
 | 
			
		||||
    carry = 1;
 | 
			
		||||
 | 
			
		||||
    while(pc >= ctr) {
 | 
			
		||||
        val = (unsigned int)*pc + carry;
 | 
			
		||||
        *pc-- = val & 0xFF;
 | 
			
		||||
        carry = val >> 8;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#if !defined(WIN32) && !defined(HAVE_MEMSET_S)
 | 
			
		||||
static void * (* const volatile memset_libssh)(void *, int, size_t) = memset;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
void _libssh2_explicit_zero(void *buf, size_t size)
 | 
			
		||||
{
 | 
			
		||||
#ifdef WIN32
 | 
			
		||||
    SecureZeroMemory(buf, size);
 | 
			
		||||
#elif defined(HAVE_MEMSET_S)
 | 
			
		||||
    (void)memset_s(buf, size, 0, size);
 | 
			
		||||
#else
 | 
			
		||||
    memset_libssh(buf, 0, size);
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* String buffer */
 | 
			
		||||
 | 
			
		||||
struct string_buf* _libssh2_string_buf_new(LIBSSH2_SESSION *session)
 | 
			
		||||
{
 | 
			
		||||
    struct string_buf *ret;
 | 
			
		||||
 | 
			
		||||
    ret = _libssh2_calloc(session, sizeof(*ret));
 | 
			
		||||
    if(ret == NULL)
 | 
			
		||||
        return NULL;
 | 
			
		||||
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void _libssh2_string_buf_free(LIBSSH2_SESSION *session, struct string_buf *buf)
 | 
			
		||||
{
 | 
			
		||||
    if(buf == NULL)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    if(buf->data != NULL)
 | 
			
		||||
        LIBSSH2_FREE(session, buf->data);
 | 
			
		||||
 | 
			
		||||
    LIBSSH2_FREE(session, buf);
 | 
			
		||||
    buf = NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int _libssh2_get_byte(struct string_buf *buf, unsigned char *out)
 | 
			
		||||
{
 | 
			
		||||
    if(!_libssh2_check_length(buf, 1)) {
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    *out = buf->dataptr[0];
 | 
			
		||||
    buf->dataptr += 1;
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int _libssh2_get_boolean(struct string_buf *buf, unsigned char *out)
 | 
			
		||||
{
 | 
			
		||||
    if(!_libssh2_check_length(buf, 1)) {
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    *out = buf->dataptr[0] == 0 ? 0 : 1;
 | 
			
		||||
    buf->dataptr += 1;
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int _libssh2_get_u32(struct string_buf *buf, uint32_t *out)
 | 
			
		||||
{
 | 
			
		||||
    if(!_libssh2_check_length(buf, 4)) {
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    *out = _libssh2_ntohu32(buf->dataptr);
 | 
			
		||||
    buf->dataptr += 4;
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int _libssh2_get_u64(struct string_buf *buf, libssh2_uint64_t *out)
 | 
			
		||||
{
 | 
			
		||||
    if(!_libssh2_check_length(buf, 8)) {
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    *out = _libssh2_ntohu64(buf->dataptr);
 | 
			
		||||
    buf->dataptr += 8;
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int _libssh2_match_string(struct string_buf *buf, const char *match)
 | 
			
		||||
{
 | 
			
		||||
    unsigned char *out;
 | 
			
		||||
    size_t len = 0;
 | 
			
		||||
    if(_libssh2_get_string(buf, &out, &len) || len != strlen(match) ||
 | 
			
		||||
        strncmp((char *)out, match, strlen(match)) != 0) {
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int _libssh2_get_string(struct string_buf *buf, unsigned char **outbuf,
 | 
			
		||||
                        size_t *outlen)
 | 
			
		||||
{
 | 
			
		||||
    uint32_t data_len;
 | 
			
		||||
    if(_libssh2_get_u32(buf, &data_len) != 0) {
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
    if(!_libssh2_check_length(buf, data_len)) {
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
    *outbuf = buf->dataptr;
 | 
			
		||||
    buf->dataptr += data_len;
 | 
			
		||||
 | 
			
		||||
    if(outlen)
 | 
			
		||||
        *outlen = (size_t)data_len;
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int _libssh2_copy_string(LIBSSH2_SESSION *session, struct string_buf *buf,
 | 
			
		||||
                         unsigned char **outbuf, size_t *outlen)
 | 
			
		||||
{
 | 
			
		||||
    size_t str_len;
 | 
			
		||||
    unsigned char *str;
 | 
			
		||||
 | 
			
		||||
    if(_libssh2_get_string(buf, &str, &str_len)) {
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if(str_len) {
 | 
			
		||||
        *outbuf = LIBSSH2_ALLOC(session, str_len);
 | 
			
		||||
        if(*outbuf) {
 | 
			
		||||
            memcpy(*outbuf, str, str_len);
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            return -1;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
        *outlen = 0;
 | 
			
		||||
        *outbuf = NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if(outlen)
 | 
			
		||||
        *outlen = str_len;
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int _libssh2_get_bignum_bytes(struct string_buf *buf, unsigned char **outbuf,
 | 
			
		||||
                              size_t *outlen)
 | 
			
		||||
{
 | 
			
		||||
    uint32_t data_len;
 | 
			
		||||
    uint32_t bn_len;
 | 
			
		||||
    unsigned char *bnptr;
 | 
			
		||||
 | 
			
		||||
    if(_libssh2_get_u32(buf, &data_len)) {
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
    if(!_libssh2_check_length(buf, data_len)) {
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bn_len = data_len;
 | 
			
		||||
    bnptr = buf->dataptr;
 | 
			
		||||
 | 
			
		||||
    /* trim leading zeros */
 | 
			
		||||
    while(bn_len > 0 && *bnptr == 0x00) {
 | 
			
		||||
        bn_len--;
 | 
			
		||||
        bnptr++;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    *outbuf = bnptr;
 | 
			
		||||
    buf->dataptr += data_len;
 | 
			
		||||
 | 
			
		||||
    if(outlen)
 | 
			
		||||
        *outlen = (size_t)bn_len;
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Given the current location in buf, _libssh2_check_length ensures
 | 
			
		||||
   callers can read the next len number of bytes out of the buffer
 | 
			
		||||
   before reading the buffer content */
 | 
			
		||||
 | 
			
		||||
int _libssh2_check_length(struct string_buf *buf, size_t len)
 | 
			
		||||
{
 | 
			
		||||
    unsigned char *endp = &buf->data[buf->len];
 | 
			
		||||
    size_t left = endp - buf->dataptr;
 | 
			
		||||
    return ((len <= left) && (left <= buf->len));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int _libssh2_eob(struct string_buf *buf)
 | 
			
		||||
{
 | 
			
		||||
    unsigned char *endp = &buf->data[buf->len];
 | 
			
		||||
    return buf->dataptr >= endp;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Wrappers */
 | 
			
		||||
 | 
			
		||||
int _libssh2_bcrypt_pbkdf(const char *pass,
 | 
			
		||||
                          size_t passlen,
 | 
			
		||||
                          const uint8_t *salt,
 | 
			
		||||
                          size_t saltlen,
 | 
			
		||||
                          uint8_t *key,
 | 
			
		||||
                          size_t keylen,
 | 
			
		||||
                          unsigned int rounds)
 | 
			
		||||
{
 | 
			
		||||
    /* defined in bcrypt_pbkdf.c */
 | 
			
		||||
    return bcrypt_pbkdf(pass,
 | 
			
		||||
                        passlen,
 | 
			
		||||
                        salt,
 | 
			
		||||
                        saltlen,
 | 
			
		||||
                        key,
 | 
			
		||||
                        keylen,
 | 
			
		||||
                        rounds);
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,133 @@
 | 
			
		|||
#if defined(ESP32)
 | 
			
		||||
#ifndef __LIBSSH2_MISC_H
 | 
			
		||||
#define __LIBSSH2_MISC_H
 | 
			
		||||
/* Copyright (c) 2009-2019 by Daniel Stenberg
 | 
			
		||||
 *
 | 
			
		||||
 * All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Redistribution and use in source and binary forms,
 | 
			
		||||
 * with or without modification, are permitted provided
 | 
			
		||||
 * that the following conditions are met:
 | 
			
		||||
 *
 | 
			
		||||
 *   Redistributions of source code must retain the above
 | 
			
		||||
 *   copyright notice, this list of conditions and the
 | 
			
		||||
 *   following disclaimer.
 | 
			
		||||
 *
 | 
			
		||||
 *   Redistributions in binary form must reproduce the above
 | 
			
		||||
 *   copyright notice, this list of conditions and the following
 | 
			
		||||
 *   disclaimer in the documentation and/or other materials
 | 
			
		||||
 *   provided with the distribution.
 | 
			
		||||
 *
 | 
			
		||||
 *   Neither the name of the copyright holder nor the names
 | 
			
		||||
 *   of any other contributors may be used to endorse or
 | 
			
		||||
 *   promote products derived from this software without
 | 
			
		||||
 *   specific prior written permission.
 | 
			
		||||
 *
 | 
			
		||||
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
 | 
			
		||||
 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 | 
			
		||||
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 | 
			
		||||
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 | 
			
		||||
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 | 
			
		||||
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | 
			
		||||
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 | 
			
		||||
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 | 
			
		||||
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 | 
			
		||||
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 | 
			
		||||
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 | 
			
		||||
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
 | 
			
		||||
 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
 | 
			
		||||
 * OF SUCH DAMAGE.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
struct list_head {
 | 
			
		||||
    struct list_node *last;
 | 
			
		||||
    struct list_node *first;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct list_node {
 | 
			
		||||
    struct list_node *next;
 | 
			
		||||
    struct list_node *prev;
 | 
			
		||||
    struct list_head *head;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct string_buf {
 | 
			
		||||
    unsigned char *data;
 | 
			
		||||
    unsigned char *dataptr;
 | 
			
		||||
    size_t len;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
int _libssh2_error_flags(LIBSSH2_SESSION* session, int errcode,
 | 
			
		||||
                         const char *errmsg, int errflags);
 | 
			
		||||
int _libssh2_error(LIBSSH2_SESSION* session, int errcode, const char *errmsg);
 | 
			
		||||
 | 
			
		||||
void _libssh2_list_init(struct list_head *head);
 | 
			
		||||
 | 
			
		||||
/* add a node last in the list */
 | 
			
		||||
void _libssh2_list_add(struct list_head *head,
 | 
			
		||||
                       struct list_node *entry);
 | 
			
		||||
 | 
			
		||||
/* return the "first" node in the list this head points to */
 | 
			
		||||
void *_libssh2_list_first(struct list_head *head);
 | 
			
		||||
 | 
			
		||||
/* return the next node in the list */
 | 
			
		||||
void *_libssh2_list_next(struct list_node *node);
 | 
			
		||||
 | 
			
		||||
/* return the prev node in the list */
 | 
			
		||||
void *_libssh2_list_prev(struct list_node *node);
 | 
			
		||||
 | 
			
		||||
/* remove this node from the list */
 | 
			
		||||
void _libssh2_list_remove(struct list_node *entry);
 | 
			
		||||
 | 
			
		||||
size_t _libssh2_base64_encode(LIBSSH2_SESSION *session,
 | 
			
		||||
                              const char *inp, size_t insize, char **outptr);
 | 
			
		||||
 | 
			
		||||
unsigned int _libssh2_ntohu32(const unsigned char *buf);
 | 
			
		||||
libssh2_uint64_t _libssh2_ntohu64(const unsigned char *buf);
 | 
			
		||||
void _libssh2_htonu32(unsigned char *buf, uint32_t val);
 | 
			
		||||
void _libssh2_store_u32(unsigned char **buf, uint32_t value);
 | 
			
		||||
void _libssh2_store_str(unsigned char **buf, const char *str, size_t len);
 | 
			
		||||
void _libssh2_store_bignum2_bytes(unsigned char **buf,
 | 
			
		||||
                                  const unsigned char *bytes,
 | 
			
		||||
                                  size_t len);
 | 
			
		||||
void *_libssh2_calloc(LIBSSH2_SESSION *session, size_t size);
 | 
			
		||||
void _libssh2_explicit_zero(void *buf, size_t size);
 | 
			
		||||
 | 
			
		||||
struct string_buf* _libssh2_string_buf_new(LIBSSH2_SESSION *session);
 | 
			
		||||
void _libssh2_string_buf_free(LIBSSH2_SESSION *session,
 | 
			
		||||
                              struct string_buf *buf);
 | 
			
		||||
int _libssh2_get_boolean(struct string_buf *buf, unsigned char *out);
 | 
			
		||||
int _libssh2_get_byte(struct string_buf *buf, unsigned char *out);
 | 
			
		||||
int _libssh2_get_u32(struct string_buf *buf, uint32_t *out);
 | 
			
		||||
int _libssh2_get_u64(struct string_buf *buf, libssh2_uint64_t *out);
 | 
			
		||||
int _libssh2_match_string(struct string_buf *buf, const char *match);
 | 
			
		||||
int _libssh2_get_string(struct string_buf *buf, unsigned char **outbuf,
 | 
			
		||||
                        size_t *outlen);
 | 
			
		||||
int _libssh2_copy_string(LIBSSH2_SESSION* session, struct string_buf *buf,
 | 
			
		||||
                         unsigned char **outbuf, size_t *outlen);
 | 
			
		||||
int _libssh2_get_bignum_bytes(struct string_buf *buf, unsigned char **outbuf,
 | 
			
		||||
                              size_t *outlen);
 | 
			
		||||
int _libssh2_check_length(struct string_buf *buf, size_t requested_len);
 | 
			
		||||
int _libssh2_eob(struct string_buf *buf);
 | 
			
		||||
 | 
			
		||||
#if defined(WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__)
 | 
			
		||||
/* provide a private one */
 | 
			
		||||
#undef HAVE_GETTIMEOFDAY
 | 
			
		||||
int __cdecl _libssh2_gettimeofday(struct timeval *tp, void *tzp);
 | 
			
		||||
#define HAVE_LIBSSH2_GETTIMEOFDAY
 | 
			
		||||
#define LIBSSH2_GETTIMEOFDAY_WIN32 /* enable the win32 implementation */
 | 
			
		||||
#else
 | 
			
		||||
#ifdef HAVE_GETTIMEOFDAY
 | 
			
		||||
#define _libssh2_gettimeofday(x,y) gettimeofday(x,y)
 | 
			
		||||
#define HAVE_LIBSSH2_GETTIMEOFDAY
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
void _libssh2_xor_data(unsigned char *output,
 | 
			
		||||
                       const unsigned char *input1,
 | 
			
		||||
                       const unsigned char *input2,
 | 
			
		||||
                       size_t length);
 | 
			
		||||
 | 
			
		||||
void _libssh2_aes_ctr_increment(unsigned char *ctr, size_t length);
 | 
			
		||||
 | 
			
		||||
#endif /* _LIBSSH2_MISC_H */
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,445 @@
 | 
			
		|||
#if defined(ESP32)
 | 
			
		||||
#ifndef __LIBSSH2_OPENSSL_H
 | 
			
		||||
#define __LIBSSH2_OPENSSL_H
 | 
			
		||||
/* Copyright (C) 2009, 2010 Simon Josefsson
 | 
			
		||||
 * Copyright (C) 2006, 2007 The Written Word, Inc.  All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Author: Simon Josefsson
 | 
			
		||||
 *
 | 
			
		||||
 * Redistribution and use in source and binary forms,
 | 
			
		||||
 * with or without modification, are permitted provided
 | 
			
		||||
 * that the following conditions are met:
 | 
			
		||||
 *
 | 
			
		||||
 *   Redistributions of source code must retain the above
 | 
			
		||||
 *   copyright notice, this list of conditions and the
 | 
			
		||||
 *   following disclaimer.
 | 
			
		||||
 *
 | 
			
		||||
 *   Redistributions in binary form must reproduce the above
 | 
			
		||||
 *   copyright notice, this list of conditions and the following
 | 
			
		||||
 *   disclaimer in the documentation and/or other materials
 | 
			
		||||
 *   provided with the distribution.
 | 
			
		||||
 *
 | 
			
		||||
 *   Neither the name of the copyright holder nor the names
 | 
			
		||||
 *   of any other contributors may be used to endorse or
 | 
			
		||||
 *   promote products derived from this software without
 | 
			
		||||
 *   specific prior written permission.
 | 
			
		||||
 *
 | 
			
		||||
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
 | 
			
		||||
 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 | 
			
		||||
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 | 
			
		||||
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 | 
			
		||||
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 | 
			
		||||
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | 
			
		||||
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 | 
			
		||||
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 | 
			
		||||
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 | 
			
		||||
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 | 
			
		||||
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 | 
			
		||||
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
 | 
			
		||||
 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
 | 
			
		||||
 * OF SUCH DAMAGE.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/* disable deprecated warnings in OpenSSL 3 */
 | 
			
		||||
#define OPENSSL_SUPPRESS_DEPRECATED
 | 
			
		||||
 | 
			
		||||
#ifdef LIBSSH2_WOLFSSL
 | 
			
		||||
 | 
			
		||||
#include <wolfssl/options.h>
 | 
			
		||||
#include <openssl/ecdh.h>
 | 
			
		||||
 | 
			
		||||
#if defined(NO_DSA) || defined(HAVE_FIPS)
 | 
			
		||||
#define OPENSSL_NO_DSA
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if defined(NO_MD5) || defined(HAVE_FIPS)
 | 
			
		||||
#define OPENSSL_NO_MD5
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if !defined(WOLFSSL_RIPEMD) || defined(HAVE_FIPS)
 | 
			
		||||
#define OPENSSL_NO_RIPEMD
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if defined(NO_RC4) || defined(HAVE_FIPS)
 | 
			
		||||
#define OPENSSL_NO_RC4
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef NO_DES3
 | 
			
		||||
#define OPENSSL_NO_DES
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef EVP_aes_128_ctr
 | 
			
		||||
#define HAVE_EVP_AES_128_CTR
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/* wolfSSL doesn't support Blowfish or CAST. */
 | 
			
		||||
#define OPENSSL_NO_BF
 | 
			
		||||
#define OPENSSL_NO_CAST
 | 
			
		||||
/* wolfSSL has no engine framework. */
 | 
			
		||||
#define OPENSSL_NO_ENGINE
 | 
			
		||||
 | 
			
		||||
#endif /* LIBSSH2_WOLFSSL */
 | 
			
		||||
 | 
			
		||||
#include <openssl/opensslconf.h>
 | 
			
		||||
#include <openssl/sha.h>
 | 
			
		||||
#include <openssl/rsa.h>
 | 
			
		||||
#ifndef OPENSSL_NO_ENGINE
 | 
			
		||||
#include <openssl/engine.h>
 | 
			
		||||
#endif
 | 
			
		||||
#ifndef OPENSSL_NO_DSA
 | 
			
		||||
#include <openssl/dsa.h>
 | 
			
		||||
#endif
 | 
			
		||||
#ifndef OPENSSL_NO_MD5
 | 
			
		||||
#include <openssl/md5.h>
 | 
			
		||||
#endif
 | 
			
		||||
#include <openssl/evp.h>
 | 
			
		||||
#include <openssl/hmac.h>
 | 
			
		||||
#include <openssl/bn.h>
 | 
			
		||||
#include <openssl/pem.h>
 | 
			
		||||
#include <openssl/rand.h>
 | 
			
		||||
 | 
			
		||||
#if (OPENSSL_VERSION_NUMBER >= 0x10100000L && \
 | 
			
		||||
    !defined(LIBRESSL_VERSION_NUMBER)) || defined(LIBSSH2_WOLFSSL) || \
 | 
			
		||||
    LIBRESSL_VERSION_NUMBER >= 0x3050000fL
 | 
			
		||||
/* For wolfSSL, whether the structs are truly opaque or not, it's best to not
 | 
			
		||||
 * rely on their internal data members being exposed publicly. */
 | 
			
		||||
# define HAVE_OPAQUE_STRUCTS 1
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef OPENSSL_NO_RSA
 | 
			
		||||
# define LIBSSH2_RSA 0
 | 
			
		||||
# define LIBSSH2_RSA_SHA2 0
 | 
			
		||||
#else
 | 
			
		||||
# define LIBSSH2_RSA 1
 | 
			
		||||
# define LIBSSH2_RSA_SHA2 1
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef OPENSSL_NO_DSA
 | 
			
		||||
# define LIBSSH2_DSA 0
 | 
			
		||||
#else
 | 
			
		||||
# define LIBSSH2_DSA 1
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if defined(OPENSSL_NO_ECDSA) || defined(OPENSSL_NO_EC)
 | 
			
		||||
# define LIBSSH2_ECDSA 0
 | 
			
		||||
#else
 | 
			
		||||
# define LIBSSH2_ECDSA 1
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if (OPENSSL_VERSION_NUMBER >= 0x10101000L && \
 | 
			
		||||
    !defined(LIBRESSL_VERSION_NUMBER)) || \
 | 
			
		||||
    LIBRESSL_VERSION_NUMBER >= 0x3070000fL
 | 
			
		||||
# define LIBSSH2_ED25519 1
 | 
			
		||||
#else
 | 
			
		||||
# define LIBSSH2_ED25519 0
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#ifdef OPENSSL_NO_MD5
 | 
			
		||||
# define LIBSSH2_MD5 0
 | 
			
		||||
#else
 | 
			
		||||
# define LIBSSH2_MD5 1
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if defined(OPENSSL_NO_RIPEMD) || defined(OPENSSL_NO_RMD160)
 | 
			
		||||
# define LIBSSH2_HMAC_RIPEMD 0
 | 
			
		||||
#else
 | 
			
		||||
# define LIBSSH2_HMAC_RIPEMD 1
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define LIBSSH2_HMAC_SHA256 1
 | 
			
		||||
#define LIBSSH2_HMAC_SHA512 1
 | 
			
		||||
 | 
			
		||||
#if (OPENSSL_VERSION_NUMBER >= 0x00907000L && !defined(OPENSSL_NO_AES)) || \
 | 
			
		||||
    (defined(LIBSSH2_WOLFSSL) && defined(WOLFSSL_AES_COUNTER))
 | 
			
		||||
# define LIBSSH2_AES_CTR 1
 | 
			
		||||
# define LIBSSH2_AES 1
 | 
			
		||||
#else
 | 
			
		||||
# define LIBSSH2_AES_CTR 0
 | 
			
		||||
# define LIBSSH2_AES 0
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef OPENSSL_NO_BF
 | 
			
		||||
# define LIBSSH2_BLOWFISH 0
 | 
			
		||||
#else
 | 
			
		||||
# define LIBSSH2_BLOWFISH 1
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef OPENSSL_NO_RC4
 | 
			
		||||
# define LIBSSH2_RC4 0
 | 
			
		||||
#else
 | 
			
		||||
# define LIBSSH2_RC4 1
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef OPENSSL_NO_CAST
 | 
			
		||||
# define LIBSSH2_CAST 0
 | 
			
		||||
#else
 | 
			
		||||
# define LIBSSH2_CAST 1
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef OPENSSL_NO_DES
 | 
			
		||||
# define LIBSSH2_3DES 0
 | 
			
		||||
#else
 | 
			
		||||
# define LIBSSH2_3DES 1
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define EC_MAX_POINT_LEN ((528 * 2 / 8) + 1)
 | 
			
		||||
 | 
			
		||||
#define _libssh2_random(buf, len) (RAND_bytes((buf), (len)) == 1 ? 0 : -1)
 | 
			
		||||
 | 
			
		||||
#define libssh2_prepare_iovec(vec, len)  /* Empty. */
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_OPAQUE_STRUCTS
 | 
			
		||||
#define libssh2_sha1_ctx EVP_MD_CTX *
 | 
			
		||||
#else
 | 
			
		||||
#define libssh2_sha1_ctx EVP_MD_CTX
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/* returns 0 in case of failure */
 | 
			
		||||
int _libssh2_sha1_init(libssh2_sha1_ctx *ctx);
 | 
			
		||||
#define libssh2_sha1_init(x) _libssh2_sha1_init(x)
 | 
			
		||||
#ifdef HAVE_OPAQUE_STRUCTS
 | 
			
		||||
#define libssh2_sha1_update(ctx, data, len) EVP_DigestUpdate(ctx, data, len)
 | 
			
		||||
#define libssh2_sha1_final(ctx, out) do { \
 | 
			
		||||
                                         EVP_DigestFinal(ctx, out, NULL); \
 | 
			
		||||
                                         EVP_MD_CTX_free(ctx); \
 | 
			
		||||
                                     } while(0)
 | 
			
		||||
#else
 | 
			
		||||
#define libssh2_sha1_update(ctx, data, len) EVP_DigestUpdate(&(ctx), data, len)
 | 
			
		||||
#define libssh2_sha1_final(ctx, out) EVP_DigestFinal(&(ctx), out, NULL)
 | 
			
		||||
#endif
 | 
			
		||||
int _libssh2_sha1(const unsigned char *message, unsigned long len,
 | 
			
		||||
                  unsigned char *out);
 | 
			
		||||
#define libssh2_sha1(x,y,z) _libssh2_sha1(x,y,z)
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_OPAQUE_STRUCTS
 | 
			
		||||
#define libssh2_sha256_ctx EVP_MD_CTX *
 | 
			
		||||
#else
 | 
			
		||||
#define libssh2_sha256_ctx EVP_MD_CTX
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/* returns 0 in case of failure */
 | 
			
		||||
int _libssh2_sha256_init(libssh2_sha256_ctx *ctx);
 | 
			
		||||
#define libssh2_sha256_init(x) _libssh2_sha256_init(x)
 | 
			
		||||
#ifdef HAVE_OPAQUE_STRUCTS
 | 
			
		||||
#define libssh2_sha256_update(ctx, data, len) EVP_DigestUpdate(ctx, data, len)
 | 
			
		||||
#define libssh2_sha256_final(ctx, out) do { \
 | 
			
		||||
                                           EVP_DigestFinal(ctx, out, NULL); \
 | 
			
		||||
                                           EVP_MD_CTX_free(ctx); \
 | 
			
		||||
                                       } while(0)
 | 
			
		||||
#else
 | 
			
		||||
#define libssh2_sha256_update(ctx, data, len) \
 | 
			
		||||
    EVP_DigestUpdate(&(ctx), data, len)
 | 
			
		||||
#define libssh2_sha256_final(ctx, out) EVP_DigestFinal(&(ctx), out, NULL)
 | 
			
		||||
#endif
 | 
			
		||||
int _libssh2_sha256(const unsigned char *message, unsigned long len,
 | 
			
		||||
                  unsigned char *out);
 | 
			
		||||
#define libssh2_sha256(x,y,z) _libssh2_sha256(x,y,z)
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_OPAQUE_STRUCTS
 | 
			
		||||
#define libssh2_sha384_ctx EVP_MD_CTX *
 | 
			
		||||
#else
 | 
			
		||||
#define libssh2_sha384_ctx EVP_MD_CTX
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/* returns 0 in case of failure */
 | 
			
		||||
int _libssh2_sha384_init(libssh2_sha384_ctx *ctx);
 | 
			
		||||
#define libssh2_sha384_init(x) _libssh2_sha384_init(x)
 | 
			
		||||
#ifdef HAVE_OPAQUE_STRUCTS
 | 
			
		||||
#define libssh2_sha384_update(ctx, data, len) EVP_DigestUpdate(ctx, data, len)
 | 
			
		||||
#define libssh2_sha384_final(ctx, out) do { \
 | 
			
		||||
                                            EVP_DigestFinal(ctx, out, NULL); \
 | 
			
		||||
                                            EVP_MD_CTX_free(ctx); \
 | 
			
		||||
                                       } while(0)
 | 
			
		||||
#else
 | 
			
		||||
#define libssh2_sha384_update(ctx, data, len)   \
 | 
			
		||||
    EVP_DigestUpdate(&(ctx), data, len)
 | 
			
		||||
#define libssh2_sha384_final(ctx, out) EVP_DigestFinal(&(ctx), out, NULL)
 | 
			
		||||
#endif
 | 
			
		||||
int _libssh2_sha384(const unsigned char *message, unsigned long len,
 | 
			
		||||
                    unsigned char *out);
 | 
			
		||||
#define libssh2_sha384(x,y,z) _libssh2_sha384(x,y,z)
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_OPAQUE_STRUCTS
 | 
			
		||||
#define libssh2_sha512_ctx EVP_MD_CTX *
 | 
			
		||||
#else
 | 
			
		||||
#define libssh2_sha512_ctx EVP_MD_CTX
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/* returns 0 in case of failure */
 | 
			
		||||
int _libssh2_sha512_init(libssh2_sha512_ctx *ctx);
 | 
			
		||||
#define libssh2_sha512_init(x) _libssh2_sha512_init(x)
 | 
			
		||||
#ifdef HAVE_OPAQUE_STRUCTS
 | 
			
		||||
#define libssh2_sha512_update(ctx, data, len) EVP_DigestUpdate(ctx, data, len)
 | 
			
		||||
#define libssh2_sha512_final(ctx, out) do { \
 | 
			
		||||
                                            EVP_DigestFinal(ctx, out, NULL); \
 | 
			
		||||
                                            EVP_MD_CTX_free(ctx); \
 | 
			
		||||
                                       } while(0)
 | 
			
		||||
#else
 | 
			
		||||
#define libssh2_sha512_update(ctx, data, len)   \
 | 
			
		||||
    EVP_DigestUpdate(&(ctx), data, len)
 | 
			
		||||
#define libssh2_sha512_final(ctx, out) EVP_DigestFinal(&(ctx), out, NULL)
 | 
			
		||||
#endif
 | 
			
		||||
int _libssh2_sha512(const unsigned char *message, unsigned long len,
 | 
			
		||||
                    unsigned char *out);
 | 
			
		||||
#define libssh2_sha512(x,y,z) _libssh2_sha512(x,y,z)
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_OPAQUE_STRUCTS
 | 
			
		||||
#define libssh2_md5_ctx EVP_MD_CTX *
 | 
			
		||||
#else
 | 
			
		||||
#define libssh2_md5_ctx EVP_MD_CTX
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/* returns 0 in case of failure */
 | 
			
		||||
int _libssh2_md5_init(libssh2_md5_ctx *ctx);
 | 
			
		||||
#define libssh2_md5_init(x) _libssh2_md5_init(x)
 | 
			
		||||
#ifdef HAVE_OPAQUE_STRUCTS
 | 
			
		||||
#define libssh2_md5_update(ctx, data, len) EVP_DigestUpdate(ctx, data, len)
 | 
			
		||||
#define libssh2_md5_final(ctx, out) do { \
 | 
			
		||||
                                        EVP_DigestFinal(ctx, out, NULL); \
 | 
			
		||||
                                        EVP_MD_CTX_free(ctx); \
 | 
			
		||||
                                    } while(0)
 | 
			
		||||
#else
 | 
			
		||||
#define libssh2_md5_update(ctx, data, len) EVP_DigestUpdate(&(ctx), data, len)
 | 
			
		||||
#define libssh2_md5_final(ctx, out) EVP_DigestFinal(&(ctx), out, NULL)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_OPAQUE_STRUCTS
 | 
			
		||||
#define libssh2_hmac_ctx HMAC_CTX *
 | 
			
		||||
#define libssh2_hmac_ctx_init(ctx) ctx = HMAC_CTX_new()
 | 
			
		||||
#define libssh2_hmac_sha1_init(ctx, key, keylen) \
 | 
			
		||||
  HMAC_Init_ex(*(ctx), key, keylen, EVP_sha1(), NULL)
 | 
			
		||||
#define libssh2_hmac_md5_init(ctx, key, keylen) \
 | 
			
		||||
  HMAC_Init_ex(*(ctx), key, keylen, EVP_md5(), NULL)
 | 
			
		||||
#define libssh2_hmac_ripemd160_init(ctx, key, keylen) \
 | 
			
		||||
  HMAC_Init_ex(*(ctx), key, keylen, EVP_ripemd160(), NULL)
 | 
			
		||||
#define libssh2_hmac_sha256_init(ctx, key, keylen) \
 | 
			
		||||
  HMAC_Init_ex(*(ctx), key, keylen, EVP_sha256(), NULL)
 | 
			
		||||
#define libssh2_hmac_sha512_init(ctx, key, keylen) \
 | 
			
		||||
  HMAC_Init_ex(*(ctx), key, keylen, EVP_sha512(), NULL)
 | 
			
		||||
 | 
			
		||||
#define libssh2_hmac_update(ctx, data, datalen) \
 | 
			
		||||
  HMAC_Update(ctx, data, datalen)
 | 
			
		||||
#define libssh2_hmac_final(ctx, data) HMAC_Final(ctx, data, NULL)
 | 
			
		||||
#define libssh2_hmac_cleanup(ctx) HMAC_CTX_free(*(ctx))
 | 
			
		||||
#else
 | 
			
		||||
#define libssh2_hmac_ctx HMAC_CTX
 | 
			
		||||
#define libssh2_hmac_ctx_init(ctx) \
 | 
			
		||||
  HMAC_CTX_init(&ctx)
 | 
			
		||||
#define libssh2_hmac_sha1_init(ctx, key, keylen) \
 | 
			
		||||
  HMAC_Init_ex(ctx, key, keylen, EVP_sha1(), NULL)
 | 
			
		||||
#define libssh2_hmac_md5_init(ctx, key, keylen) \
 | 
			
		||||
  HMAC_Init_ex(ctx, key, keylen, EVP_md5(), NULL)
 | 
			
		||||
#define libssh2_hmac_ripemd160_init(ctx, key, keylen) \
 | 
			
		||||
  HMAC_Init_ex(ctx, key, keylen, EVP_ripemd160(), NULL)
 | 
			
		||||
#define libssh2_hmac_sha256_init(ctx, key, keylen) \
 | 
			
		||||
  HMAC_Init_ex(ctx, key, keylen, EVP_sha256(), NULL)
 | 
			
		||||
#define libssh2_hmac_sha512_init(ctx, key, keylen) \
 | 
			
		||||
  HMAC_Init_ex(ctx, key, keylen, EVP_sha512(), NULL)
 | 
			
		||||
 | 
			
		||||
#define libssh2_hmac_update(ctx, data, datalen) \
 | 
			
		||||
  HMAC_Update(&(ctx), data, datalen)
 | 
			
		||||
#define libssh2_hmac_final(ctx, data) HMAC_Final(&(ctx), data, NULL)
 | 
			
		||||
#define libssh2_hmac_cleanup(ctx) HMAC_cleanup(ctx)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
extern void _libssh2_openssl_crypto_init(void);
 | 
			
		||||
extern void _libssh2_openssl_crypto_exit(void);
 | 
			
		||||
#define libssh2_crypto_init() _libssh2_openssl_crypto_init()
 | 
			
		||||
#define libssh2_crypto_exit() _libssh2_openssl_crypto_exit()
 | 
			
		||||
 | 
			
		||||
#define libssh2_rsa_ctx RSA
 | 
			
		||||
 | 
			
		||||
#define _libssh2_rsa_free(rsactx) RSA_free(rsactx)
 | 
			
		||||
 | 
			
		||||
#define libssh2_dsa_ctx DSA
 | 
			
		||||
 | 
			
		||||
#define _libssh2_dsa_free(dsactx) DSA_free(dsactx)
 | 
			
		||||
 | 
			
		||||
#if LIBSSH2_ECDSA
 | 
			
		||||
#define libssh2_ecdsa_ctx EC_KEY
 | 
			
		||||
#define _libssh2_ecdsa_free(ecdsactx) EC_KEY_free(ecdsactx)
 | 
			
		||||
#define _libssh2_ec_key EC_KEY
 | 
			
		||||
 | 
			
		||||
typedef enum {
 | 
			
		||||
    LIBSSH2_EC_CURVE_NISTP256 = NID_X9_62_prime256v1,
 | 
			
		||||
    LIBSSH2_EC_CURVE_NISTP384 = NID_secp384r1,
 | 
			
		||||
    LIBSSH2_EC_CURVE_NISTP521 = NID_secp521r1
 | 
			
		||||
}
 | 
			
		||||
libssh2_curve_type;
 | 
			
		||||
#else
 | 
			
		||||
#define _libssh2_ec_key void
 | 
			
		||||
#endif /* LIBSSH2_ECDSA */
 | 
			
		||||
 | 
			
		||||
#if LIBSSH2_ED25519
 | 
			
		||||
#define libssh2_ed25519_ctx EVP_PKEY
 | 
			
		||||
 | 
			
		||||
#define _libssh2_ed25519_free(ctx) EVP_PKEY_free(ctx)
 | 
			
		||||
#endif /* ED25519 */
 | 
			
		||||
 | 
			
		||||
#define _libssh2_cipher_type(name) const EVP_CIPHER *(*name)(void)
 | 
			
		||||
#ifdef HAVE_OPAQUE_STRUCTS
 | 
			
		||||
#define _libssh2_cipher_ctx EVP_CIPHER_CTX *
 | 
			
		||||
#else
 | 
			
		||||
#define _libssh2_cipher_ctx EVP_CIPHER_CTX
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define _libssh2_cipher_aes256 EVP_aes_256_cbc
 | 
			
		||||
#define _libssh2_cipher_aes192 EVP_aes_192_cbc
 | 
			
		||||
#define _libssh2_cipher_aes128 EVP_aes_128_cbc
 | 
			
		||||
#ifdef HAVE_EVP_AES_128_CTR
 | 
			
		||||
#define _libssh2_cipher_aes128ctr EVP_aes_128_ctr
 | 
			
		||||
#define _libssh2_cipher_aes192ctr EVP_aes_192_ctr
 | 
			
		||||
#define _libssh2_cipher_aes256ctr EVP_aes_256_ctr
 | 
			
		||||
#else
 | 
			
		||||
#define _libssh2_cipher_aes128ctr _libssh2_EVP_aes_128_ctr
 | 
			
		||||
#define _libssh2_cipher_aes192ctr _libssh2_EVP_aes_192_ctr
 | 
			
		||||
#define _libssh2_cipher_aes256ctr _libssh2_EVP_aes_256_ctr
 | 
			
		||||
#endif
 | 
			
		||||
#define _libssh2_cipher_blowfish EVP_bf_cbc
 | 
			
		||||
#define _libssh2_cipher_arcfour EVP_rc4
 | 
			
		||||
#define _libssh2_cipher_cast5 EVP_cast5_cbc
 | 
			
		||||
#define _libssh2_cipher_3des EVP_des_ede3_cbc
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_OPAQUE_STRUCTS
 | 
			
		||||
#define _libssh2_cipher_dtor(ctx) EVP_CIPHER_CTX_free(*(ctx))
 | 
			
		||||
#else
 | 
			
		||||
#define _libssh2_cipher_dtor(ctx) EVP_CIPHER_CTX_cleanup(ctx)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define _libssh2_bn BIGNUM
 | 
			
		||||
#define _libssh2_bn_ctx BN_CTX
 | 
			
		||||
#define _libssh2_bn_ctx_new() BN_CTX_new()
 | 
			
		||||
#define _libssh2_bn_ctx_free(bnctx) BN_CTX_free(bnctx)
 | 
			
		||||
#define _libssh2_bn_init() BN_new()
 | 
			
		||||
#define _libssh2_bn_init_from_bin() _libssh2_bn_init()
 | 
			
		||||
#define _libssh2_bn_set_word(bn, val) BN_set_word(bn, val)
 | 
			
		||||
#define _libssh2_bn_from_bin(bn, len, val) BN_bin2bn(val, len, bn)
 | 
			
		||||
#define _libssh2_bn_to_bin(bn, val) BN_bn2bin(bn, val)
 | 
			
		||||
#define _libssh2_bn_bytes(bn) BN_num_bytes(bn)
 | 
			
		||||
#define _libssh2_bn_bits(bn) BN_num_bits(bn)
 | 
			
		||||
#define _libssh2_bn_free(bn) BN_clear_free(bn)
 | 
			
		||||
 | 
			
		||||
#define _libssh2_dh_ctx BIGNUM *
 | 
			
		||||
#define libssh2_dh_init(dhctx) _libssh2_dh_init(dhctx)
 | 
			
		||||
#define libssh2_dh_key_pair(dhctx, public, g, p, group_order, bnctx) \
 | 
			
		||||
        _libssh2_dh_key_pair(dhctx, public, g, p, group_order, bnctx)
 | 
			
		||||
#define libssh2_dh_secret(dhctx, secret, f, p, bnctx) \
 | 
			
		||||
        _libssh2_dh_secret(dhctx, secret, f, p, bnctx)
 | 
			
		||||
#define libssh2_dh_dtor(dhctx) _libssh2_dh_dtor(dhctx)
 | 
			
		||||
extern void _libssh2_dh_init(_libssh2_dh_ctx *dhctx);
 | 
			
		||||
extern int _libssh2_dh_key_pair(_libssh2_dh_ctx *dhctx, _libssh2_bn *public,
 | 
			
		||||
                                _libssh2_bn *g, _libssh2_bn *p,
 | 
			
		||||
                                int group_order,
 | 
			
		||||
                                _libssh2_bn_ctx *bnctx);
 | 
			
		||||
extern int _libssh2_dh_secret(_libssh2_dh_ctx *dhctx, _libssh2_bn *secret,
 | 
			
		||||
                              _libssh2_bn *f, _libssh2_bn *p,
 | 
			
		||||
                              _libssh2_bn_ctx *bnctx);
 | 
			
		||||
extern void _libssh2_dh_dtor(_libssh2_dh_ctx *dhctx);
 | 
			
		||||
 | 
			
		||||
const EVP_CIPHER *_libssh2_EVP_aes_128_ctr(void);
 | 
			
		||||
const EVP_CIPHER *_libssh2_EVP_aes_192_ctr(void);
 | 
			
		||||
const EVP_CIPHER *_libssh2_EVP_aes_256_ctr(void);
 | 
			
		||||
 | 
			
		||||
#endif /* __LIBSSH2_OPENSSL_H */
 | 
			
		||||
#endif
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| 
						 | 
				
			
			@ -0,0 +1,78 @@
 | 
			
		|||
#if defined(ESP32)
 | 
			
		||||
#ifndef __LIBSSH2_PACKET_H
 | 
			
		||||
#define __LIBSSH2_PACKET_H
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2010 by Daniel Stenberg
 | 
			
		||||
 * Author: Daniel Stenberg <daniel@haxx.se>
 | 
			
		||||
 *
 | 
			
		||||
 * Redistribution and use in source and binary forms,
 | 
			
		||||
 * with or without modification, are permitted provided
 | 
			
		||||
 * that the following conditions are met:
 | 
			
		||||
 *
 | 
			
		||||
 *   Redistributions of source code must retain the above
 | 
			
		||||
 *   copyright notice, this list of conditions and the
 | 
			
		||||
 *   following disclaimer.
 | 
			
		||||
 *
 | 
			
		||||
 *   Redistributions in binary form must reproduce the above
 | 
			
		||||
 *   copyright notice, this list of conditions and the following
 | 
			
		||||
 *   disclaimer in the documentation and/or other materials
 | 
			
		||||
 *   provided with the distribution.
 | 
			
		||||
 *
 | 
			
		||||
 *   Neither the name of the copyright holder nor the names
 | 
			
		||||
 *   of any other contributors may be used to endorse or
 | 
			
		||||
 *   promote products derived from this software without
 | 
			
		||||
 *   specific prior written permission.
 | 
			
		||||
 *
 | 
			
		||||
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
 | 
			
		||||
 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 | 
			
		||||
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 | 
			
		||||
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 | 
			
		||||
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 | 
			
		||||
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | 
			
		||||
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 | 
			
		||||
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 | 
			
		||||
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 | 
			
		||||
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 | 
			
		||||
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 | 
			
		||||
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
 | 
			
		||||
 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
 | 
			
		||||
 * OF SUCH DAMAGE.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
int _libssh2_packet_read(LIBSSH2_SESSION * session);
 | 
			
		||||
 | 
			
		||||
int _libssh2_packet_ask(LIBSSH2_SESSION * session, unsigned char packet_type,
 | 
			
		||||
                        unsigned char **data, size_t *data_len,
 | 
			
		||||
                        int match_ofs,
 | 
			
		||||
                        const unsigned char *match_buf,
 | 
			
		||||
                        size_t match_len);
 | 
			
		||||
 | 
			
		||||
int _libssh2_packet_askv(LIBSSH2_SESSION * session,
 | 
			
		||||
                         const unsigned char *packet_types,
 | 
			
		||||
                         unsigned char **data, size_t *data_len,
 | 
			
		||||
                         int match_ofs,
 | 
			
		||||
                         const unsigned char *match_buf,
 | 
			
		||||
                         size_t match_len);
 | 
			
		||||
int _libssh2_packet_require(LIBSSH2_SESSION * session,
 | 
			
		||||
                            unsigned char packet_type, unsigned char **data,
 | 
			
		||||
                            size_t *data_len, int match_ofs,
 | 
			
		||||
                            const unsigned char *match_buf,
 | 
			
		||||
                            size_t match_len,
 | 
			
		||||
                            packet_require_state_t * state);
 | 
			
		||||
int _libssh2_packet_requirev(LIBSSH2_SESSION *session,
 | 
			
		||||
                             const unsigned char *packet_types,
 | 
			
		||||
                             unsigned char **data, size_t *data_len,
 | 
			
		||||
                             int match_ofs,
 | 
			
		||||
                             const unsigned char *match_buf,
 | 
			
		||||
                             size_t match_len,
 | 
			
		||||
                             packet_requirev_state_t * state);
 | 
			
		||||
int _libssh2_packet_burn(LIBSSH2_SESSION * session,
 | 
			
		||||
                         libssh2_nonblocking_states * state);
 | 
			
		||||
int _libssh2_packet_write(LIBSSH2_SESSION * session, unsigned char *data,
 | 
			
		||||
                          unsigned long data_len);
 | 
			
		||||
int _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data,
 | 
			
		||||
                        size_t datalen, int macstate);
 | 
			
		||||
 | 
			
		||||
#endif /* __LIBSSH2_PACKET_H */
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,913 @@
 | 
			
		|||
#if defined(ESP32)
 | 
			
		||||
/* Copyright (C) 2007 The Written Word, Inc.
 | 
			
		||||
 * Copyright (C) 2008, Simon Josefsson
 | 
			
		||||
 * All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Redistribution and use in source and binary forms,
 | 
			
		||||
 * with or without modification, are permitted provided
 | 
			
		||||
 * that the following conditions are met:
 | 
			
		||||
 *
 | 
			
		||||
 *   Redistributions of source code must retain the above
 | 
			
		||||
 *   copyright notice, this list of conditions and the
 | 
			
		||||
 *   following disclaimer.
 | 
			
		||||
 *
 | 
			
		||||
 *   Redistributions in binary form must reproduce the above
 | 
			
		||||
 *   copyright notice, this list of conditions and the following
 | 
			
		||||
 *   disclaimer in the documentation and/or other materials
 | 
			
		||||
 *   provided with the distribution.
 | 
			
		||||
 *
 | 
			
		||||
 *   Neither the name of the copyright holder nor the names
 | 
			
		||||
 *   of any other contributors may be used to endorse or
 | 
			
		||||
 *   promote products derived from this software without
 | 
			
		||||
 *   specific prior written permission.
 | 
			
		||||
 *
 | 
			
		||||
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
 | 
			
		||||
 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 | 
			
		||||
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 | 
			
		||||
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 | 
			
		||||
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 | 
			
		||||
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | 
			
		||||
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 | 
			
		||||
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 | 
			
		||||
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 | 
			
		||||
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 | 
			
		||||
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 | 
			
		||||
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
 | 
			
		||||
 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
 | 
			
		||||
 * OF SUCH DAMAGE.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "libssh2_priv.h"
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
readline(char *line, int line_size, FILE * fp)
 | 
			
		||||
{
 | 
			
		||||
    size_t len;
 | 
			
		||||
 | 
			
		||||
    if(!line) {
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
    if(!fgets(line, line_size, fp)) {
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if(*line) {
 | 
			
		||||
        len = strlen(line);
 | 
			
		||||
        if(len > 0 && line[len - 1] == '\n') {
 | 
			
		||||
            line[len - 1] = '\0';
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if(*line) {
 | 
			
		||||
        len = strlen(line);
 | 
			
		||||
        if(len > 0 && line[len - 1] == '\r') {
 | 
			
		||||
            line[len - 1] = '\0';
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
readline_memory(char *line, size_t line_size,
 | 
			
		||||
                const char *filedata, size_t filedata_len,
 | 
			
		||||
                size_t *filedata_offset)
 | 
			
		||||
{
 | 
			
		||||
    size_t off, len;
 | 
			
		||||
 | 
			
		||||
    off = *filedata_offset;
 | 
			
		||||
 | 
			
		||||
    for(len = 0; off + len < filedata_len && len < line_size - 1; len++) {
 | 
			
		||||
        if(filedata[off + len] == '\n' ||
 | 
			
		||||
            filedata[off + len] == '\r') {
 | 
			
		||||
                break;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if(len) {
 | 
			
		||||
        memcpy(line, filedata + off, len);
 | 
			
		||||
        *filedata_offset += len;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    line[len] = '\0';
 | 
			
		||||
    *filedata_offset += 1;
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define LINE_SIZE 128
 | 
			
		||||
 | 
			
		||||
static const char *crypt_annotation = "Proc-Type: 4,ENCRYPTED";
 | 
			
		||||
 | 
			
		||||
static unsigned char hex_decode(char digit)
 | 
			
		||||
{
 | 
			
		||||
    return (digit >= 'A') ? 0xA + (digit - 'A') : (digit - '0');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
_libssh2_pem_parse(LIBSSH2_SESSION * session,
 | 
			
		||||
                   const char *headerbegin,
 | 
			
		||||
                   const char *headerend,
 | 
			
		||||
                   const unsigned char *passphrase,
 | 
			
		||||
                   FILE * fp, unsigned char **data, unsigned int *datalen)
 | 
			
		||||
{
 | 
			
		||||
    char line[LINE_SIZE];
 | 
			
		||||
    unsigned char iv[LINE_SIZE];
 | 
			
		||||
    char *b64data = NULL;
 | 
			
		||||
    unsigned int b64datalen = 0;
 | 
			
		||||
    int ret;
 | 
			
		||||
    const LIBSSH2_CRYPT_METHOD *method = NULL;
 | 
			
		||||
 | 
			
		||||
    do {
 | 
			
		||||
        *line = '\0';
 | 
			
		||||
 | 
			
		||||
        if(readline(line, LINE_SIZE, fp)) {
 | 
			
		||||
            return -1;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    while(strcmp(line, headerbegin) != 0);
 | 
			
		||||
 | 
			
		||||
    if(readline(line, LINE_SIZE, fp)) {
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if(passphrase &&
 | 
			
		||||
            memcmp(line, crypt_annotation, strlen(crypt_annotation)) == 0) {
 | 
			
		||||
        const LIBSSH2_CRYPT_METHOD **all_methods, *cur_method;
 | 
			
		||||
        int i;
 | 
			
		||||
 | 
			
		||||
        if(readline(line, LINE_SIZE, fp)) {
 | 
			
		||||
            ret = -1;
 | 
			
		||||
            goto out;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        all_methods = libssh2_crypt_methods();
 | 
			
		||||
        while((cur_method = *all_methods++) != NULL) {
 | 
			
		||||
            if(*cur_method->pem_annotation &&
 | 
			
		||||
                    memcmp(line, cur_method->pem_annotation,
 | 
			
		||||
                           strlen(cur_method->pem_annotation)) == 0) {
 | 
			
		||||
                method = cur_method;
 | 
			
		||||
                memcpy(iv, line + strlen(method->pem_annotation) + 1,
 | 
			
		||||
                       2*method->iv_len);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /* None of the available crypt methods were able to decrypt the key */
 | 
			
		||||
        if(method == NULL)
 | 
			
		||||
            return -1;
 | 
			
		||||
 | 
			
		||||
        /* Decode IV from hex */
 | 
			
		||||
        for(i = 0; i < method->iv_len; ++i) {
 | 
			
		||||
            iv[i]  = hex_decode(iv[2*i]) << 4;
 | 
			
		||||
            iv[i] |= hex_decode(iv[2*i + 1]);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /* skip to the next line */
 | 
			
		||||
        if(readline(line, LINE_SIZE, fp)) {
 | 
			
		||||
            ret = -1;
 | 
			
		||||
            goto out;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    do {
 | 
			
		||||
        if(*line) {
 | 
			
		||||
            char *tmp;
 | 
			
		||||
            size_t linelen;
 | 
			
		||||
 | 
			
		||||
            linelen = strlen(line);
 | 
			
		||||
            tmp = LIBSSH2_REALLOC(session, b64data, b64datalen + linelen);
 | 
			
		||||
            if(!tmp) {
 | 
			
		||||
                _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
 | 
			
		||||
                               "Unable to allocate memory for PEM parsing");
 | 
			
		||||
                ret = -1;
 | 
			
		||||
                goto out;
 | 
			
		||||
            }
 | 
			
		||||
            memcpy(tmp + b64datalen, line, linelen);
 | 
			
		||||
            b64data = tmp;
 | 
			
		||||
            b64datalen += linelen;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        *line = '\0';
 | 
			
		||||
 | 
			
		||||
        if(readline(line, LINE_SIZE, fp)) {
 | 
			
		||||
            ret = -1;
 | 
			
		||||
            goto out;
 | 
			
		||||
        }
 | 
			
		||||
    } while(strcmp(line, headerend) != 0);
 | 
			
		||||
 | 
			
		||||
    if(!b64data) {
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if(libssh2_base64_decode(session, (char **) data, datalen,
 | 
			
		||||
                              b64data, b64datalen)) {
 | 
			
		||||
        ret = -1;
 | 
			
		||||
        goto out;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if(method) {
 | 
			
		||||
        /* Set up decryption */
 | 
			
		||||
        int free_iv = 0, free_secret = 0, len_decrypted = 0, padding = 0;
 | 
			
		||||
        int blocksize = method->blocksize;
 | 
			
		||||
        void *abstract;
 | 
			
		||||
        unsigned char secret[2*MD5_DIGEST_LENGTH];
 | 
			
		||||
        libssh2_md5_ctx fingerprint_ctx;
 | 
			
		||||
 | 
			
		||||
        /* Perform key derivation (PBKDF1/MD5) */
 | 
			
		||||
        if(!libssh2_md5_init(&fingerprint_ctx)) {
 | 
			
		||||
            ret = -1;
 | 
			
		||||
            goto out;
 | 
			
		||||
        }
 | 
			
		||||
        libssh2_md5_update(fingerprint_ctx, passphrase,
 | 
			
		||||
                           strlen((char *)passphrase));
 | 
			
		||||
        libssh2_md5_update(fingerprint_ctx, iv, 8);
 | 
			
		||||
        libssh2_md5_final(fingerprint_ctx, secret);
 | 
			
		||||
        if(method->secret_len > MD5_DIGEST_LENGTH) {
 | 
			
		||||
            if(!libssh2_md5_init(&fingerprint_ctx)) {
 | 
			
		||||
                ret = -1;
 | 
			
		||||
                goto out;
 | 
			
		||||
            }
 | 
			
		||||
            libssh2_md5_update(fingerprint_ctx, secret, MD5_DIGEST_LENGTH);
 | 
			
		||||
            libssh2_md5_update(fingerprint_ctx, passphrase,
 | 
			
		||||
                               strlen((char *)passphrase));
 | 
			
		||||
            libssh2_md5_update(fingerprint_ctx, iv, 8);
 | 
			
		||||
            libssh2_md5_final(fingerprint_ctx, secret + MD5_DIGEST_LENGTH);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /* Initialize the decryption */
 | 
			
		||||
        if(method->init(session, method, iv, &free_iv, secret,
 | 
			
		||||
                         &free_secret, 0, &abstract)) {
 | 
			
		||||
            _libssh2_explicit_zero((char *)secret, sizeof(secret));
 | 
			
		||||
            LIBSSH2_FREE(session, data);
 | 
			
		||||
            ret = -1;
 | 
			
		||||
            goto out;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if(free_secret) {
 | 
			
		||||
            _libssh2_explicit_zero((char *)secret, sizeof(secret));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /* Do the actual decryption */
 | 
			
		||||
        if((*datalen % blocksize) != 0) {
 | 
			
		||||
            _libssh2_explicit_zero((char *)secret, sizeof(secret));
 | 
			
		||||
            method->dtor(session, &abstract);
 | 
			
		||||
            _libssh2_explicit_zero(*data, *datalen);
 | 
			
		||||
            LIBSSH2_FREE(session, *data);
 | 
			
		||||
            ret = -1;
 | 
			
		||||
            goto out;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        while(len_decrypted <= (int)*datalen - blocksize) {
 | 
			
		||||
            if(method->crypt(session, *data + len_decrypted, blocksize,
 | 
			
		||||
                              &abstract)) {
 | 
			
		||||
                ret = LIBSSH2_ERROR_DECRYPT;
 | 
			
		||||
                _libssh2_explicit_zero((char *)secret, sizeof(secret));
 | 
			
		||||
                method->dtor(session, &abstract);
 | 
			
		||||
                _libssh2_explicit_zero(*data, *datalen);
 | 
			
		||||
                LIBSSH2_FREE(session, *data);
 | 
			
		||||
                goto out;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            len_decrypted += blocksize;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /* Account for padding */
 | 
			
		||||
        padding = (*data)[*datalen - 1];
 | 
			
		||||
        memset(&(*data)[*datalen-padding], 0, padding);
 | 
			
		||||
        *datalen -= padding;
 | 
			
		||||
 | 
			
		||||
        /* Clean up */
 | 
			
		||||
        _libssh2_explicit_zero((char *)secret, sizeof(secret));
 | 
			
		||||
        method->dtor(session, &abstract);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ret = 0;
 | 
			
		||||
  out:
 | 
			
		||||
    if(b64data) {
 | 
			
		||||
        _libssh2_explicit_zero(b64data, b64datalen);
 | 
			
		||||
        LIBSSH2_FREE(session, b64data);
 | 
			
		||||
    }
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
_libssh2_pem_parse_memory(LIBSSH2_SESSION * session,
 | 
			
		||||
                          const char *headerbegin,
 | 
			
		||||
                          const char *headerend,
 | 
			
		||||
                          const char *filedata, size_t filedata_len,
 | 
			
		||||
                          unsigned char **data, unsigned int *datalen)
 | 
			
		||||
{
 | 
			
		||||
    char line[LINE_SIZE];
 | 
			
		||||
    char *b64data = NULL;
 | 
			
		||||
    unsigned int b64datalen = 0;
 | 
			
		||||
    size_t off = 0;
 | 
			
		||||
    int ret;
 | 
			
		||||
 | 
			
		||||
    do {
 | 
			
		||||
        *line = '\0';
 | 
			
		||||
 | 
			
		||||
        if(readline_memory(line, LINE_SIZE, filedata, filedata_len, &off)) {
 | 
			
		||||
            return -1;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    while(strcmp(line, headerbegin) != 0);
 | 
			
		||||
 | 
			
		||||
    *line = '\0';
 | 
			
		||||
 | 
			
		||||
    do {
 | 
			
		||||
        if(*line) {
 | 
			
		||||
            char *tmp;
 | 
			
		||||
            size_t linelen;
 | 
			
		||||
 | 
			
		||||
            linelen = strlen(line);
 | 
			
		||||
            tmp = LIBSSH2_REALLOC(session, b64data, b64datalen + linelen);
 | 
			
		||||
            if(!tmp) {
 | 
			
		||||
                _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
 | 
			
		||||
                               "Unable to allocate memory for PEM parsing");
 | 
			
		||||
                ret = -1;
 | 
			
		||||
                goto out;
 | 
			
		||||
            }
 | 
			
		||||
            memcpy(tmp + b64datalen, line, linelen);
 | 
			
		||||
            b64data = tmp;
 | 
			
		||||
            b64datalen += linelen;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        *line = '\0';
 | 
			
		||||
 | 
			
		||||
        if(readline_memory(line, LINE_SIZE, filedata, filedata_len, &off)) {
 | 
			
		||||
            ret = -1;
 | 
			
		||||
            goto out;
 | 
			
		||||
        }
 | 
			
		||||
    } while(strcmp(line, headerend) != 0);
 | 
			
		||||
 | 
			
		||||
    if(!b64data) {
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if(libssh2_base64_decode(session, (char **) data, datalen,
 | 
			
		||||
                              b64data, b64datalen)) {
 | 
			
		||||
        ret = -1;
 | 
			
		||||
        goto out;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ret = 0;
 | 
			
		||||
  out:
 | 
			
		||||
    if(b64data) {
 | 
			
		||||
        _libssh2_explicit_zero(b64data, b64datalen);
 | 
			
		||||
        LIBSSH2_FREE(session, b64data);
 | 
			
		||||
    }
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* OpenSSH formatted keys */
 | 
			
		||||
#define AUTH_MAGIC "openssh-key-v1"
 | 
			
		||||
#define OPENSSH_HEADER_BEGIN "-----BEGIN OPENSSH PRIVATE KEY-----"
 | 
			
		||||
#define OPENSSH_HEADER_END "-----END OPENSSH PRIVATE KEY-----"
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
_libssh2_openssh_pem_parse_data(LIBSSH2_SESSION * session,
 | 
			
		||||
                                const unsigned char *passphrase,
 | 
			
		||||
                                const char *b64data, size_t b64datalen,
 | 
			
		||||
                                struct string_buf **decrypted_buf)
 | 
			
		||||
{
 | 
			
		||||
    const LIBSSH2_CRYPT_METHOD *method = NULL;
 | 
			
		||||
    struct string_buf decoded, decrypted, kdf_buf;
 | 
			
		||||
    unsigned char *ciphername = NULL;
 | 
			
		||||
    unsigned char *kdfname = NULL;
 | 
			
		||||
    unsigned char *kdf = NULL;
 | 
			
		||||
    unsigned char *buf = NULL;
 | 
			
		||||
    unsigned char *salt = NULL;
 | 
			
		||||
    uint32_t nkeys, check1, check2;
 | 
			
		||||
    uint32_t rounds = 0;
 | 
			
		||||
    unsigned char *key = NULL;
 | 
			
		||||
    unsigned char *key_part = NULL;
 | 
			
		||||
    unsigned char *iv_part = NULL;
 | 
			
		||||
    unsigned char *f = NULL;
 | 
			
		||||
    unsigned int f_len = 0;
 | 
			
		||||
    int ret = 0, keylen = 0, ivlen = 0, total_len = 0;
 | 
			
		||||
    size_t kdf_len = 0, tmp_len = 0, salt_len = 0;
 | 
			
		||||
 | 
			
		||||
    if(decrypted_buf)
 | 
			
		||||
        *decrypted_buf = NULL;
 | 
			
		||||
 | 
			
		||||
    /* decode file */
 | 
			
		||||
    if(libssh2_base64_decode(session, (char **)&f, &f_len,
 | 
			
		||||
                             b64data, b64datalen)) {
 | 
			
		||||
       ret = -1;
 | 
			
		||||
       goto out;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Parse the file */
 | 
			
		||||
    decoded.data = (unsigned char *)f;
 | 
			
		||||
    decoded.dataptr = (unsigned char *)f;
 | 
			
		||||
    decoded.len = f_len;
 | 
			
		||||
 | 
			
		||||
    if(decoded.len < strlen(AUTH_MAGIC)) {
 | 
			
		||||
        ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO, "key too short");
 | 
			
		||||
        goto out;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if(strncmp((char *) decoded.dataptr, AUTH_MAGIC,
 | 
			
		||||
               strlen(AUTH_MAGIC)) != 0) {
 | 
			
		||||
        ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
 | 
			
		||||
                             "key auth magic mismatch");
 | 
			
		||||
        goto out;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    decoded.dataptr += strlen(AUTH_MAGIC) + 1;
 | 
			
		||||
 | 
			
		||||
    if(_libssh2_get_string(&decoded, &ciphername, &tmp_len) ||
 | 
			
		||||
       tmp_len == 0) {
 | 
			
		||||
        ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
 | 
			
		||||
                             "ciphername is missing");
 | 
			
		||||
        goto out;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if(_libssh2_get_string(&decoded, &kdfname, &tmp_len) ||
 | 
			
		||||
       tmp_len == 0) {
 | 
			
		||||
        ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
 | 
			
		||||
                       "kdfname is missing");
 | 
			
		||||
        goto out;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if(_libssh2_get_string(&decoded, &kdf, &kdf_len)) {
 | 
			
		||||
        ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
 | 
			
		||||
                             "kdf is missing");
 | 
			
		||||
        goto out;
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
        kdf_buf.data = kdf;
 | 
			
		||||
        kdf_buf.dataptr = kdf;
 | 
			
		||||
        kdf_buf.len = kdf_len;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if((passphrase == NULL || strlen((const char *)passphrase) == 0) &&
 | 
			
		||||
        strcmp((const char *)ciphername, "none") != 0) {
 | 
			
		||||
        /* passphrase required */
 | 
			
		||||
        ret = LIBSSH2_ERROR_KEYFILE_AUTH_FAILED;
 | 
			
		||||
        goto out;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if(strcmp((const char *)kdfname, "none") != 0 &&
 | 
			
		||||
       strcmp((const char *)kdfname, "bcrypt") != 0) {
 | 
			
		||||
        ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
 | 
			
		||||
                             "unknown cipher");
 | 
			
		||||
        goto out;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if(!strcmp((const char *)kdfname, "none") &&
 | 
			
		||||
       strcmp((const char *)ciphername, "none") != 0) {
 | 
			
		||||
        ret =_libssh2_error(session, LIBSSH2_ERROR_PROTO,
 | 
			
		||||
                            "invalid format");
 | 
			
		||||
        goto out;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if(_libssh2_get_u32(&decoded, &nkeys) != 0 || nkeys != 1) {
 | 
			
		||||
        ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
 | 
			
		||||
                             "Multiple keys are unsupported");
 | 
			
		||||
        goto out;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* unencrypted public key */
 | 
			
		||||
 | 
			
		||||
    if(_libssh2_get_string(&decoded, &buf, &tmp_len) || tmp_len == 0) {
 | 
			
		||||
        ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
 | 
			
		||||
                             "Invalid private key; "
 | 
			
		||||
                             "expect embedded public key");
 | 
			
		||||
        goto out;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if(_libssh2_get_string(&decoded, &buf, &tmp_len) || tmp_len == 0) {
 | 
			
		||||
        ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
 | 
			
		||||
                       "Private key data not found");
 | 
			
		||||
        goto out;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* decode encrypted private key */
 | 
			
		||||
    decrypted.data = decrypted.dataptr = buf;
 | 
			
		||||
    decrypted.len = tmp_len;
 | 
			
		||||
 | 
			
		||||
    if(ciphername && strcmp((const char *)ciphername, "none") != 0) {
 | 
			
		||||
        const LIBSSH2_CRYPT_METHOD **all_methods, *cur_method;
 | 
			
		||||
 | 
			
		||||
        all_methods = libssh2_crypt_methods();
 | 
			
		||||
        while((cur_method = *all_methods++) != NULL) {
 | 
			
		||||
            if(*cur_method->name &&
 | 
			
		||||
                memcmp(ciphername, cur_method->name,
 | 
			
		||||
                       strlen(cur_method->name)) == 0) {
 | 
			
		||||
                    method = cur_method;
 | 
			
		||||
                }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /* None of the available crypt methods were able to decrypt the key */
 | 
			
		||||
 | 
			
		||||
        if(method == NULL) {
 | 
			
		||||
            ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
 | 
			
		||||
                                "No supported cipher found");
 | 
			
		||||
            goto out;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if(method) {
 | 
			
		||||
        int free_iv = 0, free_secret = 0, len_decrypted = 0;
 | 
			
		||||
        int blocksize;
 | 
			
		||||
        void *abstract = NULL;
 | 
			
		||||
 | 
			
		||||
        keylen = method->secret_len;
 | 
			
		||||
        ivlen = method->iv_len;
 | 
			
		||||
        total_len = keylen + ivlen;
 | 
			
		||||
 | 
			
		||||
        key = LIBSSH2_CALLOC(session, total_len);
 | 
			
		||||
        if(key == NULL) {
 | 
			
		||||
            ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
 | 
			
		||||
                           "Could not alloc key");
 | 
			
		||||
            goto out;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if(strcmp((const char *)kdfname, "bcrypt") == 0 &&
 | 
			
		||||
           passphrase != NULL) {
 | 
			
		||||
            if((_libssh2_get_string(&kdf_buf, &salt, &salt_len)) ||
 | 
			
		||||
                (_libssh2_get_u32(&kdf_buf, &rounds) != 0) ) {
 | 
			
		||||
                ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
 | 
			
		||||
                                     "kdf contains unexpected values");
 | 
			
		||||
                LIBSSH2_FREE(session, key);
 | 
			
		||||
                goto out;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if(_libssh2_bcrypt_pbkdf((const char *)passphrase,
 | 
			
		||||
                                     strlen((const char *)passphrase),
 | 
			
		||||
                                     salt, salt_len, key,
 | 
			
		||||
                                     keylen + ivlen, rounds) < 0) {
 | 
			
		||||
                ret = _libssh2_error(session, LIBSSH2_ERROR_DECRYPT,
 | 
			
		||||
                                     "invalid format");
 | 
			
		||||
                LIBSSH2_FREE(session, key);
 | 
			
		||||
                goto out;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            ret = _libssh2_error(session, LIBSSH2_ERROR_KEYFILE_AUTH_FAILED,
 | 
			
		||||
                                            "bcrypted without passphrase");
 | 
			
		||||
            LIBSSH2_FREE(session, key);
 | 
			
		||||
            goto out;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /* Set up decryption */
 | 
			
		||||
        blocksize = method->blocksize;
 | 
			
		||||
 | 
			
		||||
        key_part = LIBSSH2_CALLOC(session, keylen);
 | 
			
		||||
        if(key_part == NULL) {
 | 
			
		||||
            ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
 | 
			
		||||
                                 "Could not alloc key part");
 | 
			
		||||
            goto out;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        iv_part = LIBSSH2_CALLOC(session, ivlen);
 | 
			
		||||
        if(iv_part == NULL) {
 | 
			
		||||
            ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
 | 
			
		||||
                                 "Could not alloc iv part");
 | 
			
		||||
            goto out;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        memcpy(key_part, key, keylen);
 | 
			
		||||
        memcpy(iv_part, key + keylen, ivlen);
 | 
			
		||||
 | 
			
		||||
        /* Initialize the decryption */
 | 
			
		||||
        if(method->init(session, method, iv_part, &free_iv, key_part,
 | 
			
		||||
                         &free_secret, 0, &abstract)) {
 | 
			
		||||
            ret = LIBSSH2_ERROR_DECRYPT;
 | 
			
		||||
            goto out;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /* Do the actual decryption */
 | 
			
		||||
        if((decrypted.len % blocksize) != 0) {
 | 
			
		||||
            method->dtor(session, &abstract);
 | 
			
		||||
            ret = LIBSSH2_ERROR_DECRYPT;
 | 
			
		||||
            goto out;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        while((size_t)len_decrypted <= decrypted.len - blocksize) {
 | 
			
		||||
            if(method->crypt(session, decrypted.data + len_decrypted,
 | 
			
		||||
                             blocksize,
 | 
			
		||||
                             &abstract)) {
 | 
			
		||||
                ret = LIBSSH2_ERROR_DECRYPT;
 | 
			
		||||
                method->dtor(session, &abstract);
 | 
			
		||||
                goto out;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            len_decrypted += blocksize;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /* No padding */
 | 
			
		||||
 | 
			
		||||
        method->dtor(session, &abstract);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Check random bytes match */
 | 
			
		||||
 | 
			
		||||
    if(_libssh2_get_u32(&decrypted, &check1) != 0 ||
 | 
			
		||||
       _libssh2_get_u32(&decrypted, &check2) != 0 ||
 | 
			
		||||
       check1 != check2) {
 | 
			
		||||
       _libssh2_error(session, LIBSSH2_ERROR_PROTO,
 | 
			
		||||
                      "Private key unpack failed (correct password?)");
 | 
			
		||||
       ret = LIBSSH2_ERROR_KEYFILE_AUTH_FAILED;
 | 
			
		||||
       goto out;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if(decrypted_buf != NULL) {
 | 
			
		||||
        /* copy data to out-going buffer */
 | 
			
		||||
        struct string_buf *out_buf = _libssh2_string_buf_new(session);
 | 
			
		||||
        if(!out_buf) {
 | 
			
		||||
            ret = _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
 | 
			
		||||
                                 "Unable to allocate memory for "
 | 
			
		||||
                                 "decrypted struct");
 | 
			
		||||
            goto out;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        out_buf->data = LIBSSH2_CALLOC(session, decrypted.len);
 | 
			
		||||
        if(out_buf->data == NULL) {
 | 
			
		||||
            ret = _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
 | 
			
		||||
                                 "Unable to allocate memory for "
 | 
			
		||||
                                 "decrypted struct");
 | 
			
		||||
            _libssh2_string_buf_free(session, out_buf);
 | 
			
		||||
            goto out;
 | 
			
		||||
        }
 | 
			
		||||
        memcpy(out_buf->data, decrypted.data, decrypted.len);
 | 
			
		||||
        out_buf->dataptr = out_buf->data +
 | 
			
		||||
            (decrypted.dataptr - decrypted.data);
 | 
			
		||||
        out_buf->len = decrypted.len;
 | 
			
		||||
 | 
			
		||||
        *decrypted_buf = out_buf;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
out:
 | 
			
		||||
 | 
			
		||||
    /* Clean up */
 | 
			
		||||
    if(key) {
 | 
			
		||||
        _libssh2_explicit_zero(key, total_len);
 | 
			
		||||
        LIBSSH2_FREE(session, key);
 | 
			
		||||
    }
 | 
			
		||||
    if(key_part) {
 | 
			
		||||
        _libssh2_explicit_zero(key_part, keylen);
 | 
			
		||||
        LIBSSH2_FREE(session, key_part);
 | 
			
		||||
    }
 | 
			
		||||
    if(iv_part) {
 | 
			
		||||
        _libssh2_explicit_zero(iv_part, ivlen);
 | 
			
		||||
        LIBSSH2_FREE(session, iv_part);
 | 
			
		||||
    }
 | 
			
		||||
    if(f) {
 | 
			
		||||
        _libssh2_explicit_zero(f, f_len);
 | 
			
		||||
        LIBSSH2_FREE(session, f);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
_libssh2_openssh_pem_parse(LIBSSH2_SESSION * session,
 | 
			
		||||
                           const unsigned char *passphrase,
 | 
			
		||||
                           FILE * fp, struct string_buf **decrypted_buf)
 | 
			
		||||
{
 | 
			
		||||
    char line[LINE_SIZE];
 | 
			
		||||
    char *b64data = NULL;
 | 
			
		||||
    unsigned int b64datalen = 0;
 | 
			
		||||
    int ret = 0;
 | 
			
		||||
 | 
			
		||||
    /* read file */
 | 
			
		||||
 | 
			
		||||
    do {
 | 
			
		||||
        *line = '\0';
 | 
			
		||||
 | 
			
		||||
        if(readline(line, LINE_SIZE, fp)) {
 | 
			
		||||
            return -1;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    while(strcmp(line, OPENSSH_HEADER_BEGIN) != 0);
 | 
			
		||||
 | 
			
		||||
    if(readline(line, LINE_SIZE, fp)) {
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    do {
 | 
			
		||||
        if(*line) {
 | 
			
		||||
            char *tmp;
 | 
			
		||||
            size_t linelen;
 | 
			
		||||
 | 
			
		||||
            linelen = strlen(line);
 | 
			
		||||
            tmp = LIBSSH2_REALLOC(session, b64data, b64datalen + linelen);
 | 
			
		||||
            if(!tmp) {
 | 
			
		||||
                _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
 | 
			
		||||
                               "Unable to allocate memory for PEM parsing");
 | 
			
		||||
                ret = -1;
 | 
			
		||||
                goto out;
 | 
			
		||||
            }
 | 
			
		||||
            memcpy(tmp + b64datalen, line, linelen);
 | 
			
		||||
            b64data = tmp;
 | 
			
		||||
            b64datalen += linelen;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        *line = '\0';
 | 
			
		||||
 | 
			
		||||
        if(readline(line, LINE_SIZE, fp)) {
 | 
			
		||||
            ret = -1;
 | 
			
		||||
            goto out;
 | 
			
		||||
        }
 | 
			
		||||
    } while(strcmp(line, OPENSSH_HEADER_END) != 0);
 | 
			
		||||
 | 
			
		||||
    if(!b64data) {
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ret = _libssh2_openssh_pem_parse_data(session,
 | 
			
		||||
                                          passphrase,
 | 
			
		||||
                                          (const char *)b64data,
 | 
			
		||||
                                          (size_t)b64datalen,
 | 
			
		||||
                                          decrypted_buf);
 | 
			
		||||
 | 
			
		||||
    if(b64data) {
 | 
			
		||||
        _libssh2_explicit_zero(b64data, b64datalen);
 | 
			
		||||
        LIBSSH2_FREE(session, b64data);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
out:
 | 
			
		||||
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
_libssh2_openssh_pem_parse_memory(LIBSSH2_SESSION * session,
 | 
			
		||||
                                  const unsigned char *passphrase,
 | 
			
		||||
                                  const char *filedata, size_t filedata_len,
 | 
			
		||||
                                  struct string_buf **decrypted_buf)
 | 
			
		||||
{
 | 
			
		||||
    char line[LINE_SIZE];
 | 
			
		||||
    char *b64data = NULL;
 | 
			
		||||
    unsigned int b64datalen = 0;
 | 
			
		||||
    size_t off = 0;
 | 
			
		||||
    int ret;
 | 
			
		||||
 | 
			
		||||
    if(filedata == NULL || filedata_len <= 0)
 | 
			
		||||
        return _libssh2_error(session, LIBSSH2_ERROR_PROTO,
 | 
			
		||||
                              "Error parsing PEM: filedata missing");
 | 
			
		||||
 | 
			
		||||
    do {
 | 
			
		||||
 | 
			
		||||
        *line = '\0';
 | 
			
		||||
 | 
			
		||||
        if(off >= filedata_len)
 | 
			
		||||
            return _libssh2_error(session, LIBSSH2_ERROR_PROTO,
 | 
			
		||||
                                  "Error parsing PEM: offset out of bounds");
 | 
			
		||||
 | 
			
		||||
        if(readline_memory(line, LINE_SIZE, filedata, filedata_len, &off)) {
 | 
			
		||||
            return -1;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    while(strcmp(line, OPENSSH_HEADER_BEGIN) != 0);
 | 
			
		||||
 | 
			
		||||
    *line = '\0';
 | 
			
		||||
 | 
			
		||||
    do {
 | 
			
		||||
        if (*line) {
 | 
			
		||||
            char *tmp;
 | 
			
		||||
            size_t linelen;
 | 
			
		||||
 | 
			
		||||
            linelen = strlen(line);
 | 
			
		||||
            tmp = LIBSSH2_REALLOC(session, b64data, b64datalen + linelen);
 | 
			
		||||
            if(!tmp) {
 | 
			
		||||
                ret = _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
 | 
			
		||||
                                     "Unable to allocate memory for "
 | 
			
		||||
                                     "PEM parsing");
 | 
			
		||||
                goto out;
 | 
			
		||||
            }
 | 
			
		||||
            memcpy(tmp + b64datalen, line, linelen);
 | 
			
		||||
            b64data = tmp;
 | 
			
		||||
            b64datalen += linelen;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        *line = '\0';
 | 
			
		||||
 | 
			
		||||
        if(off >= filedata_len) {
 | 
			
		||||
            ret = _libssh2_error(session, LIBSSH2_ERROR_PROTO,
 | 
			
		||||
                                 "Error parsing PEM: offset out of bounds");
 | 
			
		||||
            goto out;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if(readline_memory(line, LINE_SIZE, filedata, filedata_len, &off)) {
 | 
			
		||||
            ret = -1;
 | 
			
		||||
            goto out;
 | 
			
		||||
        }
 | 
			
		||||
    } while(strcmp(line, OPENSSH_HEADER_END) != 0);
 | 
			
		||||
 | 
			
		||||
    if(!b64data)
 | 
			
		||||
        return _libssh2_error(session, LIBSSH2_ERROR_PROTO,
 | 
			
		||||
                              "Error parsing PEM: base 64 data missing");
 | 
			
		||||
 | 
			
		||||
    ret = _libssh2_openssh_pem_parse_data(session, passphrase, b64data,
 | 
			
		||||
                                          b64datalen, decrypted_buf);
 | 
			
		||||
 | 
			
		||||
out:
 | 
			
		||||
    if(b64data) {
 | 
			
		||||
        _libssh2_explicit_zero(b64data, b64datalen);
 | 
			
		||||
        LIBSSH2_FREE(session, b64data);
 | 
			
		||||
    }
 | 
			
		||||
    return ret;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
read_asn1_length(const unsigned char *data,
 | 
			
		||||
                 unsigned int datalen, unsigned int *len)
 | 
			
		||||
{
 | 
			
		||||
    unsigned int lenlen;
 | 
			
		||||
    int nextpos;
 | 
			
		||||
 | 
			
		||||
    if(datalen < 1) {
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
    *len = data[0];
 | 
			
		||||
 | 
			
		||||
    if(*len >= 0x80) {
 | 
			
		||||
        lenlen = *len & 0x7F;
 | 
			
		||||
        *len = data[1];
 | 
			
		||||
        if(1 + lenlen > datalen) {
 | 
			
		||||
            return -1;
 | 
			
		||||
        }
 | 
			
		||||
        if(lenlen > 1) {
 | 
			
		||||
            *len <<= 8;
 | 
			
		||||
            *len |= data[2];
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
        lenlen = 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    nextpos = 1 + lenlen;
 | 
			
		||||
    if(lenlen > 2 || 1 + lenlen + *len > datalen) {
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return nextpos;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
_libssh2_pem_decode_sequence(unsigned char **data, unsigned int *datalen)
 | 
			
		||||
{
 | 
			
		||||
    unsigned int len;
 | 
			
		||||
    int lenlen;
 | 
			
		||||
 | 
			
		||||
    if(*datalen < 1) {
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if((*data)[0] != '\x30') {
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    (*data)++;
 | 
			
		||||
    (*datalen)--;
 | 
			
		||||
 | 
			
		||||
    lenlen = read_asn1_length(*data, *datalen, &len);
 | 
			
		||||
    if(lenlen < 0 || lenlen + len != *datalen) {
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    *data += lenlen;
 | 
			
		||||
    *datalen -= lenlen;
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
_libssh2_pem_decode_integer(unsigned char **data, unsigned int *datalen,
 | 
			
		||||
                            unsigned char **i, unsigned int *ilen)
 | 
			
		||||
{
 | 
			
		||||
    unsigned int len;
 | 
			
		||||
    int lenlen;
 | 
			
		||||
 | 
			
		||||
    if(*datalen < 1) {
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if((*data)[0] != '\x02') {
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    (*data)++;
 | 
			
		||||
    (*datalen)--;
 | 
			
		||||
 | 
			
		||||
    lenlen = read_asn1_length(*data, *datalen, &len);
 | 
			
		||||
    if(lenlen < 0 || lenlen + len > *datalen) {
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    *data += lenlen;
 | 
			
		||||
    *datalen -= lenlen;
 | 
			
		||||
 | 
			
		||||
    *i = *data;
 | 
			
		||||
    *ilen = len;
 | 
			
		||||
 | 
			
		||||
    *data += len;
 | 
			
		||||
    *datalen -= len;
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| 
						 | 
				
			
			@ -0,0 +1,95 @@
 | 
			
		|||
#if defined(ESP32)
 | 
			
		||||
#ifndef __LIBSSH2_SESSION_H
 | 
			
		||||
#define __LIBSSH2_SESSION_H
 | 
			
		||||
/* Copyright (c) 2004-2007 Sara Golemon <sarag@libssh2.org>
 | 
			
		||||
 * Copyright (c) 2009-2010 by Daniel Stenberg
 | 
			
		||||
 * Copyright (c) 2010 Simon Josefsson <simon@josefsson.org>
 | 
			
		||||
 * All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Redistribution and use in source and binary forms,
 | 
			
		||||
 * with or without modification, are permitted provided
 | 
			
		||||
 * that the following conditions are met:
 | 
			
		||||
 *
 | 
			
		||||
 *   Redistributions of source code must retain the above
 | 
			
		||||
 *   copyright notice, this list of conditions and the
 | 
			
		||||
 *   following disclaimer.
 | 
			
		||||
 *
 | 
			
		||||
 *   Redistributions in binary form must reproduce the above
 | 
			
		||||
 *   copyright notice, this list of conditions and the following
 | 
			
		||||
 *   disclaimer in the documentation and/or other materials
 | 
			
		||||
 *   provided with the distribution.
 | 
			
		||||
 *
 | 
			
		||||
 *   Neither the name of the copyright holder nor the names
 | 
			
		||||
 *   of any other contributors may be used to endorse or
 | 
			
		||||
 *   promote products derived from this software without
 | 
			
		||||
 *   specific prior written permission.
 | 
			
		||||
 *
 | 
			
		||||
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
 | 
			
		||||
 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 | 
			
		||||
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 | 
			
		||||
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 | 
			
		||||
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 | 
			
		||||
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | 
			
		||||
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 | 
			
		||||
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 | 
			
		||||
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 | 
			
		||||
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 | 
			
		||||
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 | 
			
		||||
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
 | 
			
		||||
 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
 | 
			
		||||
 * OF SUCH DAMAGE.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/* Conveniance-macros to allow code like this;
 | 
			
		||||
 | 
			
		||||
   int rc = BLOCK_ADJUST(rc, session, session_startup(session, sock) );
 | 
			
		||||
 | 
			
		||||
   int rc = BLOCK_ADJUST_ERRNO(ptr, session, session_startup(session, sock) );
 | 
			
		||||
 | 
			
		||||
   The point of course being to make sure that while in non-blocking mode
 | 
			
		||||
   these always return no matter what the return code is, but in blocking mode
 | 
			
		||||
   it blocks if EAGAIN is the reason for the return from the underlying
 | 
			
		||||
   function.
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
#define BLOCK_ADJUST(rc, sess, x) \
 | 
			
		||||
    do { \
 | 
			
		||||
       time_t entry_time = time(NULL); \
 | 
			
		||||
       do { \
 | 
			
		||||
          rc = x; \
 | 
			
		||||
          /* the order of the check below is important to properly deal with \
 | 
			
		||||
             the case when the 'sess' is freed */ \
 | 
			
		||||
          if((rc != LIBSSH2_ERROR_EAGAIN) || !sess->api_block_mode) \
 | 
			
		||||
              break; \
 | 
			
		||||
          rc = _libssh2_wait_socket(sess, entry_time);  \
 | 
			
		||||
       } while(!rc);   \
 | 
			
		||||
    } while(0)
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * For functions that returns a pointer, we need to check if the API is
 | 
			
		||||
 * non-blocking and return immediately. If the pointer is non-NULL we return
 | 
			
		||||
 * immediately. If the API is blocking and we get a NULL we check the errno
 | 
			
		||||
 * and *only* if that is EAGAIN we loop and wait for socket action.
 | 
			
		||||
 */
 | 
			
		||||
#define BLOCK_ADJUST_ERRNO(ptr, sess, x) \
 | 
			
		||||
    do { \
 | 
			
		||||
       time_t entry_time = time(NULL); \
 | 
			
		||||
       int rc; \
 | 
			
		||||
       do { \
 | 
			
		||||
           ptr = x; \
 | 
			
		||||
           if(!sess->api_block_mode || \
 | 
			
		||||
              (ptr != NULL) || \
 | 
			
		||||
              (libssh2_session_last_errno(sess) != LIBSSH2_ERROR_EAGAIN) ) \
 | 
			
		||||
               break; \
 | 
			
		||||
           rc = _libssh2_wait_socket(sess, entry_time); \
 | 
			
		||||
        } while(!rc); \
 | 
			
		||||
    } while(0)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
int _libssh2_wait_socket(LIBSSH2_SESSION *session, time_t entry_time);
 | 
			
		||||
 | 
			
		||||
/* this is the lib-internal set blocking function */
 | 
			
		||||
int _libssh2_session_set_blocking(LIBSSH2_SESSION * session, int blocking);
 | 
			
		||||
 | 
			
		||||
#endif /* __LIBSSH2_SESSION_H */
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,240 @@
 | 
			
		|||
#if defined(ESP32)
 | 
			
		||||
#ifndef __LIBSSH2_SFTP_H
 | 
			
		||||
#define __LIBSSH2_SFTP_H
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (C) 2010 - 2012 by Daniel Stenberg
 | 
			
		||||
 * Author: Daniel Stenberg <daniel@haxx.se>
 | 
			
		||||
 *
 | 
			
		||||
 * Redistribution and use in source and binary forms,
 | 
			
		||||
 * with or without modification, are permitted provided
 | 
			
		||||
 * that the following conditions are met:
 | 
			
		||||
 *
 | 
			
		||||
 *   Redistributions of source code must retain the above
 | 
			
		||||
 *   copyright notice, this list of conditions and the
 | 
			
		||||
 *   following disclaimer.
 | 
			
		||||
 *
 | 
			
		||||
 *   Redistributions in binary form must reproduce the above
 | 
			
		||||
 *   copyright notice, this list of conditions and the following
 | 
			
		||||
 *   disclaimer in the documentation and/or other materials
 | 
			
		||||
 *   provided with the distribution.
 | 
			
		||||
 *
 | 
			
		||||
 *   Neither the name of the copyright holder nor the names
 | 
			
		||||
 *   of any other contributors may be used to endorse or
 | 
			
		||||
 *   promote products derived from this software without
 | 
			
		||||
 *   specific prior written permission.
 | 
			
		||||
 *
 | 
			
		||||
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
 | 
			
		||||
 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 | 
			
		||||
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 | 
			
		||||
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 | 
			
		||||
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 | 
			
		||||
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | 
			
		||||
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 | 
			
		||||
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 | 
			
		||||
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 | 
			
		||||
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 | 
			
		||||
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 | 
			
		||||
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
 | 
			
		||||
 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
 | 
			
		||||
 * OF SUCH DAMAGE.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * MAX_SFTP_OUTGOING_SIZE MUST not be larger than 32500 or so. This is the
 | 
			
		||||
 * amount of data sent in each FXP_WRITE packet
 | 
			
		||||
 */
 | 
			
		||||
#define MAX_SFTP_OUTGOING_SIZE 30000
 | 
			
		||||
 | 
			
		||||
/* MAX_SFTP_READ_SIZE is how much data is asked for at max in each FXP_READ
 | 
			
		||||
 * packets.
 | 
			
		||||
 */
 | 
			
		||||
#define MAX_SFTP_READ_SIZE 30000
 | 
			
		||||
 | 
			
		||||
struct sftp_pipeline_chunk {
 | 
			
		||||
    struct list_node node;
 | 
			
		||||
    libssh2_uint64_t offset; /* READ: offset at which to start reading
 | 
			
		||||
                                WRITE: not used */
 | 
			
		||||
    size_t len; /* WRITE: size of the data to write
 | 
			
		||||
                   READ: how many bytes that was asked for */
 | 
			
		||||
    size_t sent;
 | 
			
		||||
    ssize_t lefttosend; /* if 0, the entire packet has been sent off */
 | 
			
		||||
    uint32_t request_id;
 | 
			
		||||
    unsigned char packet[1]; /* data */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct sftp_zombie_requests {
 | 
			
		||||
    struct list_node node;
 | 
			
		||||
    uint32_t request_id;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#ifndef MIN
 | 
			
		||||
#define MIN(x,y) ((x)<(y)?(x):(y))
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
struct _LIBSSH2_SFTP_PACKET
 | 
			
		||||
{
 | 
			
		||||
    struct list_node node;   /* linked list header */
 | 
			
		||||
    uint32_t request_id;
 | 
			
		||||
    unsigned char *data;
 | 
			
		||||
    size_t data_len;              /* payload size */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
typedef struct _LIBSSH2_SFTP_PACKET LIBSSH2_SFTP_PACKET;
 | 
			
		||||
 | 
			
		||||
#define SFTP_HANDLE_MAXLEN 256 /* according to spec! */
 | 
			
		||||
 | 
			
		||||
struct _LIBSSH2_SFTP_HANDLE
 | 
			
		||||
{
 | 
			
		||||
    struct list_node node;
 | 
			
		||||
 | 
			
		||||
    LIBSSH2_SFTP *sftp;
 | 
			
		||||
 | 
			
		||||
    char handle[SFTP_HANDLE_MAXLEN];
 | 
			
		||||
    size_t handle_len;
 | 
			
		||||
 | 
			
		||||
    enum {
 | 
			
		||||
        LIBSSH2_SFTP_HANDLE_FILE,
 | 
			
		||||
        LIBSSH2_SFTP_HANDLE_DIR
 | 
			
		||||
    } handle_type;
 | 
			
		||||
 | 
			
		||||
    union _libssh2_sftp_handle_data
 | 
			
		||||
    {
 | 
			
		||||
        struct _libssh2_sftp_handle_file_data
 | 
			
		||||
        {
 | 
			
		||||
            libssh2_uint64_t offset;
 | 
			
		||||
            libssh2_uint64_t offset_sent;
 | 
			
		||||
            size_t acked; /* container for acked data that hasn't been
 | 
			
		||||
                             returned to caller yet, used for sftp_write */
 | 
			
		||||
 | 
			
		||||
            /* 'data' is used by sftp_read() and is allocated data that has
 | 
			
		||||
               been received already from the server but wasn't returned to
 | 
			
		||||
               the caller yet. It is of size 'data_len' and 'data_left is the
 | 
			
		||||
               number of bytes not yet returned, counted from the end of the
 | 
			
		||||
               buffer. */
 | 
			
		||||
            unsigned char *data;
 | 
			
		||||
            size_t data_len;
 | 
			
		||||
            size_t data_left;
 | 
			
		||||
 | 
			
		||||
            char eof; /* we have read to the end */
 | 
			
		||||
        } file;
 | 
			
		||||
        struct _libssh2_sftp_handle_dir_data
 | 
			
		||||
        {
 | 
			
		||||
            uint32_t names_left;
 | 
			
		||||
            void *names_packet;
 | 
			
		||||
            char *next_name;
 | 
			
		||||
            size_t names_packet_len;
 | 
			
		||||
        } dir;
 | 
			
		||||
    } u;
 | 
			
		||||
 | 
			
		||||
    /* State variables used in libssh2_sftp_close_handle() */
 | 
			
		||||
    libssh2_nonblocking_states close_state;
 | 
			
		||||
    uint32_t close_request_id;
 | 
			
		||||
    unsigned char *close_packet;
 | 
			
		||||
 | 
			
		||||
    /* list of outstanding packets sent to server */
 | 
			
		||||
    struct list_head packet_list;
 | 
			
		||||
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct _LIBSSH2_SFTP
 | 
			
		||||
{
 | 
			
		||||
    LIBSSH2_CHANNEL *channel;
 | 
			
		||||
 | 
			
		||||
    uint32_t request_id, version;
 | 
			
		||||
 | 
			
		||||
    struct list_head packets;
 | 
			
		||||
 | 
			
		||||
    /* List of FXP_READ responses to ignore because EOF already received. */
 | 
			
		||||
    struct list_head zombie_requests;
 | 
			
		||||
 | 
			
		||||
    /* a list of _LIBSSH2_SFTP_HANDLE structs */
 | 
			
		||||
    struct list_head sftp_handles;
 | 
			
		||||
 | 
			
		||||
    uint32_t last_errno;
 | 
			
		||||
 | 
			
		||||
    /* Holder for partial packet, use in libssh2_sftp_packet_read() */
 | 
			
		||||
    unsigned char partial_size[4];      /* buffer for size field   */
 | 
			
		||||
    size_t partial_size_len;            /* size field length       */
 | 
			
		||||
    unsigned char *partial_packet;      /* The data                */
 | 
			
		||||
    uint32_t partial_len;               /* Desired number of bytes */
 | 
			
		||||
    size_t partial_received;            /* Bytes received so far   */
 | 
			
		||||
 | 
			
		||||
    /* Time that libssh2_sftp_packet_requirev() started reading */
 | 
			
		||||
    time_t requirev_start;
 | 
			
		||||
 | 
			
		||||
    /* State variables used in libssh2_sftp_open_ex() */
 | 
			
		||||
    libssh2_nonblocking_states open_state;
 | 
			
		||||
    unsigned char *open_packet;
 | 
			
		||||
    uint32_t open_packet_len; /* 32 bit on the wire */
 | 
			
		||||
    size_t open_packet_sent;
 | 
			
		||||
    uint32_t open_request_id;
 | 
			
		||||
 | 
			
		||||
    /* State variable used in sftp_read() */
 | 
			
		||||
    libssh2_nonblocking_states read_state;
 | 
			
		||||
 | 
			
		||||
    /* State variable used in sftp_packet_read() */
 | 
			
		||||
    libssh2_nonblocking_states packet_state;
 | 
			
		||||
 | 
			
		||||
    /* State variable used in sftp_write() */
 | 
			
		||||
    libssh2_nonblocking_states write_state;
 | 
			
		||||
 | 
			
		||||
    /* State variables used in sftp_fsync() */
 | 
			
		||||
    libssh2_nonblocking_states fsync_state;
 | 
			
		||||
    unsigned char *fsync_packet;
 | 
			
		||||
    uint32_t fsync_request_id;
 | 
			
		||||
 | 
			
		||||
    /* State variables used in libssh2_sftp_readdir() */
 | 
			
		||||
    libssh2_nonblocking_states readdir_state;
 | 
			
		||||
    unsigned char *readdir_packet;
 | 
			
		||||
    uint32_t readdir_request_id;
 | 
			
		||||
 | 
			
		||||
    /* State variables used in libssh2_sftp_fstat_ex() */
 | 
			
		||||
    libssh2_nonblocking_states fstat_state;
 | 
			
		||||
    unsigned char *fstat_packet;
 | 
			
		||||
    uint32_t fstat_request_id;
 | 
			
		||||
 | 
			
		||||
    /* State variables used in libssh2_sftp_unlink_ex() */
 | 
			
		||||
    libssh2_nonblocking_states unlink_state;
 | 
			
		||||
    unsigned char *unlink_packet;
 | 
			
		||||
    uint32_t unlink_request_id;
 | 
			
		||||
 | 
			
		||||
    /* State variables used in libssh2_sftp_rename_ex() */
 | 
			
		||||
    libssh2_nonblocking_states rename_state;
 | 
			
		||||
    unsigned char *rename_packet;
 | 
			
		||||
    unsigned char *rename_s;
 | 
			
		||||
    uint32_t rename_request_id;
 | 
			
		||||
 | 
			
		||||
    /* State variables used in libssh2_sftp_fstatvfs() */
 | 
			
		||||
    libssh2_nonblocking_states fstatvfs_state;
 | 
			
		||||
    unsigned char *fstatvfs_packet;
 | 
			
		||||
    uint32_t fstatvfs_request_id;
 | 
			
		||||
 | 
			
		||||
    /* State variables used in libssh2_sftp_statvfs() */
 | 
			
		||||
    libssh2_nonblocking_states statvfs_state;
 | 
			
		||||
    unsigned char *statvfs_packet;
 | 
			
		||||
    uint32_t statvfs_request_id;
 | 
			
		||||
 | 
			
		||||
    /* State variables used in libssh2_sftp_mkdir() */
 | 
			
		||||
    libssh2_nonblocking_states mkdir_state;
 | 
			
		||||
    unsigned char *mkdir_packet;
 | 
			
		||||
    uint32_t mkdir_request_id;
 | 
			
		||||
 | 
			
		||||
    /* State variables used in libssh2_sftp_rmdir() */
 | 
			
		||||
    libssh2_nonblocking_states rmdir_state;
 | 
			
		||||
    unsigned char *rmdir_packet;
 | 
			
		||||
    uint32_t rmdir_request_id;
 | 
			
		||||
 | 
			
		||||
    /* State variables used in libssh2_sftp_stat() */
 | 
			
		||||
    libssh2_nonblocking_states stat_state;
 | 
			
		||||
    unsigned char *stat_packet;
 | 
			
		||||
    uint32_t stat_request_id;
 | 
			
		||||
 | 
			
		||||
    /* State variables used in libssh2_sftp_symlink() */
 | 
			
		||||
    libssh2_nonblocking_states symlink_state;
 | 
			
		||||
    unsigned char *symlink_packet;
 | 
			
		||||
    uint32_t symlink_request_id;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif /* __LIBSSH2_SFTP_H */
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,933 @@
 | 
			
		|||
#if defined(ESP32)
 | 
			
		||||
/* Copyright (C) 2007 The Written Word, Inc.  All rights reserved.
 | 
			
		||||
 * Copyright (C) 2009-2010 by Daniel Stenberg
 | 
			
		||||
 * Author: Daniel Stenberg <daniel@haxx.se>
 | 
			
		||||
 *
 | 
			
		||||
 * Redistribution and use in source and binary forms,
 | 
			
		||||
 * with or without modification, are permitted provided
 | 
			
		||||
 * that the following conditions are met:
 | 
			
		||||
 *
 | 
			
		||||
 *   Redistributions of source code must retain the above
 | 
			
		||||
 *   copyright notice, this list of conditions and the
 | 
			
		||||
 *   following disclaimer.
 | 
			
		||||
 *
 | 
			
		||||
 *   Redistributions in binary form must reproduce the above
 | 
			
		||||
 *   copyright notice, this list of conditions and the following
 | 
			
		||||
 *   disclaimer in the documentation and/or other materials
 | 
			
		||||
 *   provided with the distribution.
 | 
			
		||||
 *
 | 
			
		||||
 *   Neither the name of the copyright holder nor the names
 | 
			
		||||
 *   of any other contributors may be used to endorse or
 | 
			
		||||
 *   promote products derived from this software without
 | 
			
		||||
 *   specific prior written permission.
 | 
			
		||||
 *
 | 
			
		||||
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
 | 
			
		||||
 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 | 
			
		||||
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 | 
			
		||||
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 | 
			
		||||
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 | 
			
		||||
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | 
			
		||||
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 | 
			
		||||
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 | 
			
		||||
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 | 
			
		||||
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 | 
			
		||||
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 | 
			
		||||
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
 | 
			
		||||
 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
 | 
			
		||||
 * OF SUCH DAMAGE.
 | 
			
		||||
 *
 | 
			
		||||
 * This file handles reading and writing to the SECSH transport layer. RFC4253.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "libssh2_priv.h"
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
#include <ctype.h>
 | 
			
		||||
#ifdef LIBSSH2DEBUG
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include <assert.h>
 | 
			
		||||
 | 
			
		||||
#include "transport.h"
 | 
			
		||||
#include "mac.h"
 | 
			
		||||
 | 
			
		||||
#define MAX_BLOCKSIZE 32    /* MUST fit biggest crypto block size we use/get */
 | 
			
		||||
#define MAX_MACSIZE 64      /* MUST fit biggest MAC length we support */
 | 
			
		||||
 | 
			
		||||
#ifdef LIBSSH2DEBUG
 | 
			
		||||
#define UNPRINTABLE_CHAR '.'
 | 
			
		||||
static void
 | 
			
		||||
debugdump(LIBSSH2_SESSION * session,
 | 
			
		||||
          const char *desc, const unsigned char *ptr, size_t size)
 | 
			
		||||
{
 | 
			
		||||
    size_t i;
 | 
			
		||||
    size_t c;
 | 
			
		||||
    unsigned int width = 0x10;
 | 
			
		||||
    char buffer[256];  /* Must be enough for width*4 + about 30 or so */
 | 
			
		||||
    size_t used;
 | 
			
		||||
    static const char *hex_chars = "0123456789ABCDEF";
 | 
			
		||||
 | 
			
		||||
    if(!(session->showmask & LIBSSH2_TRACE_TRANS)) {
 | 
			
		||||
        /* not asked for, bail out */
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    used = snprintf(buffer, sizeof(buffer), "=> %s (%d bytes)\n",
 | 
			
		||||
                    desc, (int) size);
 | 
			
		||||
    if(session->tracehandler)
 | 
			
		||||
        (session->tracehandler)(session, session->tracehandler_context,
 | 
			
		||||
                                buffer, used);
 | 
			
		||||
    else
 | 
			
		||||
        fprintf(stderr, "%s", buffer);
 | 
			
		||||
 | 
			
		||||
    for(i = 0; i < size; i += width) {
 | 
			
		||||
 | 
			
		||||
        used = snprintf(buffer, sizeof(buffer), "%04lx: ", (long)i);
 | 
			
		||||
 | 
			
		||||
        /* hex not disabled, show it */
 | 
			
		||||
        for(c = 0; c < width; c++) {
 | 
			
		||||
            if(i + c < size) {
 | 
			
		||||
                buffer[used++] = hex_chars[(ptr[i + c] >> 4) & 0xF];
 | 
			
		||||
                buffer[used++] = hex_chars[ptr[i + c] & 0xF];
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
                buffer[used++] = ' ';
 | 
			
		||||
                buffer[used++] = ' ';
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            buffer[used++] = ' ';
 | 
			
		||||
            if((width/2) - 1 == c)
 | 
			
		||||
                buffer[used++] = ' ';
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        buffer[used++] = ':';
 | 
			
		||||
        buffer[used++] = ' ';
 | 
			
		||||
 | 
			
		||||
        for(c = 0; (c < width) && (i + c < size); c++) {
 | 
			
		||||
            buffer[used++] = isprint(ptr[i + c]) ?
 | 
			
		||||
                ptr[i + c] : UNPRINTABLE_CHAR;
 | 
			
		||||
        }
 | 
			
		||||
        buffer[used++] = '\n';
 | 
			
		||||
        buffer[used] = 0;
 | 
			
		||||
 | 
			
		||||
        if(session->tracehandler)
 | 
			
		||||
            (session->tracehandler)(session, session->tracehandler_context,
 | 
			
		||||
                                    buffer, used);
 | 
			
		||||
        else
 | 
			
		||||
            fprintf(stderr, "%s", buffer);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
#else
 | 
			
		||||
#define debugdump(a,x,y,z) do {} while(0)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* decrypt() decrypts 'len' bytes from 'source' to 'dest' in units of
 | 
			
		||||
 * blocksize.
 | 
			
		||||
 *
 | 
			
		||||
 * returns 0 on success and negative on failure
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
decrypt(LIBSSH2_SESSION * session, unsigned char *source,
 | 
			
		||||
        unsigned char *dest, int len)
 | 
			
		||||
{
 | 
			
		||||
    struct transportpacket *p = &session->packet;
 | 
			
		||||
    int blocksize = session->remote.crypt->blocksize;
 | 
			
		||||
 | 
			
		||||
    /* if we get called with a len that isn't an even number of blocksizes
 | 
			
		||||
       we risk losing those extra bytes */
 | 
			
		||||
    assert((len % blocksize) == 0);
 | 
			
		||||
 | 
			
		||||
    while(len >= blocksize) {
 | 
			
		||||
        if(session->remote.crypt->crypt(session, source, blocksize,
 | 
			
		||||
                                         &session->remote.crypt_abstract)) {
 | 
			
		||||
            LIBSSH2_FREE(session, p->payload);
 | 
			
		||||
            return LIBSSH2_ERROR_DECRYPT;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /* if the crypt() function would write to a given address it
 | 
			
		||||
           wouldn't have to memcpy() and we could avoid this memcpy()
 | 
			
		||||
           too */
 | 
			
		||||
        memcpy(dest, source, blocksize);
 | 
			
		||||
 | 
			
		||||
        len -= blocksize;       /* less bytes left */
 | 
			
		||||
        dest += blocksize;      /* advance write pointer */
 | 
			
		||||
        source += blocksize;    /* advance read pointer */
 | 
			
		||||
    }
 | 
			
		||||
    return LIBSSH2_ERROR_NONE;         /* all is fine */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * fullpacket() gets called when a full packet has been received and properly
 | 
			
		||||
 * collected.
 | 
			
		||||
 */
 | 
			
		||||
static int
 | 
			
		||||
fullpacket(LIBSSH2_SESSION * session, int encrypted /* 1 or 0 */ )
 | 
			
		||||
{
 | 
			
		||||
    unsigned char macbuf[MAX_MACSIZE];
 | 
			
		||||
    struct transportpacket *p = &session->packet;
 | 
			
		||||
    int rc;
 | 
			
		||||
    int compressed;
 | 
			
		||||
 | 
			
		||||
    if(session->fullpacket_state == libssh2_NB_state_idle) {
 | 
			
		||||
        session->fullpacket_macstate = LIBSSH2_MAC_CONFIRMED;
 | 
			
		||||
        session->fullpacket_payload_len = p->packet_length - 1;
 | 
			
		||||
 | 
			
		||||
        if(encrypted) {
 | 
			
		||||
 | 
			
		||||
            /* Calculate MAC hash */
 | 
			
		||||
            session->remote.mac->hash(session, macbuf,  /* store hash here */
 | 
			
		||||
                                      session->remote.seqno,
 | 
			
		||||
                                      p->init, 5,
 | 
			
		||||
                                      p->payload,
 | 
			
		||||
                                      session->fullpacket_payload_len,
 | 
			
		||||
                                      &session->remote.mac_abstract);
 | 
			
		||||
 | 
			
		||||
            /* Compare the calculated hash with the MAC we just read from
 | 
			
		||||
             * the network. The read one is at the very end of the payload
 | 
			
		||||
             * buffer. Note that 'payload_len' here is the packet_length
 | 
			
		||||
             * field which includes the padding but not the MAC.
 | 
			
		||||
             */
 | 
			
		||||
            if(memcmp(macbuf, p->payload + session->fullpacket_payload_len,
 | 
			
		||||
                       session->remote.mac->mac_len)) {
 | 
			
		||||
                session->fullpacket_macstate = LIBSSH2_MAC_INVALID;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        session->remote.seqno++;
 | 
			
		||||
 | 
			
		||||
        /* ignore the padding */
 | 
			
		||||
        session->fullpacket_payload_len -= p->padding_length;
 | 
			
		||||
 | 
			
		||||
        /* Check for and deal with decompression */
 | 
			
		||||
        compressed =
 | 
			
		||||
            session->local.comp != NULL &&
 | 
			
		||||
            session->local.comp->compress &&
 | 
			
		||||
            ((session->state & LIBSSH2_STATE_AUTHENTICATED) ||
 | 
			
		||||
             session->local.comp->use_in_auth);
 | 
			
		||||
 | 
			
		||||
        if(compressed && session->remote.comp_abstract) {
 | 
			
		||||
            /*
 | 
			
		||||
             * The buffer for the decompression (remote.comp_abstract) is
 | 
			
		||||
             * initialised in time when it is needed so as long it is NULL we
 | 
			
		||||
             * cannot decompress.
 | 
			
		||||
             */
 | 
			
		||||
 | 
			
		||||
            unsigned char *data;
 | 
			
		||||
            size_t data_len;
 | 
			
		||||
            rc = session->remote.comp->decomp(session,
 | 
			
		||||
                                              &data, &data_len,
 | 
			
		||||
                                              LIBSSH2_PACKET_MAXDECOMP,
 | 
			
		||||
                                              p->payload,
 | 
			
		||||
                                              session->fullpacket_payload_len,
 | 
			
		||||
                                              &session->remote.comp_abstract);
 | 
			
		||||
            LIBSSH2_FREE(session, p->payload);
 | 
			
		||||
            if(rc)
 | 
			
		||||
                return rc;
 | 
			
		||||
 | 
			
		||||
            p->payload = data;
 | 
			
		||||
            session->fullpacket_payload_len = data_len;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        session->fullpacket_packet_type = p->payload[0];
 | 
			
		||||
 | 
			
		||||
        debugdump(session, "libssh2_transport_read() plain",
 | 
			
		||||
                  p->payload, session->fullpacket_payload_len);
 | 
			
		||||
 | 
			
		||||
        session->fullpacket_state = libssh2_NB_state_created;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if(session->fullpacket_state == libssh2_NB_state_created) {
 | 
			
		||||
        rc = _libssh2_packet_add(session, p->payload,
 | 
			
		||||
                                 session->fullpacket_payload_len,
 | 
			
		||||
                                 session->fullpacket_macstate);
 | 
			
		||||
        if(rc == LIBSSH2_ERROR_EAGAIN)
 | 
			
		||||
            return rc;
 | 
			
		||||
        if(rc) {
 | 
			
		||||
            session->fullpacket_state = libssh2_NB_state_idle;
 | 
			
		||||
            return rc;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    session->fullpacket_state = libssh2_NB_state_idle;
 | 
			
		||||
 | 
			
		||||
    return session->fullpacket_packet_type;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * _libssh2_transport_read
 | 
			
		||||
 *
 | 
			
		||||
 * Collect a packet into the input queue.
 | 
			
		||||
 *
 | 
			
		||||
 * Returns packet type added to input queue (0 if nothing added), or a
 | 
			
		||||
 * negative error number.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * This function reads the binary stream as specified in chapter 6 of RFC4253
 | 
			
		||||
 * "The Secure Shell (SSH) Transport Layer Protocol"
 | 
			
		||||
 *
 | 
			
		||||
 * DOES NOT call _libssh2_error() for ANY error case.
 | 
			
		||||
 */
 | 
			
		||||
int _libssh2_transport_read(LIBSSH2_SESSION * session)
 | 
			
		||||
{
 | 
			
		||||
    int rc;
 | 
			
		||||
    struct transportpacket *p = &session->packet;
 | 
			
		||||
    int remainpack; /* how much there is left to add to the current payload
 | 
			
		||||
                       package */
 | 
			
		||||
    int remainbuf;  /* how much data there is remaining in the buffer to deal
 | 
			
		||||
                       with before we should read more from the network */
 | 
			
		||||
    int numbytes;   /* how much data to deal with from the buffer on this
 | 
			
		||||
                       iteration through the loop */
 | 
			
		||||
    int numdecrypt; /* number of bytes to decrypt this iteration */
 | 
			
		||||
    unsigned char block[MAX_BLOCKSIZE]; /* working block buffer */
 | 
			
		||||
    int blocksize;  /* minimum number of bytes we need before we can
 | 
			
		||||
                       use them */
 | 
			
		||||
    int encrypted = 1; /* whether the packet is encrypted or not */
 | 
			
		||||
 | 
			
		||||
    /* default clear the bit */
 | 
			
		||||
    session->socket_block_directions &= ~LIBSSH2_SESSION_BLOCK_INBOUND;
 | 
			
		||||
 | 
			
		||||
    /*
 | 
			
		||||
     * All channels, systems, subsystems, etc eventually make it down here
 | 
			
		||||
     * when looking for more incoming data. If a key exchange is going on
 | 
			
		||||
     * (LIBSSH2_STATE_EXCHANGING_KEYS bit is set) then the remote end will
 | 
			
		||||
     * ONLY send key exchange related traffic. In non-blocking mode, there is
 | 
			
		||||
     * a chance to break out of the kex_exchange function with an EAGAIN
 | 
			
		||||
     * status, and never come back to it. If LIBSSH2_STATE_EXCHANGING_KEYS is
 | 
			
		||||
     * active, then we must redirect to the key exchange. However, if
 | 
			
		||||
     * kex_exchange is active (as in it is the one that calls this execution
 | 
			
		||||
     * of packet_read, then don't redirect, as that would be an infinite loop!
 | 
			
		||||
     */
 | 
			
		||||
 | 
			
		||||
    if(session->state & LIBSSH2_STATE_EXCHANGING_KEYS &&
 | 
			
		||||
        !(session->state & LIBSSH2_STATE_KEX_ACTIVE)) {
 | 
			
		||||
 | 
			
		||||
        /* Whoever wants a packet won't get anything until the key re-exchange
 | 
			
		||||
         * is done!
 | 
			
		||||
         */
 | 
			
		||||
        _libssh2_debug(session, LIBSSH2_TRACE_TRANS, "Redirecting into the"
 | 
			
		||||
                       " key re-exchange from _libssh2_transport_read");
 | 
			
		||||
        rc = _libssh2_kex_exchange(session, 1, &session->startup_key_state);
 | 
			
		||||
        if(rc)
 | 
			
		||||
            return rc;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /*
 | 
			
		||||
     * =============================== NOTE ===============================
 | 
			
		||||
     * I know this is very ugly and not a really good use of "goto", but
 | 
			
		||||
     * this case statement would be even uglier to do it any other way
 | 
			
		||||
     */
 | 
			
		||||
    if(session->readPack_state == libssh2_NB_state_jump1) {
 | 
			
		||||
        session->readPack_state = libssh2_NB_state_idle;
 | 
			
		||||
        encrypted = session->readPack_encrypted;
 | 
			
		||||
        goto libssh2_transport_read_point1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    do {
 | 
			
		||||
        if(session->socket_state == LIBSSH2_SOCKET_DISCONNECTED) {
 | 
			
		||||
            return LIBSSH2_ERROR_SOCKET_DISCONNECT;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if(session->state & LIBSSH2_STATE_NEWKEYS) {
 | 
			
		||||
            blocksize = session->remote.crypt->blocksize;
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            encrypted = 0;      /* not encrypted */
 | 
			
		||||
            blocksize = 5;      /* not strictly true, but we can use 5 here to
 | 
			
		||||
                                   make the checks below work fine still */
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /* read/use a whole big chunk into a temporary area stored in
 | 
			
		||||
           the LIBSSH2_SESSION struct. We will decrypt data from that
 | 
			
		||||
           buffer into the packet buffer so this temp one doesn't have
 | 
			
		||||
           to be able to keep a whole SSH packet, just be large enough
 | 
			
		||||
           so that we can read big chunks from the network layer. */
 | 
			
		||||
 | 
			
		||||
        /* how much data there is remaining in the buffer to deal with
 | 
			
		||||
           before we should read more from the network */
 | 
			
		||||
        remainbuf = p->writeidx - p->readidx;
 | 
			
		||||
 | 
			
		||||
        /* if remainbuf turns negative we have a bad internal error */
 | 
			
		||||
        assert(remainbuf >= 0);
 | 
			
		||||
 | 
			
		||||
        if(remainbuf < blocksize) {
 | 
			
		||||
            /* If we have less than a blocksize left, it is too
 | 
			
		||||
               little data to deal with, read more */
 | 
			
		||||
            ssize_t nread;
 | 
			
		||||
 | 
			
		||||
            /* move any remainder to the start of the buffer so
 | 
			
		||||
               that we can do a full refill */
 | 
			
		||||
            if(remainbuf) {
 | 
			
		||||
                memmove(p->buf, &p->buf[p->readidx], remainbuf);
 | 
			
		||||
                p->readidx = 0;
 | 
			
		||||
                p->writeidx = remainbuf;
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
                /* nothing to move, just zero the indexes */
 | 
			
		||||
                p->readidx = p->writeidx = 0;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            /* now read a big chunk from the network into the temp buffer */
 | 
			
		||||
            nread =
 | 
			
		||||
                LIBSSH2_RECV(session, &p->buf[remainbuf],
 | 
			
		||||
                              PACKETBUFSIZE - remainbuf,
 | 
			
		||||
                              LIBSSH2_SOCKET_RECV_FLAGS(session));
 | 
			
		||||
            if(nread <= 0) {
 | 
			
		||||
                /* check if this is due to EAGAIN and return the special
 | 
			
		||||
                   return code if so, error out normally otherwise */
 | 
			
		||||
                if((nread < 0) && (nread == -EAGAIN)) {
 | 
			
		||||
                    session->socket_block_directions |=
 | 
			
		||||
                        LIBSSH2_SESSION_BLOCK_INBOUND;
 | 
			
		||||
                    return LIBSSH2_ERROR_EAGAIN;
 | 
			
		||||
                }
 | 
			
		||||
                _libssh2_debug(session, LIBSSH2_TRACE_SOCKET,
 | 
			
		||||
                               "Error recving %d bytes (got %d)",
 | 
			
		||||
                               PACKETBUFSIZE - remainbuf, -nread);
 | 
			
		||||
                return LIBSSH2_ERROR_SOCKET_RECV;
 | 
			
		||||
            }
 | 
			
		||||
            _libssh2_debug(session, LIBSSH2_TRACE_SOCKET,
 | 
			
		||||
                           "Recved %d/%d bytes to %p+%d", nread,
 | 
			
		||||
                           PACKETBUFSIZE - remainbuf, p->buf, remainbuf);
 | 
			
		||||
 | 
			
		||||
            debugdump(session, "libssh2_transport_read() raw",
 | 
			
		||||
                      &p->buf[remainbuf], nread);
 | 
			
		||||
            /* advance write pointer */
 | 
			
		||||
            p->writeidx += nread;
 | 
			
		||||
 | 
			
		||||
            /* update remainbuf counter */
 | 
			
		||||
            remainbuf = p->writeidx - p->readidx;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /* how much data to deal with from the buffer */
 | 
			
		||||
        numbytes = remainbuf;
 | 
			
		||||
 | 
			
		||||
        if(!p->total_num) {
 | 
			
		||||
            size_t total_num; /* the number of bytes following the initial
 | 
			
		||||
                                 (5 bytes) packet length and padding length
 | 
			
		||||
                                 fields */
 | 
			
		||||
 | 
			
		||||
            /* No payload package area allocated yet. To know the
 | 
			
		||||
               size of this payload, we need to decrypt the first
 | 
			
		||||
               blocksize data. */
 | 
			
		||||
 | 
			
		||||
            if(numbytes < blocksize) {
 | 
			
		||||
                /* we can't act on anything less than blocksize, but this
 | 
			
		||||
                   check is only done for the initial block since once we have
 | 
			
		||||
                   got the start of a block we can in fact deal with fractions
 | 
			
		||||
                */
 | 
			
		||||
                session->socket_block_directions |=
 | 
			
		||||
                    LIBSSH2_SESSION_BLOCK_INBOUND;
 | 
			
		||||
                return LIBSSH2_ERROR_EAGAIN;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if(encrypted) {
 | 
			
		||||
                rc = decrypt(session, &p->buf[p->readidx], block, blocksize);
 | 
			
		||||
                if(rc != LIBSSH2_ERROR_NONE) {
 | 
			
		||||
                    return rc;
 | 
			
		||||
                }
 | 
			
		||||
                /* save the first 5 bytes of the decrypted package, to be
 | 
			
		||||
                   used in the hash calculation later down. */
 | 
			
		||||
                memcpy(p->init, block, 5);
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
                /* the data is plain, just copy it verbatim to
 | 
			
		||||
                   the working block buffer */
 | 
			
		||||
                memcpy(block, &p->buf[p->readidx], blocksize);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            /* advance the read pointer */
 | 
			
		||||
            p->readidx += blocksize;
 | 
			
		||||
 | 
			
		||||
            /* we now have the initial blocksize bytes decrypted,
 | 
			
		||||
             * and we can extract packet and padding length from it
 | 
			
		||||
             */
 | 
			
		||||
            p->packet_length = _libssh2_ntohu32(block);
 | 
			
		||||
            if(p->packet_length < 1) {
 | 
			
		||||
                return LIBSSH2_ERROR_DECRYPT;
 | 
			
		||||
            }
 | 
			
		||||
            else if(p->packet_length > LIBSSH2_PACKET_MAXPAYLOAD) {
 | 
			
		||||
                return LIBSSH2_ERROR_OUT_OF_BOUNDARY;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            p->padding_length = block[4];
 | 
			
		||||
            if(p->padding_length > p->packet_length - 1) {
 | 
			
		||||
                return LIBSSH2_ERROR_DECRYPT;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            /* total_num is the number of bytes following the initial
 | 
			
		||||
               (5 bytes) packet length and padding length fields */
 | 
			
		||||
            total_num =
 | 
			
		||||
                p->packet_length - 1 +
 | 
			
		||||
                (encrypted ? session->remote.mac->mac_len : 0);
 | 
			
		||||
 | 
			
		||||
            /* RFC4253 section 6.1 Maximum Packet Length says:
 | 
			
		||||
             *
 | 
			
		||||
             * "All implementations MUST be able to process
 | 
			
		||||
             * packets with uncompressed payload length of 32768
 | 
			
		||||
             * bytes or less and total packet size of 35000 bytes
 | 
			
		||||
             * or less (including length, padding length, payload,
 | 
			
		||||
             * padding, and MAC.)."
 | 
			
		||||
             */
 | 
			
		||||
            if(total_num > LIBSSH2_PACKET_MAXPAYLOAD || total_num == 0) {
 | 
			
		||||
                return LIBSSH2_ERROR_OUT_OF_BOUNDARY;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            /* Get a packet handle put data into. We get one to
 | 
			
		||||
               hold all data, including padding and MAC. */
 | 
			
		||||
            p->payload = LIBSSH2_ALLOC(session, total_num);
 | 
			
		||||
            if(!p->payload) {
 | 
			
		||||
                return LIBSSH2_ERROR_ALLOC;
 | 
			
		||||
            }
 | 
			
		||||
            p->total_num = total_num;
 | 
			
		||||
            /* init write pointer to start of payload buffer */
 | 
			
		||||
            p->wptr = p->payload;
 | 
			
		||||
 | 
			
		||||
            if(blocksize > 5) {
 | 
			
		||||
                /* copy the data from index 5 to the end of
 | 
			
		||||
                   the blocksize from the temporary buffer to
 | 
			
		||||
                   the start of the decrypted buffer */
 | 
			
		||||
                if(blocksize - 5 <= (int) total_num) {
 | 
			
		||||
                    memcpy(p->wptr, &block[5], blocksize - 5);
 | 
			
		||||
                    p->wptr += blocksize - 5;       /* advance write pointer */
 | 
			
		||||
                }
 | 
			
		||||
                else {
 | 
			
		||||
                    if(p->payload)
 | 
			
		||||
                        LIBSSH2_FREE(session, p->payload);
 | 
			
		||||
                    return LIBSSH2_ERROR_OUT_OF_BOUNDARY;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            /* init the data_num field to the number of bytes of
 | 
			
		||||
               the package read so far */
 | 
			
		||||
            p->data_num = p->wptr - p->payload;
 | 
			
		||||
 | 
			
		||||
            /* we already dealt with a blocksize worth of data */
 | 
			
		||||
            numbytes -= blocksize;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /* how much there is left to add to the current payload
 | 
			
		||||
           package */
 | 
			
		||||
        remainpack = p->total_num - p->data_num;
 | 
			
		||||
 | 
			
		||||
        if(numbytes > remainpack) {
 | 
			
		||||
            /* if we have more data in the buffer than what is going into this
 | 
			
		||||
               particular packet, we limit this round to this packet only */
 | 
			
		||||
            numbytes = remainpack;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if(encrypted) {
 | 
			
		||||
            /* At the end of the incoming stream, there is a MAC,
 | 
			
		||||
               and we don't want to decrypt that since we need it
 | 
			
		||||
               "raw". We MUST however decrypt the padding data
 | 
			
		||||
               since it is used for the hash later on. */
 | 
			
		||||
            int skip = session->remote.mac->mac_len;
 | 
			
		||||
 | 
			
		||||
            /* if what we have plus numbytes is bigger than the
 | 
			
		||||
               total minus the skip margin, we should lower the
 | 
			
		||||
               amount to decrypt even more */
 | 
			
		||||
            if((p->data_num + numbytes) > (p->total_num - skip)) {
 | 
			
		||||
                numdecrypt = (p->total_num - skip) - p->data_num;
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
                int frac;
 | 
			
		||||
                numdecrypt = numbytes;
 | 
			
		||||
                frac = numdecrypt % blocksize;
 | 
			
		||||
                if(frac) {
 | 
			
		||||
                    /* not an aligned amount of blocks,
 | 
			
		||||
                       align it */
 | 
			
		||||
                    numdecrypt -= frac;
 | 
			
		||||
                    /* and make it no unencrypted data
 | 
			
		||||
                       after it */
 | 
			
		||||
                    numbytes = 0;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            /* unencrypted data should not be decrypted at all */
 | 
			
		||||
            numdecrypt = 0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /* if there are bytes to decrypt, do that */
 | 
			
		||||
        if(numdecrypt > 0) {
 | 
			
		||||
            /* now decrypt the lot */
 | 
			
		||||
            rc = decrypt(session, &p->buf[p->readidx], p->wptr, numdecrypt);
 | 
			
		||||
            if(rc != LIBSSH2_ERROR_NONE) {
 | 
			
		||||
                p->total_num = 0;   /* no packet buffer available */
 | 
			
		||||
                return rc;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            /* advance the read pointer */
 | 
			
		||||
            p->readidx += numdecrypt;
 | 
			
		||||
            /* advance write pointer */
 | 
			
		||||
            p->wptr += numdecrypt;
 | 
			
		||||
            /* increase data_num */
 | 
			
		||||
            p->data_num += numdecrypt;
 | 
			
		||||
 | 
			
		||||
            /* bytes left to take care of without decryption */
 | 
			
		||||
            numbytes -= numdecrypt;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /* if there are bytes to copy that aren't decrypted, simply
 | 
			
		||||
           copy them as-is to the target buffer */
 | 
			
		||||
        if(numbytes > 0) {
 | 
			
		||||
 | 
			
		||||
            if(numbytes <= (int)(p->total_num - (p->wptr - p->payload))) {
 | 
			
		||||
                memcpy(p->wptr, &p->buf[p->readidx], numbytes);
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
                if(p->payload)
 | 
			
		||||
                    LIBSSH2_FREE(session, p->payload);
 | 
			
		||||
                return LIBSSH2_ERROR_OUT_OF_BOUNDARY;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            /* advance the read pointer */
 | 
			
		||||
            p->readidx += numbytes;
 | 
			
		||||
            /* advance write pointer */
 | 
			
		||||
            p->wptr += numbytes;
 | 
			
		||||
            /* increase data_num */
 | 
			
		||||
            p->data_num += numbytes;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /* now check how much data there's left to read to finish the
 | 
			
		||||
           current packet */
 | 
			
		||||
        remainpack = p->total_num - p->data_num;
 | 
			
		||||
 | 
			
		||||
        if(!remainpack) {
 | 
			
		||||
            /* we have a full packet */
 | 
			
		||||
          libssh2_transport_read_point1:
 | 
			
		||||
            rc = fullpacket(session, encrypted);
 | 
			
		||||
            if(rc == LIBSSH2_ERROR_EAGAIN) {
 | 
			
		||||
 | 
			
		||||
                if(session->packAdd_state != libssh2_NB_state_idle) {
 | 
			
		||||
                    /* fullpacket only returns LIBSSH2_ERROR_EAGAIN if
 | 
			
		||||
                     * libssh2_packet_add returns LIBSSH2_ERROR_EAGAIN. If
 | 
			
		||||
                     * that returns LIBSSH2_ERROR_EAGAIN but the packAdd_state
 | 
			
		||||
                     * is idle, then the packet has been added to the brigade,
 | 
			
		||||
                     * but some immediate action that was taken based on the
 | 
			
		||||
                     * packet type (such as key re-exchange) is not yet
 | 
			
		||||
                     * complete.  Clear the way for a new packet to be read
 | 
			
		||||
                     * in.
 | 
			
		||||
                     */
 | 
			
		||||
                    session->readPack_encrypted = encrypted;
 | 
			
		||||
                    session->readPack_state = libssh2_NB_state_jump1;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                return rc;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            p->total_num = 0;   /* no packet buffer available */
 | 
			
		||||
 | 
			
		||||
            return rc;
 | 
			
		||||
        }
 | 
			
		||||
    } while(1);                /* loop */
 | 
			
		||||
 | 
			
		||||
    return LIBSSH2_ERROR_SOCKET_RECV; /* we never reach this point */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
send_existing(LIBSSH2_SESSION *session, const unsigned char *data,
 | 
			
		||||
              size_t data_len, ssize_t *ret)
 | 
			
		||||
{
 | 
			
		||||
    ssize_t rc;
 | 
			
		||||
    ssize_t length;
 | 
			
		||||
    struct transportpacket *p = &session->packet;
 | 
			
		||||
 | 
			
		||||
    if(!p->olen) {
 | 
			
		||||
        *ret = 0;
 | 
			
		||||
        return LIBSSH2_ERROR_NONE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* send as much as possible of the existing packet */
 | 
			
		||||
    if((data != p->odata) || (data_len != p->olen)) {
 | 
			
		||||
        /* When we are about to complete the sending of a packet, it is vital
 | 
			
		||||
           that the caller doesn't try to send a new/different packet since
 | 
			
		||||
           we don't add this one up until the previous one has been sent. To
 | 
			
		||||
           make the caller really notice his/hers flaw, we return error for
 | 
			
		||||
           this case */
 | 
			
		||||
        return LIBSSH2_ERROR_BAD_USE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    *ret = 1;                   /* set to make our parent return */
 | 
			
		||||
 | 
			
		||||
    /* number of bytes left to send */
 | 
			
		||||
    length = p->ototal_num - p->osent;
 | 
			
		||||
 | 
			
		||||
    rc = LIBSSH2_SEND(session, &p->outbuf[p->osent], length,
 | 
			
		||||
                       LIBSSH2_SOCKET_SEND_FLAGS(session));
 | 
			
		||||
    if(rc < 0)
 | 
			
		||||
        _libssh2_debug(session, LIBSSH2_TRACE_SOCKET,
 | 
			
		||||
                       "Error sending %d bytes: %d", length, -rc);
 | 
			
		||||
    else {
 | 
			
		||||
        _libssh2_debug(session, LIBSSH2_TRACE_SOCKET,
 | 
			
		||||
                       "Sent %d/%d bytes at %p+%d", rc, length, p->outbuf,
 | 
			
		||||
                       p->osent);
 | 
			
		||||
        debugdump(session, "libssh2_transport_write send()",
 | 
			
		||||
                  &p->outbuf[p->osent], rc);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if(rc == length) {
 | 
			
		||||
        /* the remainder of the package was sent */
 | 
			
		||||
        p->ototal_num = 0;
 | 
			
		||||
        p->olen = 0;
 | 
			
		||||
        /* we leave *ret set so that the parent returns as we MUST return back
 | 
			
		||||
           a send success now, so that we don't risk sending EAGAIN later
 | 
			
		||||
           which then would confuse the parent function */
 | 
			
		||||
        return LIBSSH2_ERROR_NONE;
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
    else if(rc < 0) {
 | 
			
		||||
        /* nothing was sent */
 | 
			
		||||
        if(rc != -EAGAIN)
 | 
			
		||||
            /* send failure! */
 | 
			
		||||
            return LIBSSH2_ERROR_SOCKET_SEND;
 | 
			
		||||
 | 
			
		||||
        session->socket_block_directions |= LIBSSH2_SESSION_BLOCK_OUTBOUND;
 | 
			
		||||
        return LIBSSH2_ERROR_EAGAIN;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    p->osent += rc;         /* we sent away this much data */
 | 
			
		||||
 | 
			
		||||
    return rc < length ? LIBSSH2_ERROR_EAGAIN : LIBSSH2_ERROR_NONE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * libssh2_transport_send
 | 
			
		||||
 *
 | 
			
		||||
 * Send a packet, encrypting it and adding a MAC code if necessary
 | 
			
		||||
 * Returns 0 on success, non-zero on failure.
 | 
			
		||||
 *
 | 
			
		||||
 * The data is provided as _two_ data areas that are combined by this
 | 
			
		||||
 * function.  The 'data' part is sent immediately before 'data2'. 'data2' may
 | 
			
		||||
 * be set to NULL to only use a single part.
 | 
			
		||||
 *
 | 
			
		||||
 * Returns LIBSSH2_ERROR_EAGAIN if it would block or if the whole packet was
 | 
			
		||||
 * not sent yet. If it does so, the caller should call this function again as
 | 
			
		||||
 * soon as it is likely that more data can be sent, and this function MUST
 | 
			
		||||
 * then be called with the same argument set (same data pointer and same
 | 
			
		||||
 * data_len) until ERROR_NONE or failure is returned.
 | 
			
		||||
 *
 | 
			
		||||
 * This function DOES NOT call _libssh2_error() on any errors.
 | 
			
		||||
 */
 | 
			
		||||
int _libssh2_transport_send(LIBSSH2_SESSION *session,
 | 
			
		||||
                            const unsigned char *data, size_t data_len,
 | 
			
		||||
                            const unsigned char *data2, size_t data2_len)
 | 
			
		||||
{
 | 
			
		||||
    int blocksize =
 | 
			
		||||
        (session->state & LIBSSH2_STATE_NEWKEYS) ?
 | 
			
		||||
        session->local.crypt->blocksize : 8;
 | 
			
		||||
    int padding_length;
 | 
			
		||||
    size_t packet_length;
 | 
			
		||||
    int total_length;
 | 
			
		||||
#ifdef RANDOM_PADDING
 | 
			
		||||
    int rand_max;
 | 
			
		||||
    int seed = data[0];         /* FIXME: make this random */
 | 
			
		||||
#endif
 | 
			
		||||
    struct transportpacket *p = &session->packet;
 | 
			
		||||
    int encrypted;
 | 
			
		||||
    int compressed;
 | 
			
		||||
    ssize_t ret;
 | 
			
		||||
    int rc;
 | 
			
		||||
    const unsigned char *orgdata = data;
 | 
			
		||||
    size_t orgdata_len = data_len;
 | 
			
		||||
 | 
			
		||||
    /*
 | 
			
		||||
     * If the last read operation was interrupted in the middle of a key
 | 
			
		||||
     * exchange, we must complete that key exchange before continuing to write
 | 
			
		||||
     * further data.
 | 
			
		||||
     *
 | 
			
		||||
     * See the similar block in _libssh2_transport_read for more details.
 | 
			
		||||
     */
 | 
			
		||||
    if(session->state & LIBSSH2_STATE_EXCHANGING_KEYS &&
 | 
			
		||||
        !(session->state & LIBSSH2_STATE_KEX_ACTIVE)) {
 | 
			
		||||
        /* Don't write any new packets if we're still in the middle of a key
 | 
			
		||||
         * exchange. */
 | 
			
		||||
        _libssh2_debug(session, LIBSSH2_TRACE_TRANS, "Redirecting into the"
 | 
			
		||||
                       " key re-exchange from _libssh2_transport_send");
 | 
			
		||||
        rc = _libssh2_kex_exchange(session, 1, &session->startup_key_state);
 | 
			
		||||
        if(rc)
 | 
			
		||||
            return rc;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    debugdump(session, "libssh2_transport_write plain", data, data_len);
 | 
			
		||||
    if(data2)
 | 
			
		||||
        debugdump(session, "libssh2_transport_write plain2", data2, data2_len);
 | 
			
		||||
 | 
			
		||||
    /* FIRST, check if we have a pending write to complete. send_existing
 | 
			
		||||
       only sanity-check data and data_len and not data2 and data2_len!! */
 | 
			
		||||
    rc = send_existing(session, data, data_len, &ret);
 | 
			
		||||
    if(rc)
 | 
			
		||||
        return rc;
 | 
			
		||||
 | 
			
		||||
    session->socket_block_directions &= ~LIBSSH2_SESSION_BLOCK_OUTBOUND;
 | 
			
		||||
 | 
			
		||||
    if(ret)
 | 
			
		||||
        /* set by send_existing if data was sent */
 | 
			
		||||
        return rc;
 | 
			
		||||
 | 
			
		||||
    encrypted = (session->state & LIBSSH2_STATE_NEWKEYS) ? 1 : 0;
 | 
			
		||||
 | 
			
		||||
    compressed =
 | 
			
		||||
        session->local.comp != NULL &&
 | 
			
		||||
        session->local.comp->compress &&
 | 
			
		||||
        ((session->state & LIBSSH2_STATE_AUTHENTICATED) ||
 | 
			
		||||
         session->local.comp->use_in_auth);
 | 
			
		||||
 | 
			
		||||
    if(encrypted && compressed && session->local.comp_abstract) {
 | 
			
		||||
        /* the idea here is that these function must fail if the output gets
 | 
			
		||||
           larger than what fits in the assigned buffer so thus they don't
 | 
			
		||||
           check the input size as we don't know how much it compresses */
 | 
			
		||||
        size_t dest_len = MAX_SSH_PACKET_LEN-5-256;
 | 
			
		||||
        size_t dest2_len = dest_len;
 | 
			
		||||
 | 
			
		||||
        /* compress directly to the target buffer */
 | 
			
		||||
        rc = session->local.comp->comp(session,
 | 
			
		||||
                                       &p->outbuf[5], &dest_len,
 | 
			
		||||
                                       data, data_len,
 | 
			
		||||
                                       &session->local.comp_abstract);
 | 
			
		||||
        if(rc)
 | 
			
		||||
            return rc;     /* compression failure */
 | 
			
		||||
 | 
			
		||||
        if(data2 && data2_len) {
 | 
			
		||||
            /* compress directly to the target buffer right after where the
 | 
			
		||||
               previous call put data */
 | 
			
		||||
            dest2_len -= dest_len;
 | 
			
		||||
 | 
			
		||||
            rc = session->local.comp->comp(session,
 | 
			
		||||
                                           &p->outbuf[5 + dest_len],
 | 
			
		||||
                                           &dest2_len,
 | 
			
		||||
                                           data2, data2_len,
 | 
			
		||||
                                           &session->local.comp_abstract);
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
            dest2_len = 0;
 | 
			
		||||
        if(rc)
 | 
			
		||||
            return rc;     /* compression failure */
 | 
			
		||||
 | 
			
		||||
        data_len = dest_len + dest2_len; /* use the combined length */
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
        if((data_len + data2_len) >= (MAX_SSH_PACKET_LEN-0x100))
 | 
			
		||||
            /* too large packet, return error for this until we make this
 | 
			
		||||
               function split it up and send multiple SSH packets */
 | 
			
		||||
            return LIBSSH2_ERROR_INVAL;
 | 
			
		||||
 | 
			
		||||
        /* copy the payload data */
 | 
			
		||||
        memcpy(&p->outbuf[5], data, data_len);
 | 
			
		||||
        if(data2 && data2_len)
 | 
			
		||||
            memcpy(&p->outbuf[5 + data_len], data2, data2_len);
 | 
			
		||||
        data_len += data2_len; /* use the combined length */
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /* RFC4253 says: Note that the length of the concatenation of
 | 
			
		||||
       'packet_length', 'padding_length', 'payload', and 'random padding'
 | 
			
		||||
       MUST be a multiple of the cipher block size or 8, whichever is
 | 
			
		||||
       larger. */
 | 
			
		||||
 | 
			
		||||
    /* Plain math: (4 + 1 + packet_length + padding_length) % blocksize == 0 */
 | 
			
		||||
 | 
			
		||||
    packet_length = data_len + 1 + 4;   /* 1 is for padding_length field
 | 
			
		||||
                                           4 for the packet_length field */
 | 
			
		||||
 | 
			
		||||
    /* at this point we have it all except the padding */
 | 
			
		||||
 | 
			
		||||
    /* first figure out our minimum padding amount to make it an even
 | 
			
		||||
       block size */
 | 
			
		||||
    padding_length = blocksize - (packet_length % blocksize);
 | 
			
		||||
 | 
			
		||||
    /* if the padding becomes too small we add another blocksize worth
 | 
			
		||||
       of it (taken from the original libssh2 where it didn't have any
 | 
			
		||||
       real explanation) */
 | 
			
		||||
    if(padding_length < 4) {
 | 
			
		||||
        padding_length += blocksize;
 | 
			
		||||
    }
 | 
			
		||||
#ifdef RANDOM_PADDING
 | 
			
		||||
    /* FIXME: we can add padding here, but that also makes the packets
 | 
			
		||||
       bigger etc */
 | 
			
		||||
 | 
			
		||||
    /* now we can add 'blocksize' to the padding_length N number of times
 | 
			
		||||
       (to "help thwart traffic analysis") but it must be less than 255 in
 | 
			
		||||
       total */
 | 
			
		||||
    rand_max = (255 - padding_length) / blocksize + 1;
 | 
			
		||||
    padding_length += blocksize * (seed % rand_max);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    packet_length += padding_length;
 | 
			
		||||
 | 
			
		||||
    /* append the MAC length to the total_length size */
 | 
			
		||||
    total_length =
 | 
			
		||||
        packet_length + (encrypted ? session->local.mac->mac_len : 0);
 | 
			
		||||
 | 
			
		||||
    /* store packet_length, which is the size of the whole packet except
 | 
			
		||||
       the MAC and the packet_length field itself */
 | 
			
		||||
    _libssh2_htonu32(p->outbuf, packet_length - 4);
 | 
			
		||||
    /* store padding_length */
 | 
			
		||||
    p->outbuf[4] = (unsigned char)padding_length;
 | 
			
		||||
 | 
			
		||||
    /* fill the padding area with random junk */
 | 
			
		||||
    if(_libssh2_random(p->outbuf + 5 + data_len, padding_length)) {
 | 
			
		||||
        return _libssh2_error(session, LIBSSH2_ERROR_RANDGEN,
 | 
			
		||||
                              "Unable to get random bytes for packet padding");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if(encrypted) {
 | 
			
		||||
        size_t i;
 | 
			
		||||
 | 
			
		||||
        /* Calculate MAC hash. Put the output at index packet_length,
 | 
			
		||||
           since that size includes the whole packet. The MAC is
 | 
			
		||||
           calculated on the entire unencrypted packet, including all
 | 
			
		||||
           fields except the MAC field itself. */
 | 
			
		||||
        session->local.mac->hash(session, p->outbuf + packet_length,
 | 
			
		||||
                                 session->local.seqno, p->outbuf,
 | 
			
		||||
                                 packet_length, NULL, 0,
 | 
			
		||||
                                 &session->local.mac_abstract);
 | 
			
		||||
 | 
			
		||||
        /* Encrypt the whole packet data, one block size at a time.
 | 
			
		||||
           The MAC field is not encrypted. */
 | 
			
		||||
        for(i = 0; i < packet_length; i += session->local.crypt->blocksize) {
 | 
			
		||||
            unsigned char *ptr = &p->outbuf[i];
 | 
			
		||||
            if(session->local.crypt->crypt(session, ptr,
 | 
			
		||||
                                            session->local.crypt->blocksize,
 | 
			
		||||
                                            &session->local.crypt_abstract))
 | 
			
		||||
                return LIBSSH2_ERROR_ENCRYPT;     /* encryption failure */
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    session->local.seqno++;
 | 
			
		||||
 | 
			
		||||
    ret = LIBSSH2_SEND(session, p->outbuf, total_length,
 | 
			
		||||
                        LIBSSH2_SOCKET_SEND_FLAGS(session));
 | 
			
		||||
    if(ret < 0)
 | 
			
		||||
        _libssh2_debug(session, LIBSSH2_TRACE_SOCKET,
 | 
			
		||||
                       "Error sending %d bytes: %d", total_length, -ret);
 | 
			
		||||
    else {
 | 
			
		||||
        _libssh2_debug(session, LIBSSH2_TRACE_SOCKET, "Sent %d/%d bytes at %p",
 | 
			
		||||
                       ret, total_length, p->outbuf);
 | 
			
		||||
        debugdump(session, "libssh2_transport_write send()", p->outbuf, ret);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if(ret != total_length) {
 | 
			
		||||
        if(ret >= 0 || ret == -EAGAIN) {
 | 
			
		||||
            /* the whole packet could not be sent, save the rest */
 | 
			
		||||
            session->socket_block_directions |= LIBSSH2_SESSION_BLOCK_OUTBOUND;
 | 
			
		||||
            p->odata = orgdata;
 | 
			
		||||
            p->olen = orgdata_len;
 | 
			
		||||
            p->osent = ret <= 0 ? 0 : ret;
 | 
			
		||||
            p->ototal_num = total_length;
 | 
			
		||||
            return LIBSSH2_ERROR_EAGAIN;
 | 
			
		||||
        }
 | 
			
		||||
        return LIBSSH2_ERROR_SOCKET_SEND;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* the whole thing got sent away */
 | 
			
		||||
    p->odata = NULL;
 | 
			
		||||
    p->olen = 0;
 | 
			
		||||
 | 
			
		||||
    return LIBSSH2_ERROR_NONE;         /* all is good */
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,88 @@
 | 
			
		|||
#if defined(ESP32)
 | 
			
		||||
#ifndef __LIBSSH2_TRANSPORT_H
 | 
			
		||||
#define __LIBSSH2_TRANSPORT_H
 | 
			
		||||
/* Copyright (C) 2007 The Written Word, Inc.  All rights reserved.
 | 
			
		||||
 * Copyright (C) 2009-2010 by Daniel Stenberg
 | 
			
		||||
 * Author: Daniel Stenberg <daniel@haxx.se>
 | 
			
		||||
 *
 | 
			
		||||
 * Redistribution and use in source and binary forms,
 | 
			
		||||
 * with or without modification, are permitted provided
 | 
			
		||||
 * that the following conditions are met:
 | 
			
		||||
 *
 | 
			
		||||
 *   Redistributions of source code must retain the above
 | 
			
		||||
 *   copyright notice, this list of conditions and the
 | 
			
		||||
 *   following disclaimer.
 | 
			
		||||
 *
 | 
			
		||||
 *   Redistributions in binary form must reproduce the above
 | 
			
		||||
 *   copyright notice, this list of conditions and the following
 | 
			
		||||
 *   disclaimer in the documentation and/or other materials
 | 
			
		||||
 *   provided with the distribution.
 | 
			
		||||
 *
 | 
			
		||||
 *   Neither the name of the copyright holder nor the names
 | 
			
		||||
 *   of any other contributors may be used to endorse or
 | 
			
		||||
 *   promote products derived from this software without
 | 
			
		||||
 *   specific prior written permission.
 | 
			
		||||
 *
 | 
			
		||||
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
 | 
			
		||||
 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 | 
			
		||||
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 | 
			
		||||
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 | 
			
		||||
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 | 
			
		||||
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | 
			
		||||
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 | 
			
		||||
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 | 
			
		||||
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 | 
			
		||||
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 | 
			
		||||
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 | 
			
		||||
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
 | 
			
		||||
 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
 | 
			
		||||
 * OF SUCH DAMAGE.
 | 
			
		||||
 *
 | 
			
		||||
 * This file handles reading and writing to the SECSH transport layer. RFC4253.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "libssh2_priv.h"
 | 
			
		||||
#include "packet.h"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * libssh2_transport_send
 | 
			
		||||
 *
 | 
			
		||||
 * Send a packet, encrypting it and adding a MAC code if necessary
 | 
			
		||||
 * Returns 0 on success, non-zero on failure.
 | 
			
		||||
 *
 | 
			
		||||
 * The data is provided as _two_ data areas that are combined by this
 | 
			
		||||
 * function.  The 'data' part is sent immediately before 'data2'. 'data2' can
 | 
			
		||||
 * be set to NULL (or data2_len to 0) to only use a single part.
 | 
			
		||||
 *
 | 
			
		||||
 * Returns LIBSSH2_ERROR_EAGAIN if it would block or if the whole packet was
 | 
			
		||||
 * not sent yet. If it does so, the caller should call this function again as
 | 
			
		||||
 * soon as it is likely that more data can be sent, and this function MUST
 | 
			
		||||
 * then be called with the same argument set (same data pointer and same
 | 
			
		||||
 * data_len) until ERROR_NONE or failure is returned.
 | 
			
		||||
 *
 | 
			
		||||
 * This function DOES NOT call _libssh2_error() on any errors.
 | 
			
		||||
 */
 | 
			
		||||
int _libssh2_transport_send(LIBSSH2_SESSION *session,
 | 
			
		||||
                            const unsigned char *data, size_t data_len,
 | 
			
		||||
                            const unsigned char *data2, size_t data2_len);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * _libssh2_transport_read
 | 
			
		||||
 *
 | 
			
		||||
 * Collect a packet into the input brigade block only controls whether or not
 | 
			
		||||
 * to wait for a packet to start.
 | 
			
		||||
 *
 | 
			
		||||
 * Returns packet type added to input brigade (PACKET_NONE if nothing added),
 | 
			
		||||
 * or PACKET_FAIL on failure and PACKET_EAGAIN if it couldn't process a full
 | 
			
		||||
 * packet.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * This function reads the binary stream as specified in chapter 6 of RFC4253
 | 
			
		||||
 * "The Secure Shell (SSH) Transport Layer Protocol"
 | 
			
		||||
 */
 | 
			
		||||
int _libssh2_transport_read(LIBSSH2_SESSION * session);
 | 
			
		||||
 | 
			
		||||
#endif /* __LIBSSH2_TRANSPORT_H */
 | 
			
		||||
#endif
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| 
						 | 
				
			
			@ -0,0 +1,53 @@
 | 
			
		|||
#if defined(ESP32)
 | 
			
		||||
#ifndef __LIBSSH2_USERAUTH_H
 | 
			
		||||
#define __LIBSSH2_USERAUTH_H
 | 
			
		||||
/* Copyright (c) 2004-2007, Sara Golemon <sarag@libssh2.org>
 | 
			
		||||
 * Copyright (c) 2009-2010 by Daniel Stenberg
 | 
			
		||||
 * All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Redistribution and use in source and binary forms,
 | 
			
		||||
 * with or without modification, are permitted provided
 | 
			
		||||
 * that the following conditions are met:
 | 
			
		||||
 *
 | 
			
		||||
 *   Redistributions of source code must retain the above
 | 
			
		||||
 *   copyright notice, this list of conditions and the
 | 
			
		||||
 *   following disclaimer.
 | 
			
		||||
 *
 | 
			
		||||
 *   Redistributions in binary form must reproduce the above
 | 
			
		||||
 *   copyright notice, this list of conditions and the following
 | 
			
		||||
 *   disclaimer in the documentation and/or other materials
 | 
			
		||||
 *   provided with the distribution.
 | 
			
		||||
 *
 | 
			
		||||
 *   Neither the name of the copyright holder nor the names
 | 
			
		||||
 *   of any other contributors may be used to endorse or
 | 
			
		||||
 *   promote products derived from this software without
 | 
			
		||||
 *   specific prior written permission.
 | 
			
		||||
 *
 | 
			
		||||
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
 | 
			
		||||
 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 | 
			
		||||
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 | 
			
		||||
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 | 
			
		||||
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 | 
			
		||||
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | 
			
		||||
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 | 
			
		||||
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 | 
			
		||||
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 | 
			
		||||
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 | 
			
		||||
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 | 
			
		||||
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
 | 
			
		||||
 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
 | 
			
		||||
 * OF SUCH DAMAGE.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
_libssh2_userauth_publickey(LIBSSH2_SESSION *session,
 | 
			
		||||
                            const char *username,
 | 
			
		||||
                            unsigned int username_len,
 | 
			
		||||
                            const unsigned char *pubkeydata,
 | 
			
		||||
                            unsigned long pubkeydata_len,
 | 
			
		||||
                            LIBSSH2_USERAUTH_PUBLICKEY_SIGN_FUNC
 | 
			
		||||
                            ((*sign_callback)),
 | 
			
		||||
                            void *abstract);
 | 
			
		||||
 | 
			
		||||
#endif /* __LIBSSH2_USERAUTH_H */
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,164 @@
 | 
			
		|||
#if defined(ESP32)
 | 
			
		||||
/* Copyright (c) 2022, Xaver Loppenstedt <xaver@loppenstedt.de>
 | 
			
		||||
 * All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Redistribution and use in source and binary forms,
 | 
			
		||||
 * with or without modification, are permitted provided
 | 
			
		||||
 * that the following conditions are met:
 | 
			
		||||
 *
 | 
			
		||||
 *   Redistributions of source code must retain the above
 | 
			
		||||
 *   copyright notice, this list of conditions and the
 | 
			
		||||
 *   following disclaimer.
 | 
			
		||||
 *
 | 
			
		||||
 *   Redistributions in binary form must reproduce the above
 | 
			
		||||
 *   copyright notice, this list of conditions and the following
 | 
			
		||||
 *   disclaimer in the documentation and/or other materials
 | 
			
		||||
 *   provided with the distribution.
 | 
			
		||||
 *
 | 
			
		||||
 *   Neither the name of the copyright holder nor the names
 | 
			
		||||
 *   of any other contributors may be used to endorse or
 | 
			
		||||
 *   promote products derived from this software without
 | 
			
		||||
 *   specific prior written permission.
 | 
			
		||||
 *
 | 
			
		||||
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
 | 
			
		||||
 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 | 
			
		||||
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 | 
			
		||||
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 | 
			
		||||
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 | 
			
		||||
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | 
			
		||||
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 | 
			
		||||
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 | 
			
		||||
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 | 
			
		||||
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 | 
			
		||||
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 | 
			
		||||
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
 | 
			
		||||
 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
 | 
			
		||||
 * OF SUCH DAMAGE.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "libssh2_priv.h"
 | 
			
		||||
#include "userauth_kbd_packet.h"
 | 
			
		||||
 | 
			
		||||
int userauth_keyboard_interactive_decode_info_request(LIBSSH2_SESSION *session)
 | 
			
		||||
{
 | 
			
		||||
    unsigned char *language_tag;
 | 
			
		||||
    size_t language_tag_len;
 | 
			
		||||
    unsigned int i;
 | 
			
		||||
    unsigned char packet_type;
 | 
			
		||||
 | 
			
		||||
    struct string_buf decoded;
 | 
			
		||||
 | 
			
		||||
    decoded.data = session->userauth_kybd_data;
 | 
			
		||||
    decoded.dataptr = session->userauth_kybd_data;
 | 
			
		||||
    decoded.len = session->userauth_kybd_data_len;
 | 
			
		||||
 | 
			
		||||
    if(session->userauth_kybd_data_len < 17) {
 | 
			
		||||
        _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL,
 | 
			
		||||
                       "userauth keyboard data buffer too small "
 | 
			
		||||
                       "to get length");
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* byte      SSH_MSG_USERAUTH_INFO_REQUEST */
 | 
			
		||||
    _libssh2_get_byte(&decoded, &packet_type);
 | 
			
		||||
 | 
			
		||||
    /* string    name (ISO-10646 UTF-8) */
 | 
			
		||||
    if(_libssh2_copy_string(session, &decoded,
 | 
			
		||||
                            &session->userauth_kybd_auth_name,
 | 
			
		||||
                            &session->userauth_kybd_auth_name_len) == -1) {
 | 
			
		||||
        _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
 | 
			
		||||
                       "Unable to decode "
 | 
			
		||||
                       "keyboard-interactive 'name' "
 | 
			
		||||
                       "request field");
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* string    instruction (ISO-10646 UTF-8) */
 | 
			
		||||
    if(_libssh2_copy_string(session, &decoded,
 | 
			
		||||
                            &session->userauth_kybd_auth_instruction,
 | 
			
		||||
                            &session->userauth_kybd_auth_instruction_len)
 | 
			
		||||
       == -1) {
 | 
			
		||||
        _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
 | 
			
		||||
                       "Unable to decode "
 | 
			
		||||
                       "keyboard-interactive 'instruction' "
 | 
			
		||||
                       "request field");
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* string    language tag (as defined in [RFC-3066]) */
 | 
			
		||||
    if(_libssh2_get_string(&decoded, &language_tag,
 | 
			
		||||
                           &language_tag_len) == -1) {
 | 
			
		||||
        _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
 | 
			
		||||
                       "Unable to decode "
 | 
			
		||||
                       "keyboard-interactive 'language tag' "
 | 
			
		||||
                       "request field");
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* int       num-prompts */
 | 
			
		||||
    if(_libssh2_get_u32(&decoded, &session->userauth_kybd_num_prompts) == -1) {
 | 
			
		||||
        _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL,
 | 
			
		||||
                       "Unable to decode "
 | 
			
		||||
                       "keyboard-interactive number of keyboard prompts");
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if(session->userauth_kybd_num_prompts > 100) {
 | 
			
		||||
        _libssh2_error(session, LIBSSH2_ERROR_OUT_OF_BOUNDARY,
 | 
			
		||||
                       "Too many replies for "
 | 
			
		||||
                       "keyboard-interactive prompts");
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if(session->userauth_kybd_num_prompts == 0) {
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    session->userauth_kybd_prompts =
 | 
			
		||||
        LIBSSH2_CALLOC(session,
 | 
			
		||||
                       sizeof(LIBSSH2_USERAUTH_KBDINT_PROMPT) *
 | 
			
		||||
                       session->userauth_kybd_num_prompts);
 | 
			
		||||
    if(!session->userauth_kybd_prompts) {
 | 
			
		||||
        _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
 | 
			
		||||
                       "Unable to allocate memory for "
 | 
			
		||||
                       "keyboard-interactive prompts array");
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    session->userauth_kybd_responses =
 | 
			
		||||
        LIBSSH2_CALLOC(session,
 | 
			
		||||
                       sizeof(LIBSSH2_USERAUTH_KBDINT_RESPONSE) *
 | 
			
		||||
                       session->userauth_kybd_num_prompts);
 | 
			
		||||
    if(!session->userauth_kybd_responses) {
 | 
			
		||||
        _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
 | 
			
		||||
                       "Unable to allocate memory for "
 | 
			
		||||
                       "keyboard-interactive responses array");
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for(i = 0; i < session->userauth_kybd_num_prompts; i++) {
 | 
			
		||||
        /* string    prompt[1] (ISO-10646 UTF-8) */
 | 
			
		||||
        if(_libssh2_copy_string(session, &decoded,
 | 
			
		||||
                                &session->userauth_kybd_prompts[i].text,
 | 
			
		||||
                                &session->userauth_kybd_prompts[i].length)
 | 
			
		||||
           == -1) {
 | 
			
		||||
            _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
 | 
			
		||||
                           "Unable to decode "
 | 
			
		||||
                           "keyboard-interactive prompt message");
 | 
			
		||||
            return -1;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /* boolean   echo[1] */
 | 
			
		||||
        if(_libssh2_get_boolean(&decoded,
 | 
			
		||||
                                &session->userauth_kybd_prompts[i].echo)
 | 
			
		||||
           == -1) {
 | 
			
		||||
            _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL,
 | 
			
		||||
                           "Unable to decode "
 | 
			
		||||
                           "user auth keyboard prompt echo");
 | 
			
		||||
            return -1;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,45 @@
 | 
			
		|||
#if defined(ESP32)
 | 
			
		||||
/* Copyright (c) 2022, Xaver Loppenstedt <xaver@loppenstedt.de>
 | 
			
		||||
 * All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Redistribution and use in source and binary forms,
 | 
			
		||||
 * with or without modification, are permitted provided
 | 
			
		||||
 * that the following conditions are met:
 | 
			
		||||
 *
 | 
			
		||||
 *   Redistributions of source code must retain the above
 | 
			
		||||
 *   copyright notice, this list of conditions and the
 | 
			
		||||
 *   following disclaimer.
 | 
			
		||||
 *
 | 
			
		||||
 *   Redistributions in binary form must reproduce the above
 | 
			
		||||
 *   copyright notice, this list of conditions and the following
 | 
			
		||||
 *   disclaimer in the documentation and/or other materials
 | 
			
		||||
 *   provided with the distribution.
 | 
			
		||||
 *
 | 
			
		||||
 *   Neither the name of the copyright holder nor the names
 | 
			
		||||
 *   of any other contributors may be used to endorse or
 | 
			
		||||
 *   promote products derived from this software without
 | 
			
		||||
 *   specific prior written permission.
 | 
			
		||||
 *
 | 
			
		||||
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
 | 
			
		||||
 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 | 
			
		||||
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 | 
			
		||||
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 | 
			
		||||
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 | 
			
		||||
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | 
			
		||||
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 | 
			
		||||
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 | 
			
		||||
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 | 
			
		||||
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 | 
			
		||||
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 | 
			
		||||
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
 | 
			
		||||
 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
 | 
			
		||||
 * OF SUCH DAMAGE.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef __LIBSSH2_USERAUTH_KBD_PARSE_H
 | 
			
		||||
#define __LIBSSH2_USERAUTH_KBD_PARSE_H
 | 
			
		||||
 | 
			
		||||
int userauth_keyboard_interactive_decode_info_request(LIBSSH2_SESSION *);
 | 
			
		||||
 | 
			
		||||
#endif /* __LIBSSH2_USERAUTH_KBD_PARSE_H */
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,572 @@
 | 
			
		|||
/**
 | 
			
		||||
 * @file
 | 
			
		||||
 * SLIP Interface
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
 | 
			
		||||
 * All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Redistribution and use in source and binary forms, with or without
 | 
			
		||||
 * modification, are permitted provided that the following conditions
 | 
			
		||||
 * are met:
 | 
			
		||||
 * 1. Redistributions of source code must retain the above copyright
 | 
			
		||||
 *    notice, this list of conditions and the following disclaimer.
 | 
			
		||||
 * 2. Redistributions in binary form must reproduce the above copyright
 | 
			
		||||
 *    notice, this list of conditions and the following disclaimer in the
 | 
			
		||||
 *    documentation and/or other materials provided with the distribution.
 | 
			
		||||
 * 3. Neither the name of the Institute nor the names of its contributors
 | 
			
		||||
 *    may be used to endorse or promote products derived from this software
 | 
			
		||||
 *    without specific prior written permission.
 | 
			
		||||
 *
 | 
			
		||||
 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
 | 
			
		||||
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 | 
			
		||||
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 | 
			
		||||
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
 | 
			
		||||
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 | 
			
		||||
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 | 
			
		||||
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 | 
			
		||||
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 | 
			
		||||
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 | 
			
		||||
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 | 
			
		||||
 * SUCH DAMAGE.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is built upon the file: src/arch/rtxc/netif/sioslip.c
 | 
			
		||||
 *
 | 
			
		||||
 * Author: Magnus Ivarsson <magnus.ivarsson(at)volvo.com>
 | 
			
		||||
 *         Simon Goldschmidt
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @defgroup slipif SLIP
 | 
			
		||||
 * @ingroup netifs
 | 
			
		||||
 *
 | 
			
		||||
 * This is an arch independent SLIP netif. The specific serial hooks must be
 | 
			
		||||
 * provided by another file. They are sio_open, sio_read/sio_tryread and sio_send
 | 
			
		||||
 *
 | 
			
		||||
 * Usage: This netif can be used in three ways:
 | 
			
		||||
 *        1. For NO_SYS==0, an RX thread can be used which blocks on sio_read()
 | 
			
		||||
 *           until data is received.
 | 
			
		||||
 *        2. In your main loop, call slipif_poll() to check for new RX bytes,
 | 
			
		||||
 *           completed packets are fed into netif->input().
 | 
			
		||||
 *        3. Call slipif_received_byte[s]() from your serial RX ISR and
 | 
			
		||||
 *           slipif_process_rxqueue() from your main loop. ISR level decodes
 | 
			
		||||
 *           packets and puts completed packets on a queue which is fed into
 | 
			
		||||
 *           the stack from the main loop (needs SYS_LIGHTWEIGHT_PROT for
 | 
			
		||||
 *           pbuf_alloc to work on ISR level!).
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "slipif.h"
 | 
			
		||||
#include "lwip/opt.h"
 | 
			
		||||
 | 
			
		||||
#include "lwip/def.h"
 | 
			
		||||
#include "lwip/pbuf.h"
 | 
			
		||||
#include "lwip/stats.h"
 | 
			
		||||
#include "lwip/snmp.h"
 | 
			
		||||
#include "lwip/sys.h"
 | 
			
		||||
#include "lwip/sio.h"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void* sio_open  (u8_t sid)
 | 
			
		||||
{
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
u32_t sio_read (sio_fd_t fd, u8_t *data, u32_t len)
 | 
			
		||||
{
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
u32_t sio_tryread (sio_fd_t fd, u8_t *data, u32_t len)
 | 
			
		||||
{
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
void sio_send (u8_t c, void *s) {}
 | 
			
		||||
#define SLIP_END     0xC0 /* 0300: start and end of every packet */
 | 
			
		||||
#define SLIP_ESC     0xDB /* 0333: escape start (one byte escaped data follows) */
 | 
			
		||||
#define SLIP_ESC_END 0xDC /* 0334: following escape: original byte is 0xC0 (END) */
 | 
			
		||||
#define SLIP_ESC_ESC 0xDD /* 0335: following escape: original byte is 0xDB (ESC) */
 | 
			
		||||
 | 
			
		||||
/** Maximum packet size that is received by this netif */
 | 
			
		||||
#ifndef SLIP_MAX_SIZE
 | 
			
		||||
#define SLIP_MAX_SIZE 1500
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/** Define this to the interface speed for SNMP
 | 
			
		||||
 * (sio_fd is the sio_fd_t returned by sio_open).
 | 
			
		||||
 * The default value of zero means 'unknown'.
 | 
			
		||||
 */
 | 
			
		||||
#ifndef SLIP_SIO_SPEED
 | 
			
		||||
#define SLIP_SIO_SPEED(sio_fd) 0
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
enum slipif_recv_state {
 | 
			
		||||
  SLIP_RECV_NORMAL,
 | 
			
		||||
  SLIP_RECV_ESCAPE
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct slipif_priv {
 | 
			
		||||
  sio_fd_t sd;
 | 
			
		||||
  /* q is the whole pbuf chain for a packet, p is the current pbuf in the chain */
 | 
			
		||||
  struct pbuf *p, *q;
 | 
			
		||||
  u8_t state;
 | 
			
		||||
  u16_t i, recved;
 | 
			
		||||
#if SLIP_RX_FROM_ISR
 | 
			
		||||
  struct pbuf *rxpackets;
 | 
			
		||||
#endif
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Send a pbuf doing the necessary SLIP encapsulation
 | 
			
		||||
 *
 | 
			
		||||
 * Uses the serial layer's sio_send()
 | 
			
		||||
 *
 | 
			
		||||
 * @param netif the lwip network interface structure for this slipif
 | 
			
		||||
 * @param p the pbuf chain packet to send
 | 
			
		||||
 * @return always returns ERR_OK since the serial layer does not provide return values
 | 
			
		||||
 */
 | 
			
		||||
static err_t
 | 
			
		||||
slipif_output(struct netif *netif, struct pbuf *p)
 | 
			
		||||
{
 | 
			
		||||
  struct slipif_priv *priv;
 | 
			
		||||
  struct pbuf *q;
 | 
			
		||||
  u16_t i;
 | 
			
		||||
  u8_t c;
 | 
			
		||||
 | 
			
		||||
  LWIP_ASSERT("netif != NULL", (netif != NULL));
 | 
			
		||||
  LWIP_ASSERT("netif->state != NULL", (netif->state != NULL));
 | 
			
		||||
  LWIP_ASSERT("p != NULL", (p != NULL));
 | 
			
		||||
 | 
			
		||||
  LWIP_DEBUGF(SLIP_DEBUG, ("slipif_output: sending %"U16_F" bytes\n", p->tot_len));
 | 
			
		||||
  priv = (struct slipif_priv *)netif->state;
 | 
			
		||||
 | 
			
		||||
  /* Send pbuf out on the serial I/O device. */
 | 
			
		||||
  /* Start with packet delimiter. */
 | 
			
		||||
  sio_send(SLIP_END, priv->sd);
 | 
			
		||||
 | 
			
		||||
  for (q = p; q != NULL; q = q->next) {
 | 
			
		||||
    for (i = 0; i < q->len; i++) {
 | 
			
		||||
      c = ((u8_t *)q->payload)[i];
 | 
			
		||||
      switch (c) {
 | 
			
		||||
        case SLIP_END:
 | 
			
		||||
          /* need to escape this byte (0xC0 -> 0xDB, 0xDC) */
 | 
			
		||||
          sio_send(SLIP_ESC, priv->sd);
 | 
			
		||||
          sio_send(SLIP_ESC_END, priv->sd);
 | 
			
		||||
          break;
 | 
			
		||||
        case SLIP_ESC:
 | 
			
		||||
          /* need to escape this byte (0xDB -> 0xDB, 0xDD) */
 | 
			
		||||
          sio_send(SLIP_ESC, priv->sd);
 | 
			
		||||
          sio_send(SLIP_ESC_ESC, priv->sd);
 | 
			
		||||
          break;
 | 
			
		||||
        default:
 | 
			
		||||
          /* normal byte - no need for escaping */
 | 
			
		||||
          sio_send(c, priv->sd);
 | 
			
		||||
          break;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  /* End with packet delimiter. */
 | 
			
		||||
  sio_send(SLIP_END, priv->sd);
 | 
			
		||||
  return ERR_OK;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#if LWIP_IPV4
 | 
			
		||||
/**
 | 
			
		||||
 * Send a pbuf doing the necessary SLIP encapsulation
 | 
			
		||||
 *
 | 
			
		||||
 * Uses the serial layer's sio_send()
 | 
			
		||||
 *
 | 
			
		||||
 * @param netif the lwip network interface structure for this slipif
 | 
			
		||||
 * @param p the pbuf chain packet to send
 | 
			
		||||
 * @param ipaddr the ip address to send the packet to (not used for slipif)
 | 
			
		||||
 * @return always returns ERR_OK since the serial layer does not provide return values
 | 
			
		||||
 */
 | 
			
		||||
static err_t
 | 
			
		||||
slipif_output_v4(struct netif *netif, struct pbuf *p, const ip4_addr_t *ipaddr)
 | 
			
		||||
{
 | 
			
		||||
  LWIP_UNUSED_ARG(ipaddr);
 | 
			
		||||
  return slipif_output(netif, p);
 | 
			
		||||
}
 | 
			
		||||
#endif /* LWIP_IPV4 */
 | 
			
		||||
 | 
			
		||||
#if LWIP_IPV6
 | 
			
		||||
/**
 | 
			
		||||
 * Send a pbuf doing the necessary SLIP encapsulation
 | 
			
		||||
 *
 | 
			
		||||
 * Uses the serial layer's sio_send()
 | 
			
		||||
 *
 | 
			
		||||
 * @param netif the lwip network interface structure for this slipif
 | 
			
		||||
 * @param p the pbuf chain packet to send
 | 
			
		||||
 * @param ipaddr the ip address to send the packet to (not used for slipif)
 | 
			
		||||
 * @return always returns ERR_OK since the serial layer does not provide return values
 | 
			
		||||
 */
 | 
			
		||||
static err_t
 | 
			
		||||
slipif_output_v6(struct netif *netif, struct pbuf *p, const ip6_addr_t *ipaddr)
 | 
			
		||||
{
 | 
			
		||||
  LWIP_UNUSED_ARG(ipaddr);
 | 
			
		||||
  return slipif_output(netif, p);
 | 
			
		||||
}
 | 
			
		||||
#endif /* LWIP_IPV6 */
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Handle the incoming SLIP stream character by character
 | 
			
		||||
 *
 | 
			
		||||
 * @param netif the lwip network interface structure for this slipif
 | 
			
		||||
 * @param c received character (multiple calls to this function will
 | 
			
		||||
 *        return a complete packet, NULL is returned before - used for polling)
 | 
			
		||||
 * @return The IP packet when SLIP_END is received
 | 
			
		||||
 */
 | 
			
		||||
static struct pbuf *
 | 
			
		||||
slipif_rxbyte(struct netif *netif, u8_t c)
 | 
			
		||||
{
 | 
			
		||||
  struct slipif_priv *priv;
 | 
			
		||||
  struct pbuf *t;
 | 
			
		||||
 | 
			
		||||
  LWIP_ASSERT("netif != NULL", (netif != NULL));
 | 
			
		||||
  LWIP_ASSERT("netif->state != NULL", (netif->state != NULL));
 | 
			
		||||
 | 
			
		||||
  priv = (struct slipif_priv *)netif->state;
 | 
			
		||||
 | 
			
		||||
  switch (priv->state) {
 | 
			
		||||
    case SLIP_RECV_NORMAL:
 | 
			
		||||
      switch (c) {
 | 
			
		||||
        case SLIP_END:
 | 
			
		||||
          if (priv->recved > 0) {
 | 
			
		||||
            /* Received whole packet. */
 | 
			
		||||
            /* Trim the pbuf to the size of the received packet. */
 | 
			
		||||
            pbuf_realloc(priv->q, priv->recved);
 | 
			
		||||
 | 
			
		||||
            LINK_STATS_INC(link.recv);
 | 
			
		||||
 | 
			
		||||
            LWIP_DEBUGF(SLIP_DEBUG, ("slipif: Got packet (%"U16_F" bytes)\n", priv->recved));
 | 
			
		||||
            t = priv->q;
 | 
			
		||||
            priv->p = priv->q = NULL;
 | 
			
		||||
            priv->i = priv->recved = 0;
 | 
			
		||||
            return t;
 | 
			
		||||
          }
 | 
			
		||||
          return NULL;
 | 
			
		||||
        case SLIP_ESC:
 | 
			
		||||
          priv->state = SLIP_RECV_ESCAPE;
 | 
			
		||||
          return NULL;
 | 
			
		||||
        default:
 | 
			
		||||
          break;
 | 
			
		||||
      } /* end switch (c) */
 | 
			
		||||
      break;
 | 
			
		||||
    case SLIP_RECV_ESCAPE:
 | 
			
		||||
      /* un-escape END or ESC bytes, leave other bytes
 | 
			
		||||
         (although that would be a protocol error) */
 | 
			
		||||
      switch (c) {
 | 
			
		||||
        case SLIP_ESC_END:
 | 
			
		||||
          c = SLIP_END;
 | 
			
		||||
          break;
 | 
			
		||||
        case SLIP_ESC_ESC:
 | 
			
		||||
          c = SLIP_ESC;
 | 
			
		||||
          break;
 | 
			
		||||
        default:
 | 
			
		||||
          break;
 | 
			
		||||
      }
 | 
			
		||||
      priv->state = SLIP_RECV_NORMAL;
 | 
			
		||||
      break;
 | 
			
		||||
    default:
 | 
			
		||||
      break;
 | 
			
		||||
  } /* end switch (priv->state) */
 | 
			
		||||
 | 
			
		||||
  /* byte received, packet not yet completely received */
 | 
			
		||||
  if (priv->p == NULL) {
 | 
			
		||||
    /* allocate a new pbuf */
 | 
			
		||||
    LWIP_DEBUGF(SLIP_DEBUG, ("slipif_input: alloc\n"));
 | 
			
		||||
    priv->p = pbuf_alloc(PBUF_LINK, (PBUF_POOL_BUFSIZE - PBUF_LINK_HLEN - PBUF_LINK_ENCAPSULATION_HLEN), PBUF_POOL);
 | 
			
		||||
 | 
			
		||||
    if (priv->p == NULL) {
 | 
			
		||||
      LINK_STATS_INC(link.drop);
 | 
			
		||||
      LWIP_DEBUGF(SLIP_DEBUG, ("slipif_input: no new pbuf! (DROP)\n"));
 | 
			
		||||
      /* don't process any further since we got no pbuf to receive to */
 | 
			
		||||
      return NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (priv->q != NULL) {
 | 
			
		||||
      /* 'chain' the pbuf to the existing chain */
 | 
			
		||||
      pbuf_cat(priv->q, priv->p);
 | 
			
		||||
    } else {
 | 
			
		||||
      /* p is the first pbuf in the chain */
 | 
			
		||||
      priv->q = priv->p;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /* this automatically drops bytes if > SLIP_MAX_SIZE */
 | 
			
		||||
  if ((priv->p != NULL) && (priv->recved <= SLIP_MAX_SIZE)) {
 | 
			
		||||
    ((u8_t *)priv->p->payload)[priv->i] = c;
 | 
			
		||||
    priv->recved++;
 | 
			
		||||
    priv->i++;
 | 
			
		||||
    if (priv->i >= priv->p->len) {
 | 
			
		||||
      /* on to the next pbuf */
 | 
			
		||||
      priv->i = 0;
 | 
			
		||||
      if (priv->p->next != NULL && priv->p->next->len > 0) {
 | 
			
		||||
        /* p is a chain, on to the next in the chain */
 | 
			
		||||
        priv->p = priv->p->next;
 | 
			
		||||
      } else {
 | 
			
		||||
        /* p is a single pbuf, set it to NULL so next time a new
 | 
			
		||||
         * pbuf is allocated */
 | 
			
		||||
        priv->p = NULL;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** Like slipif_rxbyte, but passes completed packets to netif->input
 | 
			
		||||
 *
 | 
			
		||||
 * @param netif The lwip network interface structure for this slipif
 | 
			
		||||
 * @param c received character
 | 
			
		||||
 */
 | 
			
		||||
static void
 | 
			
		||||
slipif_rxbyte_input(struct netif *netif, u8_t c)
 | 
			
		||||
{
 | 
			
		||||
  struct pbuf *p;
 | 
			
		||||
  p = slipif_rxbyte(netif, c);
 | 
			
		||||
  if (p != NULL) {
 | 
			
		||||
    if (netif->input(p, netif) != ERR_OK) {
 | 
			
		||||
      pbuf_free(p);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#if SLIP_USE_RX_THREAD
 | 
			
		||||
/**
 | 
			
		||||
 * The SLIP input thread.
 | 
			
		||||
 *
 | 
			
		||||
 * Feed the IP layer with incoming packets
 | 
			
		||||
 *
 | 
			
		||||
 * @param nf the lwip network interface structure for this slipif
 | 
			
		||||
 */
 | 
			
		||||
static void
 | 
			
		||||
slipif_loop_thread(void *nf)
 | 
			
		||||
{
 | 
			
		||||
  u8_t c;
 | 
			
		||||
  struct netif *netif = (struct netif *)nf;
 | 
			
		||||
  struct slipif_priv *priv = (struct slipif_priv *)netif->state;
 | 
			
		||||
 | 
			
		||||
  while (1) {
 | 
			
		||||
    if (sio_read(priv->sd, &c, 1) > 0) {
 | 
			
		||||
      slipif_rxbyte_input(netif, c);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
#endif /* SLIP_USE_RX_THREAD */
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @ingroup slipif
 | 
			
		||||
 * SLIP netif initialization
 | 
			
		||||
 *
 | 
			
		||||
 * Call the arch specific sio_open and remember
 | 
			
		||||
 * the opened device in the state field of the netif.
 | 
			
		||||
 *
 | 
			
		||||
 * @param netif the lwip network interface structure for this slipif
 | 
			
		||||
 * @return ERR_OK if serial line could be opened,
 | 
			
		||||
 *         ERR_MEM if no memory could be allocated,
 | 
			
		||||
 *         ERR_IF is serial line couldn't be opened
 | 
			
		||||
 *
 | 
			
		||||
 * @note If netif->state is interpreted as an u8_t serial port number.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
err_t
 | 
			
		||||
slipif_init(struct netif *netif)
 | 
			
		||||
{
 | 
			
		||||
  struct slipif_priv *priv;
 | 
			
		||||
  u8_t sio_num;
 | 
			
		||||
 | 
			
		||||
  LWIP_ASSERT("slipif needs an input callback", netif->input != NULL);
 | 
			
		||||
 | 
			
		||||
  /* netif->state contains serial port number */
 | 
			
		||||
  sio_num = LWIP_PTR_NUMERIC_CAST(u8_t, netif->state);
 | 
			
		||||
 | 
			
		||||
  LWIP_DEBUGF(SLIP_DEBUG, ("slipif_init: netif->num=%"U16_F"\n", (u16_t)sio_num));
 | 
			
		||||
 | 
			
		||||
  /* Allocate private data */
 | 
			
		||||
  priv = (struct slipif_priv *)mem_malloc(sizeof(struct slipif_priv));
 | 
			
		||||
  if (!priv) {
 | 
			
		||||
    return ERR_MEM;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  netif->name[0] = 's';
 | 
			
		||||
  netif->name[1] = 'l';
 | 
			
		||||
#if LWIP_IPV4
 | 
			
		||||
  netif->output = slipif_output_v4;
 | 
			
		||||
#endif /* LWIP_IPV4 */
 | 
			
		||||
#if LWIP_IPV6
 | 
			
		||||
  netif->output_ip6 = slipif_output_v6;
 | 
			
		||||
#endif /* LWIP_IPV6 */
 | 
			
		||||
  netif->mtu = SLIP_MAX_SIZE;
 | 
			
		||||
 | 
			
		||||
  /* Try to open the serial port. */
 | 
			
		||||
  priv->sd = sio_open(sio_num);
 | 
			
		||||
  if (!priv->sd) {
 | 
			
		||||
    /* Opening the serial port failed. */
 | 
			
		||||
    mem_free(priv);
 | 
			
		||||
    return ERR_IF;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /* Initialize private data */
 | 
			
		||||
  priv->p = NULL;
 | 
			
		||||
  priv->q = NULL;
 | 
			
		||||
  priv->state = SLIP_RECV_NORMAL;
 | 
			
		||||
  priv->i = 0;
 | 
			
		||||
  priv->recved = 0;
 | 
			
		||||
#if SLIP_RX_FROM_ISR
 | 
			
		||||
  priv->rxpackets = NULL;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
  netif->state = priv;
 | 
			
		||||
 | 
			
		||||
  /* initialize the snmp variables and counters inside the struct netif */
 | 
			
		||||
  MIB2_INIT_NETIF(netif, snmp_ifType_slip, SLIP_SIO_SPEED(priv->sd));
 | 
			
		||||
 | 
			
		||||
#if SLIP_USE_RX_THREAD
 | 
			
		||||
  /* Create a thread to poll the serial line. */
 | 
			
		||||
  sys_thread_new(SLIPIF_THREAD_NAME, slipif_loop_thread, netif,
 | 
			
		||||
                 SLIPIF_THREAD_STACKSIZE, SLIPIF_THREAD_PRIO);
 | 
			
		||||
#endif /* SLIP_USE_RX_THREAD */
 | 
			
		||||
  return ERR_OK;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @ingroup slipif
 | 
			
		||||
 * Polls the serial device and feeds the IP layer with incoming packets.
 | 
			
		||||
 *
 | 
			
		||||
 * @param netif The lwip network interface structure for this slipif
 | 
			
		||||
 */
 | 
			
		||||
void
 | 
			
		||||
slipif_poll(struct netif *netif)
 | 
			
		||||
{
 | 
			
		||||
  u8_t c;
 | 
			
		||||
  struct slipif_priv *priv;
 | 
			
		||||
 | 
			
		||||
  LWIP_ASSERT("netif != NULL", (netif != NULL));
 | 
			
		||||
  LWIP_ASSERT("netif->state != NULL", (netif->state != NULL));
 | 
			
		||||
 | 
			
		||||
  priv = (struct slipif_priv *)netif->state;
 | 
			
		||||
 | 
			
		||||
  while (sio_tryread(priv->sd, &c, 1) > 0) {
 | 
			
		||||
    slipif_rxbyte_input(netif, c);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#if SLIP_RX_FROM_ISR
 | 
			
		||||
/**
 | 
			
		||||
 * @ingroup slipif
 | 
			
		||||
 * Feeds the IP layer with incoming packets that were receive
 | 
			
		||||
 *
 | 
			
		||||
 * @param netif The lwip network interface structure for this slipif
 | 
			
		||||
 */
 | 
			
		||||
void
 | 
			
		||||
slipif_process_rxqueue(struct netif *netif)
 | 
			
		||||
{
 | 
			
		||||
  struct slipif_priv *priv;
 | 
			
		||||
  SYS_ARCH_DECL_PROTECT(old_level);
 | 
			
		||||
 | 
			
		||||
  LWIP_ASSERT("netif != NULL", (netif != NULL));
 | 
			
		||||
  LWIP_ASSERT("netif->state != NULL", (netif->state != NULL));
 | 
			
		||||
 | 
			
		||||
  priv = (struct slipif_priv *)netif->state;
 | 
			
		||||
 | 
			
		||||
  SYS_ARCH_PROTECT(old_level);
 | 
			
		||||
  while (priv->rxpackets != NULL) {
 | 
			
		||||
    struct pbuf *p = priv->rxpackets;
 | 
			
		||||
#if SLIP_RX_QUEUE
 | 
			
		||||
    /* dequeue packet */
 | 
			
		||||
    struct pbuf *q = p;
 | 
			
		||||
    while ((q->len != q->tot_len) && (q->next != NULL)) {
 | 
			
		||||
      q = q->next;
 | 
			
		||||
    }
 | 
			
		||||
    priv->rxpackets = q->next;
 | 
			
		||||
    q->next = NULL;
 | 
			
		||||
#else /* SLIP_RX_QUEUE */
 | 
			
		||||
    priv->rxpackets = NULL;
 | 
			
		||||
#endif /* SLIP_RX_QUEUE */
 | 
			
		||||
    SYS_ARCH_UNPROTECT(old_level);
 | 
			
		||||
    if (netif->input(p, netif) != ERR_OK) {
 | 
			
		||||
      pbuf_free(p);
 | 
			
		||||
    }
 | 
			
		||||
    SYS_ARCH_PROTECT(old_level);
 | 
			
		||||
  }
 | 
			
		||||
  SYS_ARCH_UNPROTECT(old_level);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** Like slipif_rxbyte, but queues completed packets.
 | 
			
		||||
 *
 | 
			
		||||
 * @param netif The lwip network interface structure for this slipif
 | 
			
		||||
 * @param data Received serial byte
 | 
			
		||||
 */
 | 
			
		||||
static void
 | 
			
		||||
slipif_rxbyte_enqueue(struct netif *netif, u8_t data)
 | 
			
		||||
{
 | 
			
		||||
  struct pbuf *p;
 | 
			
		||||
  struct slipif_priv *priv = (struct slipif_priv *)netif->state;
 | 
			
		||||
  SYS_ARCH_DECL_PROTECT(old_level);
 | 
			
		||||
 | 
			
		||||
  p = slipif_rxbyte(netif, data);
 | 
			
		||||
  if (p != NULL) {
 | 
			
		||||
    SYS_ARCH_PROTECT(old_level);
 | 
			
		||||
    if (priv->rxpackets != NULL) {
 | 
			
		||||
#if SLIP_RX_QUEUE
 | 
			
		||||
      /* queue multiple pbufs */
 | 
			
		||||
      struct pbuf *q = p;
 | 
			
		||||
      while (q->next != NULL) {
 | 
			
		||||
        q = q->next;
 | 
			
		||||
      }
 | 
			
		||||
      q->next = p;
 | 
			
		||||
    } else {
 | 
			
		||||
#else /* SLIP_RX_QUEUE */
 | 
			
		||||
      pbuf_free(priv->rxpackets);
 | 
			
		||||
    }
 | 
			
		||||
    {
 | 
			
		||||
#endif /* SLIP_RX_QUEUE */
 | 
			
		||||
      priv->rxpackets = p;
 | 
			
		||||
    }
 | 
			
		||||
    SYS_ARCH_UNPROTECT(old_level);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @ingroup slipif
 | 
			
		||||
 * Process a received byte, completed packets are put on a queue that is
 | 
			
		||||
 * fed into IP through slipif_process_rxqueue().
 | 
			
		||||
 *
 | 
			
		||||
 * This function can be called from ISR if SYS_LIGHTWEIGHT_PROT is enabled.
 | 
			
		||||
 *
 | 
			
		||||
 * @param netif The lwip network interface structure for this slipif
 | 
			
		||||
 * @param data received character
 | 
			
		||||
 */
 | 
			
		||||
void
 | 
			
		||||
slipif_received_byte(struct netif *netif, u8_t data)
 | 
			
		||||
{
 | 
			
		||||
  LWIP_ASSERT("netif != NULL", (netif != NULL));
 | 
			
		||||
  LWIP_ASSERT("netif->state != NULL", (netif->state != NULL));
 | 
			
		||||
  slipif_rxbyte_enqueue(netif, data);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @ingroup slipif
 | 
			
		||||
 * Process multiple received byte, completed packets are put on a queue that is
 | 
			
		||||
 * fed into IP through slipif_process_rxqueue().
 | 
			
		||||
 *
 | 
			
		||||
 * This function can be called from ISR if SYS_LIGHTWEIGHT_PROT is enabled.
 | 
			
		||||
 *
 | 
			
		||||
 * @param netif The lwip network interface structure for this slipif
 | 
			
		||||
 * @param data received character
 | 
			
		||||
 * @param len Number of received characters
 | 
			
		||||
 */
 | 
			
		||||
void
 | 
			
		||||
slipif_received_bytes(struct netif *netif, u8_t *data, u8_t len)
 | 
			
		||||
{
 | 
			
		||||
  u8_t i;
 | 
			
		||||
  u8_t *rxdata = data;
 | 
			
		||||
  LWIP_ASSERT("netif != NULL", (netif != NULL));
 | 
			
		||||
  LWIP_ASSERT("netif->state != NULL", (netif->state != NULL));
 | 
			
		||||
 | 
			
		||||
  for (i = 0; i < len; i++, rxdata++) {
 | 
			
		||||
    slipif_rxbyte_enqueue(netif, *rxdata);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
#endif /* SLIP_RX_FROM_ISR */
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,86 @@
 | 
			
		|||
/**
 | 
			
		||||
 * @file
 | 
			
		||||
 *
 | 
			
		||||
 * SLIP netif API
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (c) 2001, Swedish Institute of Computer Science.
 | 
			
		||||
 * All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * Redistribution and use in source and binary forms, with or without
 | 
			
		||||
 * modification, are permitted provided that the following conditions
 | 
			
		||||
 * are met:
 | 
			
		||||
 * 1. Redistributions of source code must retain the above copyright
 | 
			
		||||
 *    notice, this list of conditions and the following disclaimer.
 | 
			
		||||
 * 2. Redistributions in binary form must reproduce the above copyright
 | 
			
		||||
 *    notice, this list of conditions and the following disclaimer in the
 | 
			
		||||
 *    documentation and/or other materials provided with the distribution.
 | 
			
		||||
 * 3. Neither the name of the Institute nor the names of its contributors
 | 
			
		||||
 *    may be used to endorse or promote products derived from this software
 | 
			
		||||
 *    without specific prior written permission.
 | 
			
		||||
 *
 | 
			
		||||
 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
 | 
			
		||||
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 | 
			
		||||
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 | 
			
		||||
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
 | 
			
		||||
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 | 
			
		||||
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 | 
			
		||||
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 | 
			
		||||
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 | 
			
		||||
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 | 
			
		||||
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 | 
			
		||||
 * SUCH DAMAGE.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is part of the lwIP TCP/IP stack.
 | 
			
		||||
 *
 | 
			
		||||
 * Author: Adam Dunkels <adam@sics.se>
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
#ifndef LWIP_HDR_NETIF_SLIPIF_H
 | 
			
		||||
#define LWIP_HDR_NETIF_SLIPIF_H
 | 
			
		||||
 | 
			
		||||
#include "lwip/opt.h"
 | 
			
		||||
#include "lwip/netif.h"
 | 
			
		||||
 | 
			
		||||
/** Set this to 1 to start a thread that blocks reading on the serial line
 | 
			
		||||
 * (using sio_read()).
 | 
			
		||||
 */
 | 
			
		||||
#ifndef SLIP_USE_RX_THREAD
 | 
			
		||||
#define SLIP_USE_RX_THREAD !NO_SYS
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/** Set this to 1 to enable functions to pass in RX bytes from ISR context.
 | 
			
		||||
 * If enabled, slipif_received_byte[s]() process incoming bytes and put assembled
 | 
			
		||||
 * packets on a queue, which is fed into lwIP from slipif_poll().
 | 
			
		||||
 * If disabled, slipif_poll() polls the serial line (using sio_tryread()).
 | 
			
		||||
 */
 | 
			
		||||
#ifndef SLIP_RX_FROM_ISR
 | 
			
		||||
#define SLIP_RX_FROM_ISR 0
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/** Set this to 1 (default for SLIP_RX_FROM_ISR) to queue incoming packets
 | 
			
		||||
 * received by slipif_received_byte[s]() as long as PBUF_POOL pbufs are available.
 | 
			
		||||
 * If disabled, packets will be dropped if more than one packet is received.
 | 
			
		||||
 */
 | 
			
		||||
#ifndef SLIP_RX_QUEUE
 | 
			
		||||
#define SLIP_RX_QUEUE SLIP_RX_FROM_ISR
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
err_t slipif_init(struct netif * netif);
 | 
			
		||||
void slipif_poll(struct netif *netif);
 | 
			
		||||
#if SLIP_RX_FROM_ISR
 | 
			
		||||
void slipif_process_rxqueue(struct netif *netif);
 | 
			
		||||
void slipif_received_byte(struct netif *netif, u8_t data);
 | 
			
		||||
void slipif_received_bytes(struct netif *netif, u8_t *data, u8_t len);
 | 
			
		||||
#endif /* SLIP_RX_FROM_ISR */
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif /* LWIP_HDR_NETIF_SLIPIF_H */
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,15 @@
 | 
			
		|||
; PlatformIO Project Configuration File
 | 
			
		||||
;
 | 
			
		||||
;   Build options: build flags, source filter
 | 
			
		||||
;   Upload options: custom upload port, speed and extra flags
 | 
			
		||||
;   Library options: dependencies, extra library storages
 | 
			
		||||
;   Advanced options: extra scripting
 | 
			
		||||
;
 | 
			
		||||
; Please visit documentation for the other options and examples
 | 
			
		||||
; https://docs.platformio.org/page/projectconf.html
 | 
			
		||||
 | 
			
		||||
[env:esp12e]
 | 
			
		||||
platform = espressif8266
 | 
			
		||||
board = esp12e
 | 
			
		||||
framework = arduino
 | 
			
		||||
lib_deps =
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,140 @@
 | 
			
		|||
#include <Arduino.h>
 | 
			
		||||
/*
 | 
			
		||||
   Copyright 2016-2019 Bo Zimmerman
 | 
			
		||||
 | 
			
		||||
   Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
   you may not use this file except in compliance with the License.
 | 
			
		||||
   You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
     http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
   Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
   distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
   See the License for the specific language governing permissions and
 | 
			
		||||
   limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
ConnSettings::ConnSettings(int flagBitmap)
 | 
			
		||||
{
 | 
			
		||||
  petscii = (flagBitmap & FLAG_PETSCII) > 0;
 | 
			
		||||
  telnet = (flagBitmap & FLAG_TELNET) > 0;
 | 
			
		||||
  echo = (flagBitmap & FLAG_ECHO) > 0;
 | 
			
		||||
  xonxoff = (flagBitmap & FLAG_XONXOFF) > 0;
 | 
			
		||||
  rtscts = (flagBitmap & FLAG_RTSCTS) > 0;
 | 
			
		||||
  secure = (flagBitmap & FLAG_SECURE) > 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ConnSettings::ConnSettings(const char *dmodifiers)
 | 
			
		||||
{
 | 
			
		||||
  petscii=((strchr(dmodifiers,'p')!=null) || (strchr(dmodifiers,'P')!=null));
 | 
			
		||||
  telnet=((strchr(dmodifiers,'t')!=null) || (strchr(dmodifiers,'T')!=null));
 | 
			
		||||
  echo=((strchr(dmodifiers,'e')!=null) || (strchr(dmodifiers,'E')!=null));
 | 
			
		||||
  xonxoff=((strchr(dmodifiers,'x')!=null) || (strchr(dmodifiers,'X')!=null));
 | 
			
		||||
  rtscts=((strchr(dmodifiers,'r')!=null) || (strchr(dmodifiers,'R')!=null));
 | 
			
		||||
  secure=((strchr(dmodifiers,'s')!=null) || (strchr(dmodifiers,'S')!=null));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ConnSettings::ConnSettings(String modifiers) : ConnSettings(modifiers.c_str())
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int ConnSettings::getBitmap()
 | 
			
		||||
{
 | 
			
		||||
  int flagsBitmap = 0;
 | 
			
		||||
  if(petscii)
 | 
			
		||||
    flagsBitmap = flagsBitmap | FLAG_PETSCII;
 | 
			
		||||
  if(telnet)
 | 
			
		||||
    flagsBitmap = flagsBitmap | FLAG_TELNET;
 | 
			
		||||
  if(echo)
 | 
			
		||||
    flagsBitmap = flagsBitmap | FLAG_ECHO;
 | 
			
		||||
  if(xonxoff)
 | 
			
		||||
    flagsBitmap = flagsBitmap | FLAG_XONXOFF;
 | 
			
		||||
  if(rtscts)
 | 
			
		||||
    flagsBitmap = flagsBitmap | FLAG_RTSCTS;
 | 
			
		||||
  if(secure)
 | 
			
		||||
    flagsBitmap = flagsBitmap | FLAG_SECURE;
 | 
			
		||||
  return flagsBitmap;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int ConnSettings::getBitmap(FlowControlType forceCheck)
 | 
			
		||||
{
 | 
			
		||||
  int flagsBitmap = getBitmap();
 | 
			
		||||
  if(((flagsBitmap & (FLAG_XONXOFF | FLAG_RTSCTS))==0)
 | 
			
		||||
  &&(forceCheck==FCT_RTSCTS))
 | 
			
		||||
    flagsBitmap |= FLAG_RTSCTS;
 | 
			
		||||
  return flagsBitmap;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
String ConnSettings::getFlagString()
 | 
			
		||||
{
 | 
			
		||||
  String lastOptions =(petscii?"p":"");
 | 
			
		||||
  lastOptions += (petscii?"p":"");
 | 
			
		||||
  lastOptions += (telnet?"t":"");
 | 
			
		||||
  lastOptions += (echo?"e":"");
 | 
			
		||||
  lastOptions += (xonxoff?"x":"");
 | 
			
		||||
  lastOptions += (rtscts?"r":"");
 | 
			
		||||
  lastOptions += (secure?"s":"");
 | 
			
		||||
  return lastOptions;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ConnSettings::setFlag(ConnFlag flagMask, boolean newVal)
 | 
			
		||||
{
 | 
			
		||||
  switch(flagMask)
 | 
			
		||||
  {
 | 
			
		||||
    case FLAG_DISCONNECT_ON_EXIT: break;
 | 
			
		||||
    case FLAG_PETSCII: petscii = newVal; break;
 | 
			
		||||
    case FLAG_TELNET: telnet = newVal; break;
 | 
			
		||||
    case FLAG_ECHO: echo = newVal; break;
 | 
			
		||||
    case FLAG_XONXOFF: xonxoff = newVal; break;
 | 
			
		||||
    case FLAG_SECURE: secure = newVal; break;
 | 
			
		||||
    case FLAG_RTSCTS: rtscts = newVal; break;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ConnSettings::IPtoStr(IPAddress *ip, String &str)
 | 
			
		||||
{
 | 
			
		||||
  if(ip == null)
 | 
			
		||||
  {
 | 
			
		||||
    str="";
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
  char temp[20];
 | 
			
		||||
  sprintf(temp,"%d.%d.%d.%d",(*ip)[0],(*ip)[1],(*ip)[2],(*ip)[3]);
 | 
			
		||||
  str = temp;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
IPAddress *ConnSettings::parseIP(const char *ipStr)
 | 
			
		||||
{
 | 
			
		||||
  uint8_t dots[4];
 | 
			
		||||
  int dotDex=0;
 | 
			
		||||
  char *le = (char *)ipStr;
 | 
			
		||||
  const char *ld = ipStr+strlen(ipStr);
 | 
			
		||||
  if(strlen(ipStr)<7)
 | 
			
		||||
    return null;
 | 
			
		||||
  for(char *e=le;e<=ld;e++)
 | 
			
		||||
  {
 | 
			
		||||
    if((*e=='.')||(e==ld))
 | 
			
		||||
    {
 | 
			
		||||
      if(le==e)
 | 
			
		||||
        break;
 | 
			
		||||
      *e=0;
 | 
			
		||||
      String sdot = le;
 | 
			
		||||
      sdot.trim();
 | 
			
		||||
      if((sdot.length()==0)||(dotDex>3))
 | 
			
		||||
      {
 | 
			
		||||
        dotDex=99;
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
      dots[dotDex++]=(uint8_t)atoi(sdot.c_str());
 | 
			
		||||
      if(e==ld)
 | 
			
		||||
        le=e;
 | 
			
		||||
      else
 | 
			
		||||
        le=e+1;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  if((dotDex!=4)||(*le != 0))
 | 
			
		||||
    return null;
 | 
			
		||||
  return new IPAddress(dots[0],dots[1],dots[2],dots[3]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,284 @@
 | 
			
		|||
#include <Arduino.h>
 | 
			
		||||
/*
 | 
			
		||||
   Copyright 2016-2019 Bo Zimmerman
 | 
			
		||||
 | 
			
		||||
   Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
   you may not use this file except in compliance with the License.
 | 
			
		||||
   You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
     http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
   Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
   distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
   See the License for the specific language governing permissions and
 | 
			
		||||
   limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#include <cstdio>
 | 
			
		||||
 | 
			
		||||
static char HD[3];
 | 
			
		||||
static char HDL[17];
 | 
			
		||||
 | 
			
		||||
static unsigned long logStartTime = millis();
 | 
			
		||||
static unsigned long lastLogTime = millis();
 | 
			
		||||
static unsigned long logCurCount = 0;
 | 
			
		||||
static LogOutputState logOutputState = LOS_NADA;
 | 
			
		||||
 | 
			
		||||
static uint8_t FROMHEXDIGIT(uint8_t a1)
 | 
			
		||||
{
 | 
			
		||||
  a1 = lc(a1);
 | 
			
		||||
  if((a1 >= '0')&&(a1 <= '9'))
 | 
			
		||||
    return a1-'0';
 | 
			
		||||
  if((a1 >= 'a')&&(a1 <= 'f'))
 | 
			
		||||
    return 10 + (a1-'a');
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static uint8_t FROMHEX(uint8_t a1, uint8_t a2)
 | 
			
		||||
{
 | 
			
		||||
  return (FROMHEXDIGIT(a1) * 16) + FROMHEXDIGIT(a2);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static char *FROMHEX(const char *hex, char *s, const size_t len)
 | 
			
		||||
{
 | 
			
		||||
  int i=0;
 | 
			
		||||
  for(const char *h=hex;*h != 0 && (*(h+1)!=0) && (i<len-1);i++,h+=2)
 | 
			
		||||
    s[i]=FROMHEX((uint8_t)*h,(uint8_t)*(h+1));
 | 
			
		||||
  s[i]=0;
 | 
			
		||||
  return s;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static uint8_t *FROMHEX(uint8_t *s, const size_t len)
 | 
			
		||||
{
 | 
			
		||||
  int i=0;
 | 
			
		||||
  for(int i=0;i<len;i+=2)
 | 
			
		||||
    s[i/2]=FROMHEX(s[i],s[i+1]);
 | 
			
		||||
  s[i]=0;
 | 
			
		||||
  return s;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static char *TOHEX(const char *s, char *hex, const size_t len)
 | 
			
		||||
{
 | 
			
		||||
  int i=0;
 | 
			
		||||
  for(const char *t=s;*t != 0 && (i<len-2);i+=2,t++)
 | 
			
		||||
  {
 | 
			
		||||
    char *x=TOHEX(*t);
 | 
			
		||||
    hex[i]=x[0];
 | 
			
		||||
    hex[i+1]=x[1];
 | 
			
		||||
  }
 | 
			
		||||
  hex[i]=0;
 | 
			
		||||
  return hex;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static char *TOHEX(uint8_t a)
 | 
			
		||||
{
 | 
			
		||||
  HD[0] = "0123456789ABCDEF"[(a >> 4) & 0x0f];
 | 
			
		||||
  HD[1] = "0123456789ABCDEF"[a & 0x0f];
 | 
			
		||||
  HD[2] = 0;
 | 
			
		||||
  return HD;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static char *tohex(uint8_t a)
 | 
			
		||||
{
 | 
			
		||||
  HD[0] = "0123456789abcdef"[(a >> 4) & 0x0f];
 | 
			
		||||
  HD[1] = "0123456789abcdef"[a & 0x0f];
 | 
			
		||||
  HD[2] = 0;
 | 
			
		||||
  return HD;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static char *TOHEX(unsigned long a)
 | 
			
		||||
{
 | 
			
		||||
  for(int i=7;i>=0;i--)
 | 
			
		||||
  {
 | 
			
		||||
    HDL[i] = "0123456789ABCDEF"[a & 0x0f];
 | 
			
		||||
    a = a >> 4;
 | 
			
		||||
  }
 | 
			
		||||
  HDL[8] = 0;
 | 
			
		||||
  char *H=HDL;
 | 
			
		||||
  if((strlen(H)>2) && (strstr(H,"00")==H))
 | 
			
		||||
    H+=2;
 | 
			
		||||
  return H;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static char *TOHEX(unsigned int a)
 | 
			
		||||
{
 | 
			
		||||
  for(int i=3;i>=0;i--)
 | 
			
		||||
  {
 | 
			
		||||
    HDL[i] = "0123456789ABCDEF"[a & 0x0f];
 | 
			
		||||
    a = a >> 4;
 | 
			
		||||
  }
 | 
			
		||||
  HDL[4] = 0;
 | 
			
		||||
  char *H=HDL;
 | 
			
		||||
  if((strlen(H)>2) && (strstr(H,"00")==H))
 | 
			
		||||
    H+=2;
 | 
			
		||||
  return H;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static char *TOHEX(int a)
 | 
			
		||||
{
 | 
			
		||||
  return TOHEX((unsigned int)a);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static char *TOHEX(long a)
 | 
			
		||||
{
 | 
			
		||||
  return TOHEX((unsigned long)a);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void logInternalOut(const LogOutputState m, const uint8_t c)
 | 
			
		||||
{
 | 
			
		||||
  if(logFileOpen)
 | 
			
		||||
  {
 | 
			
		||||
    if((m != logOutputState)
 | 
			
		||||
    ||(++logCurCount > DBG_BYT_CTR)
 | 
			
		||||
    ||((millis()-lastLogTime)>expectedSerialTime))
 | 
			
		||||
    {
 | 
			
		||||
      logCurCount=0;
 | 
			
		||||
      
 | 
			
		||||
      logOutputState = m;
 | 
			
		||||
      rawLogPrintln("");
 | 
			
		||||
      switch(m)
 | 
			
		||||
      {
 | 
			
		||||
      case LOS_NADA:
 | 
			
		||||
        break;
 | 
			
		||||
      case LOS_SocketIn:
 | 
			
		||||
        rawLogPrintf("%s SocI: ",TOHEX(millis()-logStartTime));
 | 
			
		||||
        break;
 | 
			
		||||
      case LOS_SocketOut:
 | 
			
		||||
        rawLogPrintf("%s SocO: ",TOHEX(millis()-logStartTime));
 | 
			
		||||
        break;
 | 
			
		||||
      case LOS_SerialIn:
 | 
			
		||||
        rawLogPrintf("%s SerI: ",TOHEX(millis()-logStartTime));
 | 
			
		||||
        break;
 | 
			
		||||
      case LOS_SerialOut:
 | 
			
		||||
        rawLogPrintf("%s SerO: ",TOHEX(millis()-logStartTime));
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    lastLogTime=millis();
 | 
			
		||||
    rawLogPrint(TOHEX(c));
 | 
			
		||||
    rawLogPrint(" ");
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void logSerialOut(const uint8_t c)
 | 
			
		||||
{
 | 
			
		||||
  logInternalOut(LOS_SerialOut,c);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void logSocketOut(const uint8_t c)
 | 
			
		||||
{
 | 
			
		||||
  logInternalOut(LOS_SocketOut,c);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void logSerialIn(const uint8_t c)
 | 
			
		||||
{
 | 
			
		||||
  logInternalOut(LOS_SerialIn,c);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void logSocketIn(const uint8_t c)
 | 
			
		||||
{
 | 
			
		||||
  logInternalOut(LOS_SocketIn,c);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void logSocketIn(const uint8_t *c, int n)
 | 
			
		||||
{
 | 
			
		||||
  if(logFileOpen)
 | 
			
		||||
  {
 | 
			
		||||
    for(int i=0;i<n;i++)
 | 
			
		||||
      logInternalOut(LOS_SocketIn,c[i]);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void rawLogPrintf(const char* format, ...)
 | 
			
		||||
{
 | 
			
		||||
  int ret;
 | 
			
		||||
  va_list arglist;
 | 
			
		||||
  va_start(arglist, format);
 | 
			
		||||
  vsnprintf(FBUF,sizeof(FBUF), format, arglist);
 | 
			
		||||
  rawLogPrint(FBUF);
 | 
			
		||||
  va_end(arglist);
 | 
			
		||||
  
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void rawLogPrint(const char* str)
 | 
			
		||||
{
 | 
			
		||||
  if(logFileDebug)
 | 
			
		||||
    debugPrintf(str);
 | 
			
		||||
  else
 | 
			
		||||
    logFile.print(str);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void rawLogPrintln(const char* str)
 | 
			
		||||
{
 | 
			
		||||
  if(logFileDebug)
 | 
			
		||||
  {
 | 
			
		||||
    debugPrintf(str);
 | 
			
		||||
    debugPrintf("\n");
 | 
			
		||||
  }
 | 
			
		||||
  else
 | 
			
		||||
    logFile.println(str);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void logPrintfln(const char* format, ...) 
 | 
			
		||||
{
 | 
			
		||||
  if(logFileOpen)
 | 
			
		||||
  {
 | 
			
		||||
    if(logOutputState != LOS_NADA)
 | 
			
		||||
    {
 | 
			
		||||
      rawLogPrintln("");
 | 
			
		||||
      logOutputState = LOS_NADA;
 | 
			
		||||
    }
 | 
			
		||||
    int ret;
 | 
			
		||||
    va_list arglist;
 | 
			
		||||
    va_start(arglist, format);
 | 
			
		||||
    vsnprintf(FBUF,sizeof(FBUF), format, arglist);
 | 
			
		||||
    rawLogPrintln(FBUF);
 | 
			
		||||
    va_end(arglist);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void logPrintf(const char* format, ...) 
 | 
			
		||||
{
 | 
			
		||||
  if(logFileOpen)
 | 
			
		||||
  {
 | 
			
		||||
    if(logOutputState != LOS_NADA)
 | 
			
		||||
    {
 | 
			
		||||
      rawLogPrintln("");
 | 
			
		||||
      logOutputState = LOS_NADA;
 | 
			
		||||
    }
 | 
			
		||||
    int ret;
 | 
			
		||||
    va_list arglist;
 | 
			
		||||
    va_start(arglist, format);
 | 
			
		||||
    vsnprintf(FBUF, sizeof(FBUF), format, arglist);
 | 
			
		||||
    rawLogPrint(FBUF);
 | 
			
		||||
    va_end(arglist);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void logPrint(const char* msg)
 | 
			
		||||
{
 | 
			
		||||
  if(logFileOpen)
 | 
			
		||||
  {
 | 
			
		||||
    if(logOutputState != LOS_NADA)
 | 
			
		||||
    {
 | 
			
		||||
      rawLogPrintln("");
 | 
			
		||||
      logOutputState = LOS_NADA;
 | 
			
		||||
    }
 | 
			
		||||
    rawLogPrint(msg);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void logPrintln(const char* msg)
 | 
			
		||||
{
 | 
			
		||||
  if(logFileOpen)
 | 
			
		||||
  {
 | 
			
		||||
    if(logOutputState != LOS_NADA)
 | 
			
		||||
    {
 | 
			
		||||
      rawLogPrintln("");
 | 
			
		||||
      logOutputState = LOS_NADA;
 | 
			
		||||
    }
 | 
			
		||||
    rawLogPrintln(msg);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,350 @@
 | 
			
		|||
#include <Arduino.h>
 | 
			
		||||
/*
 | 
			
		||||
   Copyright 2016-2019 Bo Zimmerman
 | 
			
		||||
 | 
			
		||||
   Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
   you may not use this file except in compliance with the License.
 | 
			
		||||
   You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
	   http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
   Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
   distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
   See the License for the specific language governing permissions and
 | 
			
		||||
   limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
// courtesy Craig Bruce, 1995
 | 
			
		||||
 | 
			
		||||
unsigned char petToAscTable[256] PROGMEM = {
 | 
			
		||||
0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x14,0x09,0x0d,0x11,0x93,0x0a,0x0e,0x0f,
 | 
			
		||||
0x10,0x0b,0x12,0x13,0x08,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
 | 
			
		||||
0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
 | 
			
		||||
0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
 | 
			
		||||
0x40,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
 | 
			
		||||
0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x5b,0x5c,0x5d,0x5e,0x5f,
 | 
			
		||||
0x60,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
 | 
			
		||||
0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x7b,0x7c,0x7d,0x7e,0x7f,
 | 
			
		||||
0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
 | 
			
		||||
0x90,0x91,0x92,0x0c,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f,
 | 
			
		||||
0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
 | 
			
		||||
0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
 | 
			
		||||
0x60,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
 | 
			
		||||
0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0xda,0xdb,0xdc,0xdd,0xde,0xdf,
 | 
			
		||||
0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
 | 
			
		||||
0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
unsigned char ascToPetTable[256] PROGMEM = {
 | 
			
		||||
0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x14,0x20,0x0a,0x11,0x93,0x0d,0x0e,0x0f,
 | 
			
		||||
0x10,0x0b,0x12,0x13,0x08,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
 | 
			
		||||
0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
 | 
			
		||||
0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
 | 
			
		||||
0x40,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,
 | 
			
		||||
0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0x5b,0x5c,0x5d,0x5e,0x5f,
 | 
			
		||||
0xc0,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
 | 
			
		||||
0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0xdb,0xdc,0xdd,0xde,0xdf,
 | 
			
		||||
0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
 | 
			
		||||
0x90,0x91,0x92,0x0c,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f,
 | 
			
		||||
0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
 | 
			
		||||
0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
 | 
			
		||||
0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,
 | 
			
		||||
0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,
 | 
			
		||||
0xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
 | 
			
		||||
0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define TELNET_BINARY 0 
 | 
			
		||||
  /** TELNET CODE: echo */
 | 
			
		||||
#define TELNET_ECHO 1 
 | 
			
		||||
  /** TELNET CODE: echo */
 | 
			
		||||
#define TELNET_LOGOUT 18 
 | 
			
		||||
  /** TELNET CODE: supress go ahead*/
 | 
			
		||||
#define TELNET_SUPRESS_GO_AHEAD 3 
 | 
			
		||||
  /** TELNET CODE: sending terminal type*/
 | 
			
		||||
#define TELNET_TERMTYPE 24 
 | 
			
		||||
  /** TELNET CODE: Negotiate About Window Size.*/
 | 
			
		||||
#define TELNET_NAWS 31 
 | 
			
		||||
  /** TELNET CODE: Remote Flow Control.*/
 | 
			
		||||
#define TELNET_TOGGLE_FLOW_CONTROL 33 
 | 
			
		||||
  /** TELNET CODE: Linemode*/
 | 
			
		||||
#define TELNET_LINEMODE 34 
 | 
			
		||||
  /** TELNET CODE: MSDP protocol*/
 | 
			
		||||
#define TELNET_MSDP 69 
 | 
			
		||||
  /** TELNET CODE: MSSP Server Status protocol*/
 | 
			
		||||
#define TELNET_MSSP 70 
 | 
			
		||||
  /** TELNET CODE: text compression, protocol 1*/
 | 
			
		||||
#define TELNET_COMPRESS 85 
 | 
			
		||||
  /** TELNET CODE: text compression, protocol 2*/
 | 
			
		||||
#define TELNET_COMPRESS2 86 
 | 
			
		||||
  /** TELNET CODE: MSP SOund protocol*/
 | 
			
		||||
#define TELNET_MSP 90 
 | 
			
		||||
  /** TELNET CODE: MXP Extended protocol*/
 | 
			
		||||
#define TELNET_MXP 91 
 | 
			
		||||
  /** TELNET CODE: AARD protocol*/
 | 
			
		||||
#define TELNET_AARD 102 
 | 
			
		||||
  /** TELNET CODE: End of subnegotiation parameters*/
 | 
			
		||||
#define TELNET_SE 240 
 | 
			
		||||
  /** TELNET CODE: Are You There*/
 | 
			
		||||
#define TELNET_AYT 246 
 | 
			
		||||
  /** TELNET CODE: Erase character*/
 | 
			
		||||
#define TELNET_EC 247 
 | 
			
		||||
  /** TELNET CODE: ATCP protocol*/
 | 
			
		||||
#define TELNET_ATCP 200 
 | 
			
		||||
  /** TELNET CODE: GMCP protocol*/
 | 
			
		||||
#define TELNET_GMCP 201 
 | 
			
		||||
  /** TELNET CODE: Indicates that what follows is subnegotiation of the indicated option*/
 | 
			
		||||
#define TELNET_SB 250 
 | 
			
		||||
  /** TELNET CODE: Indicates the desire to begin performing, or confirmation that you are now performing, the indicated option*/
 | 
			
		||||
#define TELNET_WILL 251 
 | 
			
		||||
  /** TELNET CODE: Indicates the refusal to perform, or continue performing, the indicated option*/
 | 
			
		||||
#define TELNET_WONT 252 
 | 
			
		||||
  /** TELNET CODE: Indicates the request that the other party perform, or confirmation that you are expecting the other party to perform, the indicated option*/
 | 
			
		||||
#define TELNET_DO 253 
 | 
			
		||||
  /** TELNET CODE: 253 doubles as fake ansi telnet code*/
 | 
			
		||||
#define TELNET_ANSI 253 
 | 
			
		||||
  /** TELNET CODE: Indicates the demand that the other party stop performing, or confirmation that you are no longer expecting the other party to perform, the indicated option.*/
 | 
			
		||||
#define TELNET_DONT 254 
 | 
			
		||||
  /** TELNET CODE: Indicates that the other party can go ahead and transmit -- I'm done.*/
 | 
			
		||||
#define TELNET_GA 249 
 | 
			
		||||
  /** TELNET CODE: Indicates that there is nothing to do?*/
 | 
			
		||||
#define TELNET_NOP 241 
 | 
			
		||||
  /** TELNET CODE: IAC*/
 | 
			
		||||
#define TELNET_IAC 255 
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
uint8_t streamAvailRead(Stream *stream)
 | 
			
		||||
{
 | 
			
		||||
  int ct=0;
 | 
			
		||||
  while((stream->available()==0)
 | 
			
		||||
  &&(ct++)<250)
 | 
			
		||||
    delay(1);
 | 
			
		||||
  return stream->read();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool handleAsciiIAC(char *c, Stream *stream)
 | 
			
		||||
{
 | 
			
		||||
  if(*c == 255)
 | 
			
		||||
  {
 | 
			
		||||
    *c=streamAvailRead(stream);
 | 
			
		||||
    logSocketIn(*c);
 | 
			
		||||
    if(*c==TELNET_IAC)
 | 
			
		||||
    {
 | 
			
		||||
      *c = 255;
 | 
			
		||||
      return true;
 | 
			
		||||
    }
 | 
			
		||||
    if(*c==TELNET_WILL)
 | 
			
		||||
    {
 | 
			
		||||
      char what=streamAvailRead(stream);
 | 
			
		||||
      logSocketIn(what);
 | 
			
		||||
      uint8_t iacDont[] = {TELNET_IAC, TELNET_DONT, what};
 | 
			
		||||
      if(what == TELNET_TERMTYPE)
 | 
			
		||||
        iacDont[1] = TELNET_DO;
 | 
			
		||||
      for(int i=0;i<3;i++)
 | 
			
		||||
        logSocketOut(iacDont[i]);
 | 
			
		||||
      stream->write(iacDont,3);
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
    if(*c==TELNET_DONT)
 | 
			
		||||
    {
 | 
			
		||||
      char what=streamAvailRead(stream);
 | 
			
		||||
      logSocketIn(what);
 | 
			
		||||
      uint8_t iacWont[] = {TELNET_IAC, TELNET_WONT, what};
 | 
			
		||||
      for(int i=0;i<3;i++)
 | 
			
		||||
        logSocketOut(iacWont[i]);
 | 
			
		||||
      stream->write(iacWont,3);
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
    if(*c==TELNET_WONT)
 | 
			
		||||
    {
 | 
			
		||||
      char what=streamAvailRead(stream);
 | 
			
		||||
      logSocketIn(what);
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
    if(*c==TELNET_DO)
 | 
			
		||||
    {
 | 
			
		||||
      char what=streamAvailRead(stream);
 | 
			
		||||
      logSocketIn(what);
 | 
			
		||||
      uint8_t iacWont[] = {TELNET_IAC, TELNET_WONT, what};
 | 
			
		||||
      if(what == TELNET_TERMTYPE)
 | 
			
		||||
        iacWont[1] = TELNET_WILL;
 | 
			
		||||
      for(int i=0;i<3;i++)
 | 
			
		||||
        logSocketOut(iacWont[i]);
 | 
			
		||||
      stream->write(iacWont,3);
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
    if(*c==TELNET_SB)
 | 
			
		||||
    {
 | 
			
		||||
      char what=streamAvailRead(stream);
 | 
			
		||||
      logSocketIn(what);
 | 
			
		||||
      char lastC=*c;
 | 
			
		||||
      while(((lastC!=TELNET_IAC)||(*c!=TELNET_SE))&&(*c>=0))
 | 
			
		||||
      {
 | 
			
		||||
        lastC=*c;
 | 
			
		||||
        *c=streamAvailRead(stream);
 | 
			
		||||
        logSocketIn(*c);
 | 
			
		||||
      }
 | 
			
		||||
      if(what == TELNET_TERMTYPE)
 | 
			
		||||
      {
 | 
			
		||||
        int respLen = termType.length() + 6;
 | 
			
		||||
        uint8_t buf[respLen];
 | 
			
		||||
        buf[0]=TELNET_IAC;
 | 
			
		||||
        buf[1]=TELNET_SB;
 | 
			
		||||
        buf[2]=TELNET_TERMTYPE;
 | 
			
		||||
        buf[3]=(uint8_t)0;
 | 
			
		||||
        sprintf((char *)buf+4,termType.c_str());
 | 
			
		||||
        buf[respLen-2]=TELNET_IAC;
 | 
			
		||||
        buf[respLen-1]=TELNET_SE;
 | 
			
		||||
        for(int i=0;i<respLen;i++)
 | 
			
		||||
          logSocketOut(buf[i]);
 | 
			
		||||
        stream->write(buf,respLen);
 | 
			
		||||
        return false;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool ansiColorToPetsciiColor(char *c, Stream *stream)
 | 
			
		||||
{
 | 
			
		||||
  if(*c == 27)
 | 
			
		||||
  {
 | 
			
		||||
    *c=streamAvailRead(stream);
 | 
			
		||||
    logSocketIn(*c);
 | 
			
		||||
    if(*c=='[')
 | 
			
		||||
    {
 | 
			
		||||
      int code1=0;
 | 
			
		||||
      int code2=-1;
 | 
			
		||||
      *c=streamAvailRead(stream);
 | 
			
		||||
      logSocketIn(*c);
 | 
			
		||||
      while((*c>='0')&&(*c<='9'))
 | 
			
		||||
      {
 | 
			
		||||
        code1=(code1*10) + (*c-'0');
 | 
			
		||||
        *c=streamAvailRead(stream);
 | 
			
		||||
        logSocketIn(*c);
 | 
			
		||||
      }
 | 
			
		||||
      while(*c==';')
 | 
			
		||||
      {
 | 
			
		||||
        *c=streamAvailRead(stream);
 | 
			
		||||
        logSocketIn(*c);
 | 
			
		||||
        if((*c>='0')&&(*c<='9'))
 | 
			
		||||
          code2=0;
 | 
			
		||||
        while((*c>='0')&&(*c<='9'))
 | 
			
		||||
        {
 | 
			
		||||
          code2=(code2*10) + (*c-'0');
 | 
			
		||||
          *c=streamAvailRead(stream);
 | 
			
		||||
          logSocketIn(*c);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      switch(code1)
 | 
			
		||||
      {
 | 
			
		||||
      case 0:
 | 
			
		||||
        // dark...
 | 
			
		||||
        switch(code2)
 | 
			
		||||
        {
 | 
			
		||||
        case -1:
 | 
			
		||||
        case 0:
 | 
			
		||||
          *c=  146; // rvs off
 | 
			
		||||
          return true;
 | 
			
		||||
        case 30: // black
 | 
			
		||||
          *c=  155;//144;
 | 
			
		||||
          return true;
 | 
			
		||||
        case 31: // red
 | 
			
		||||
          *c=  28;
 | 
			
		||||
          return true;
 | 
			
		||||
        case 32: // green
 | 
			
		||||
          *c=  30;
 | 
			
		||||
          return true;
 | 
			
		||||
        case 33: // yellow
 | 
			
		||||
          *c=  129;
 | 
			
		||||
          return true;
 | 
			
		||||
        case 34: // blue
 | 
			
		||||
          *c=  31;
 | 
			
		||||
          return true;
 | 
			
		||||
        case 35: // purple
 | 
			
		||||
          *c=  149;
 | 
			
		||||
          return true;
 | 
			
		||||
        case 36: // cyan
 | 
			
		||||
          *c=  152;
 | 
			
		||||
          return true;
 | 
			
		||||
        case 37: // white/grey
 | 
			
		||||
        default: 
 | 
			
		||||
          *c= 155;
 | 
			
		||||
          return true;
 | 
			
		||||
        }
 | 
			
		||||
        break;
 | 
			
		||||
      case 1:
 | 
			
		||||
        // light..
 | 
			
		||||
        switch(code2)
 | 
			
		||||
        {
 | 
			
		||||
        case -1:/* bold */ 
 | 
			
		||||
          *c=  0;
 | 
			
		||||
          return true;
 | 
			
		||||
        case 0:
 | 
			
		||||
          *c=  146; // rvs off
 | 
			
		||||
          return true;
 | 
			
		||||
        case 30: // black
 | 
			
		||||
          *c=  151;
 | 
			
		||||
          return true;
 | 
			
		||||
        case 31: // red
 | 
			
		||||
          *c=  150;
 | 
			
		||||
          return true;
 | 
			
		||||
        case 32: // green
 | 
			
		||||
          *c=  153;
 | 
			
		||||
          return true;
 | 
			
		||||
        case 33: // yellow
 | 
			
		||||
          *c=  158;
 | 
			
		||||
          return true;
 | 
			
		||||
        case 34: // blue
 | 
			
		||||
          *c=  154;
 | 
			
		||||
          return true;
 | 
			
		||||
        case 35: // purple
 | 
			
		||||
          *c=  156;
 | 
			
		||||
          return true;
 | 
			
		||||
        case 36: // cyan
 | 
			
		||||
          *c=  159;
 | 
			
		||||
          return true;
 | 
			
		||||
        case 37: // white/grey
 | 
			
		||||
        default: 
 | 
			
		||||
          *c=  5;
 | 
			
		||||
          return true;
 | 
			
		||||
        }
 | 
			
		||||
        break;
 | 
			
		||||
      case 2: /*?*/
 | 
			
		||||
      case 3: /*?*/
 | 
			
		||||
      case 4: /*underline*/
 | 
			
		||||
      case 5: /*blink*/
 | 
			
		||||
      case 6: /*italics*/
 | 
			
		||||
        *c=0;
 | 
			
		||||
        return true;
 | 
			
		||||
      case 40: case 41: case 42: case 43: case 44: 
 | 
			
		||||
      case 45: case 46: case 47: case 48: case 49:
 | 
			
		||||
        *c=18; // rvs on
 | 
			
		||||
        return true;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    *c = 0;
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
  return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
char petToAsc(char c)
 | 
			
		||||
{
 | 
			
		||||
  return pgm_read_byte_near(petToAscTable + (int)c);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool ascToPet(char *c, Stream *stream)
 | 
			
		||||
{
 | 
			
		||||
  if(!ansiColorToPetsciiColor(c,stream))
 | 
			
		||||
    *c = pgm_read_byte_near(ascToPetTable + (int)(*c));
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
char ascToPetcii(char c)
 | 
			
		||||
{
 | 
			
		||||
  return pgm_read_byte_near(ascToPetTable + (int)c);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,191 @@
 | 
			
		|||
#include <Arduino.h>
 | 
			
		||||
/*
 | 
			
		||||
   Copyright 2016-2019 Bo Zimmerman
 | 
			
		||||
 | 
			
		||||
   Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
   you may not use this file except in compliance with the License.
 | 
			
		||||
   You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
	   http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
   Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
   distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
   See the License for the specific language governing permissions and
 | 
			
		||||
   limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
PhoneBookEntry::PhoneBookEntry(unsigned long phnum, const char *addr, const char *mod, const char *note)
 | 
			
		||||
{
 | 
			
		||||
  number=phnum;
 | 
			
		||||
  address = new char[strlen(addr)+1];
 | 
			
		||||
  strcpy((char *)address,addr);
 | 
			
		||||
  modifiers = new char[strlen(mod)+1];
 | 
			
		||||
  strcpy((char *)modifiers,mod);
 | 
			
		||||
  notes = new char[strlen(note)+1];
 | 
			
		||||
  strcpy((char *)notes,note);
 | 
			
		||||
  
 | 
			
		||||
  if(phonebook == null)
 | 
			
		||||
  {
 | 
			
		||||
    phonebook = this;
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
  PhoneBookEntry *last = phonebook;
 | 
			
		||||
  if(last->number > number)
 | 
			
		||||
  {
 | 
			
		||||
    phonebook = this;
 | 
			
		||||
    next = last;
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
  while(last->next != null)
 | 
			
		||||
  {
 | 
			
		||||
    if(last->next->number > number)
 | 
			
		||||
    {
 | 
			
		||||
      next = last->next;
 | 
			
		||||
      last->next = this;
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    last = last->next;
 | 
			
		||||
  }
 | 
			
		||||
  last->next = this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PhoneBookEntry::~PhoneBookEntry()
 | 
			
		||||
{
 | 
			
		||||
  if(phonebook == this)
 | 
			
		||||
    phonebook = next;
 | 
			
		||||
  else
 | 
			
		||||
  {
 | 
			
		||||
    PhoneBookEntry *last = phonebook;
 | 
			
		||||
    while((last != null) && (last->next != this)) // don't change this!
 | 
			
		||||
      last = last->next;
 | 
			
		||||
    if(last != null)
 | 
			
		||||
      last->next = next;
 | 
			
		||||
  }
 | 
			
		||||
  freeCharArray((char **)&address);
 | 
			
		||||
  freeCharArray((char **)&modifiers);
 | 
			
		||||
  freeCharArray((char **)¬es);
 | 
			
		||||
  next=null;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void PhoneBookEntry::loadPhonebook()
 | 
			
		||||
{
 | 
			
		||||
  clearPhonebook();
 | 
			
		||||
  if(SPIFFS.exists("/zphonebook.txt"))
 | 
			
		||||
  {
 | 
			
		||||
    File f = SPIFFS.open("/zphonebook.txt", "r");
 | 
			
		||||
    while(f.available()>0)
 | 
			
		||||
    {
 | 
			
		||||
      String str="";
 | 
			
		||||
      char c=f.read();
 | 
			
		||||
      while((c != '\n') && (f.available()>0))
 | 
			
		||||
      {
 | 
			
		||||
        str += c;
 | 
			
		||||
        c=f.read();
 | 
			
		||||
      }
 | 
			
		||||
      int argn=0;
 | 
			
		||||
      String configArguments[4];
 | 
			
		||||
      for(int i=0;i<4;i++)
 | 
			
		||||
        configArguments[i]="";
 | 
			
		||||
      for(int i=0;i<str.length();i++)
 | 
			
		||||
      {
 | 
			
		||||
        if((str[i]==',')&&(argn<=2))
 | 
			
		||||
          argn++;
 | 
			
		||||
        else
 | 
			
		||||
          configArguments[argn] += str[i];
 | 
			
		||||
      }
 | 
			
		||||
      PhoneBookEntry *phb = new PhoneBookEntry(atol(configArguments[0].c_str()),configArguments[1].c_str(),configArguments[2].c_str(),configArguments[3].c_str());
 | 
			
		||||
    }
 | 
			
		||||
    f.close();
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool PhoneBookEntry::checkPhonebookEntry(String cmd)
 | 
			
		||||
{
 | 
			
		||||
    const char *vbuf=(char *)cmd.c_str();
 | 
			
		||||
    bool error = false;
 | 
			
		||||
    for(char *cptr=(char *)vbuf;*cptr!=0;cptr++)
 | 
			
		||||
    {
 | 
			
		||||
      if(strchr("0123456789",*cptr) < 0)
 | 
			
		||||
      {
 | 
			
		||||
        error =true;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    if(error || (strlen((char *)vbuf)>9))
 | 
			
		||||
      return false;
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PhoneBookEntry *PhoneBookEntry::findPhonebookEntry(long number)
 | 
			
		||||
{
 | 
			
		||||
  PhoneBookEntry *p = phonebook;
 | 
			
		||||
  while(p != null)
 | 
			
		||||
  {
 | 
			
		||||
    if(p->number == number)
 | 
			
		||||
      return p;
 | 
			
		||||
    p=p->next;
 | 
			
		||||
  }
 | 
			
		||||
  return null;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PhoneBookEntry *PhoneBookEntry::findPhonebookEntry(String number)
 | 
			
		||||
{
 | 
			
		||||
  if(!checkPhonebookEntry(number))
 | 
			
		||||
    return null;
 | 
			
		||||
  return findPhonebookEntry(atol(number.c_str()));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void PhoneBookEntry::clearPhonebook()
 | 
			
		||||
{
 | 
			
		||||
  PhoneBookEntry *phb = phonebook;
 | 
			
		||||
  while(phonebook != null)
 | 
			
		||||
    delete phonebook;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void PhoneBookEntry::savePhonebook()
 | 
			
		||||
{
 | 
			
		||||
  SPIFFS.remove("/zphonebook.txt");
 | 
			
		||||
  delay(500);
 | 
			
		||||
  File f = SPIFFS.open("/zphonebook.txt", "w");
 | 
			
		||||
  int ct=0;
 | 
			
		||||
  PhoneBookEntry *phb=phonebook;
 | 
			
		||||
  while(phb != null)
 | 
			
		||||
  {
 | 
			
		||||
    f.printf("%ul,%s,%s,%s\n",phb->number,phb->address,phb->modifiers,phb->notes);
 | 
			
		||||
    phb = phb->next;
 | 
			
		||||
    ct++;
 | 
			
		||||
  }
 | 
			
		||||
  f.close();
 | 
			
		||||
  delay(500);
 | 
			
		||||
  if(SPIFFS.exists("/zphonebook.txt"))
 | 
			
		||||
  {
 | 
			
		||||
    File f = SPIFFS.open("/zphonebook.txt", "r");
 | 
			
		||||
    while(f.available()>0)
 | 
			
		||||
    {
 | 
			
		||||
      String str="";
 | 
			
		||||
      char c=f.read();
 | 
			
		||||
      while((c != '\n') && (f.available()>0))
 | 
			
		||||
      {
 | 
			
		||||
        str += c;
 | 
			
		||||
        c=f.read();
 | 
			
		||||
      }
 | 
			
		||||
      int argn=0;
 | 
			
		||||
      if(str.length()>0)
 | 
			
		||||
      {
 | 
			
		||||
        for(int i=0;i<str.length();i++)
 | 
			
		||||
        {
 | 
			
		||||
          if((str[i]==',')&&(argn<=2))
 | 
			
		||||
            argn++;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      if(argn!=3)
 | 
			
		||||
      {
 | 
			
		||||
        delay(100);
 | 
			
		||||
        f.close();
 | 
			
		||||
        savePhonebook();
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    f.close();
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,542 @@
 | 
			
		|||
#include <Arduino.h>
 | 
			
		||||
/*
 | 
			
		||||
   Copyright 2018-2019 Bo Zimmerman
 | 
			
		||||
 | 
			
		||||
   Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
   you may not use this file except in compliance with the License.
 | 
			
		||||
   You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
     http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
   Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
   distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
   See the License for the specific language governing permissions and
 | 
			
		||||
   limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
#ifdef INCLUDE_SD_SHELL
 | 
			
		||||
 | 
			
		||||
FTPHost::~FTPHost()
 | 
			
		||||
{
 | 
			
		||||
  freeCharArray(&hostIp);
 | 
			
		||||
  freeCharArray(&username);
 | 
			
		||||
  freeCharArray(&pw);
 | 
			
		||||
  freeCharArray(&path);
 | 
			
		||||
  freeCharArray(&file);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool FTPHost::doGet(FS *fs, const char *localpath, const char *remotepath)
 | 
			
		||||
{
 | 
			
		||||
  fixPath(remotepath);
 | 
			
		||||
  return doFTPGet(fs,hostIp,port,localpath,file,username,pw,doSSL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool FTPHost::doPut(File &f, const char *remotepath)
 | 
			
		||||
{
 | 
			
		||||
  fixPath(remotepath);
 | 
			
		||||
  return doFTPPut(f,hostIp,port,file,username,pw,doSSL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool FTPHost::doLS(ZSerial *serial, const char *remotepath)
 | 
			
		||||
{
 | 
			
		||||
  fixPath(remotepath);
 | 
			
		||||
  bool kaplah = doFTPLS(serial,hostIp,port,file,username,pw,doSSL);
 | 
			
		||||
  if((kaplah) 
 | 
			
		||||
  && (strcmp(file,path) != 0)
 | 
			
		||||
  && (strlen(file)>0))
 | 
			
		||||
  {
 | 
			
		||||
    if(file[strlen(file)-1]=='/')
 | 
			
		||||
      setCharArray(&path, file);
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
      char buf[strlen(file)+2];
 | 
			
		||||
      sprintf(buf,"%s/",file);
 | 
			
		||||
      setCharArray(&path, buf);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  return kaplah;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void FTPHost::fixPath(const char *remotepath)
 | 
			
		||||
{
 | 
			
		||||
  if(remotepath == 0)
 | 
			
		||||
    return;
 | 
			
		||||
  char *end = strrchr(remotepath, '/');
 | 
			
		||||
  int buflen = ((path == 0) ? 0 : strlen(path)) + strlen(remotepath) + 3;
 | 
			
		||||
  char fbuf[buflen];
 | 
			
		||||
  char pbuf[buflen];
 | 
			
		||||
  if(remotepath[0] == '/')
 | 
			
		||||
  {
 | 
			
		||||
    strcpy(fbuf, remotepath);
 | 
			
		||||
    if(end > 0)
 | 
			
		||||
    {
 | 
			
		||||
      *end = 0;
 | 
			
		||||
      sprintf(pbuf,"%s/",remotepath);
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
      strcpy(pbuf, "/");
 | 
			
		||||
  }
 | 
			
		||||
  else
 | 
			
		||||
  {
 | 
			
		||||
    sprintf(fbuf,"%s%s",path,remotepath);
 | 
			
		||||
    if(end > 0)
 | 
			
		||||
    {
 | 
			
		||||
      *end = 0;
 | 
			
		||||
      sprintf(pbuf,"%s%s/",path,remotepath);
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
      strcpy(pbuf, path);
 | 
			
		||||
  }
 | 
			
		||||
  setCharArray(&path, pbuf);
 | 
			
		||||
  setCharArray(&file, fbuf);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool FTPHost::parseUrl(uint8_t *vbuf, char **req)
 | 
			
		||||
{
 | 
			
		||||
  char *newHostIp;
 | 
			
		||||
  int newPort;
 | 
			
		||||
  bool newDoSSL;
 | 
			
		||||
  char *newUsername;
 | 
			
		||||
  char *newPassword;
 | 
			
		||||
  if(parseFTPUrl(vbuf,&newHostIp,req,&newPort,&newDoSSL,&newUsername,&newPassword))
 | 
			
		||||
  {
 | 
			
		||||
    setCharArray(&hostIp,newHostIp);
 | 
			
		||||
    port = newPort;
 | 
			
		||||
    doSSL = newDoSSL;
 | 
			
		||||
    setCharArray(&username,newUsername);
 | 
			
		||||
    setCharArray(&pw,newPassword);
 | 
			
		||||
    setCharArray(&path,"/");
 | 
			
		||||
    setCharArray(&file,"");
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
  return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
FTPHost *makeFTPHost(bool isUrl, FTPHost *host, uint8_t *buf, char **req)
 | 
			
		||||
{
 | 
			
		||||
  if(isUrl)
 | 
			
		||||
  {
 | 
			
		||||
    if(host != 0)
 | 
			
		||||
      delete host;
 | 
			
		||||
    host = new FTPHost();
 | 
			
		||||
    if(!(host->parseUrl(buf,req)))
 | 
			
		||||
    {
 | 
			
		||||
      delete host;
 | 
			
		||||
      host=0;
 | 
			
		||||
      *req=0;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  else
 | 
			
		||||
    *req=(char *)buf;
 | 
			
		||||
  return host;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool parseFTPUrl(uint8_t *vbuf, char **hostIp, char **req, int *port, bool *doSSL, char **username, char **pw)
 | 
			
		||||
{
 | 
			
		||||
  *doSSL = false;
 | 
			
		||||
  if(strstr((char *)vbuf,"ftp:")==(char *)vbuf)
 | 
			
		||||
    vbuf = vbuf + 4;
 | 
			
		||||
  else
 | 
			
		||||
  if(strstr((char *)vbuf,"ftps:")==(char *)vbuf)
 | 
			
		||||
  {
 | 
			
		||||
    vbuf = vbuf + 5;
 | 
			
		||||
    *doSSL = true;
 | 
			
		||||
  }
 | 
			
		||||
  while(*vbuf == '/')
 | 
			
		||||
    vbuf++;
 | 
			
		||||
 | 
			
		||||
  *port= 21;
 | 
			
		||||
  *hostIp = (char *)vbuf;
 | 
			
		||||
  char *atSign=strchr((char *)vbuf,'@');
 | 
			
		||||
  *username=NULL;
 | 
			
		||||
  *pw = NULL;
 | 
			
		||||
  if(atSign != NULL)
 | 
			
		||||
  {
 | 
			
		||||
    *hostIp = atSign + 1;
 | 
			
		||||
    *atSign = 0;
 | 
			
		||||
    *username = (char *)vbuf;
 | 
			
		||||
    vbuf = (uint8_t *)(atSign + 1);
 | 
			
		||||
    char *pwB = strchr(*username, ':');
 | 
			
		||||
    if(pwB != NULL)
 | 
			
		||||
    {
 | 
			
		||||
      *pw = pwB+1;
 | 
			
		||||
      *pwB=0;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  char *portB=strchr((char *)vbuf,':');
 | 
			
		||||
  int len=strlen((char *)vbuf);
 | 
			
		||||
  *req = strchr((char *)vbuf,'/');
 | 
			
		||||
  if(*req != NULL)
 | 
			
		||||
  {
 | 
			
		||||
    *(*req)=0;
 | 
			
		||||
    if((*req) != (char *)(vbuf+len-1))
 | 
			
		||||
      (*req)++;
 | 
			
		||||
  }
 | 
			
		||||
  else
 | 
			
		||||
    *req = (char *)(vbuf + len);
 | 
			
		||||
  if(portB != NULL)
 | 
			
		||||
  {
 | 
			
		||||
     *portB = 0;
 | 
			
		||||
     portB++;
 | 
			
		||||
     *port = atoi(portB);
 | 
			
		||||
     if(port <= 0)
 | 
			
		||||
       return ZERROR;
 | 
			
		||||
  }
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool doFTPQuit(WiFiClient **c)
 | 
			
		||||
{
 | 
			
		||||
  if((*c)->connected())
 | 
			
		||||
  {
 | 
			
		||||
    (*c)->printf("QUIT\r\n");
 | 
			
		||||
    delay(500);
 | 
			
		||||
  }
 | 
			
		||||
  (*c)->stop();
 | 
			
		||||
  delete (*c);
 | 
			
		||||
  return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static String readLine(WiFiClient *c, int timeout)
 | 
			
		||||
{
 | 
			
		||||
  unsigned long now=millis();
 | 
			
		||||
  String line = "";
 | 
			
		||||
  while(((millis()-now < timeout) || (c->available()>0)) 
 | 
			
		||||
  && (c->connected()|| (c->available()>0)))
 | 
			
		||||
  {
 | 
			
		||||
    yield();
 | 
			
		||||
    if(c->available()>0)
 | 
			
		||||
    {
 | 
			
		||||
      char ch=c->read();
 | 
			
		||||
      if((ch=='\n')||(ch=='\r'))
 | 
			
		||||
      {
 | 
			
		||||
          if(line.length()>0)
 | 
			
		||||
            return line;
 | 
			
		||||
      }
 | 
			
		||||
      else
 | 
			
		||||
      if((ch >= 32 ) && (ch <= 127))
 | 
			
		||||
        line += ch;
 | 
			
		||||
      now=millis();
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  return line;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int getFTPResponseCode(WiFiClient *c, char *buf)
 | 
			
		||||
{
 | 
			
		||||
  String resp = readLine(c,5000);
 | 
			
		||||
  if(resp.length() == 0)
 | 
			
		||||
    return -1; // timeout total
 | 
			
		||||
  while((resp.length()<3)
 | 
			
		||||
      ||(resp[0] < '0')||(resp[0] > '9')
 | 
			
		||||
      ||(resp[1] < '0')||(resp[1] > '9')
 | 
			
		||||
      ||(resp[2] < '0')||(resp[2] > '9'))
 | 
			
		||||
  {
 | 
			
		||||
      yield();
 | 
			
		||||
      resp = readLine(c,1000);
 | 
			
		||||
      if(resp.length()==0)
 | 
			
		||||
        return -1;
 | 
			
		||||
  }
 | 
			
		||||
  if((buf != NULL)&&(resp.length()<132))
 | 
			
		||||
    strcpy(buf,resp.substring(4).c_str());
 | 
			
		||||
  return atoi(resp.substring(0,3).c_str());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void readBytesToSilence(WiFiClient *cc)
 | 
			
		||||
{
 | 
			
		||||
  unsigned long now = millis(); // just eat the intro for 1 second of silence
 | 
			
		||||
  while(millis()-now < 1000)
 | 
			
		||||
  {
 | 
			
		||||
    yield();
 | 
			
		||||
    if(cc->available()>0)
 | 
			
		||||
    {
 | 
			
		||||
      cc->read();
 | 
			
		||||
      now=millis();
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool doFTPGet(FS *fs, const char *hostIp, int port, const char *localpath, const char *remotepath, const char *username, const char *pw, const bool doSSL)
 | 
			
		||||
{
 | 
			
		||||
  WiFiClient *cc = createWiFiClient(doSSL);
 | 
			
		||||
  if(WiFi.status() != WL_CONNECTED)
 | 
			
		||||
    return false;
 | 
			
		||||
  if(!cc->connect(hostIp, port))
 | 
			
		||||
    return doFTPQuit(&cc);
 | 
			
		||||
  cc->setNoDelay(DEFAULT_NO_DELAY);
 | 
			
		||||
  readBytesToSilence(cc);
 | 
			
		||||
  if(username == NULL)
 | 
			
		||||
    cc->printf("USER anonymous\r\n");
 | 
			
		||||
  else
 | 
			
		||||
    cc->printf("USER %s\r\n",username);
 | 
			
		||||
  int respCode = getFTPResponseCode(cc, NULL);
 | 
			
		||||
  if(respCode != 331)
 | 
			
		||||
    return doFTPQuit(&cc);
 | 
			
		||||
  if(pw == NULL)
 | 
			
		||||
    cc->printf("PASS zimodem@zimtime.net\r\n");
 | 
			
		||||
  else
 | 
			
		||||
    cc->printf("PASS %s\r\n",pw);
 | 
			
		||||
  respCode = getFTPResponseCode(cc, NULL);
 | 
			
		||||
  if(respCode != 230)
 | 
			
		||||
    return doFTPQuit(&cc);
 | 
			
		||||
  readBytesToSilence(cc);
 | 
			
		||||
  cc->printf("TYPE I\r\n");
 | 
			
		||||
  respCode = getFTPResponseCode(cc, NULL);
 | 
			
		||||
  if(respCode < 0)
 | 
			
		||||
    return doFTPQuit(&cc);
 | 
			
		||||
  char ipbuf[129];
 | 
			
		||||
  cc->printf("PASV\r\n");
 | 
			
		||||
  respCode = getFTPResponseCode(cc, ipbuf);
 | 
			
		||||
  if(respCode != 227)
 | 
			
		||||
    return doFTPQuit(&cc);
 | 
			
		||||
  // now parse the pasv result in .* (ipv4,ipv4,ipv4,ipv4,
 | 
			
		||||
  char *ipptr = strchr(ipbuf,'(');
 | 
			
		||||
  while((ipptr != NULL) && (strchr(ipptr+1,'(')!= NULL))
 | 
			
		||||
    ipptr=strchr(ipptr+1,'(');
 | 
			
		||||
  if(ipptr == NULL)
 | 
			
		||||
    return doFTPQuit(&cc);
 | 
			
		||||
  int digitCount=0;
 | 
			
		||||
  int digits[10];
 | 
			
		||||
  char *commaPtr=strchr(ipptr+1,',');
 | 
			
		||||
  while((commaPtr != NULL)&&(digitCount < 10))
 | 
			
		||||
  {
 | 
			
		||||
    *commaPtr = 0;
 | 
			
		||||
    digits[digitCount++] = atoi(ipptr+1);
 | 
			
		||||
    ipptr=commaPtr;
 | 
			
		||||
    commaPtr=strchr(ipptr+1,',');
 | 
			
		||||
    if(commaPtr == NULL)
 | 
			
		||||
      commaPtr=strchr(ipptr+1,')');
 | 
			
		||||
  }
 | 
			
		||||
  if(digitCount < 6)
 | 
			
		||||
    return doFTPQuit(&cc);
 | 
			
		||||
  sprintf(ipbuf,"%d.%d.%d.%d",digits[0],digits[1],digits[2],digits[3]);
 | 
			
		||||
  int dataPort = (256 * digits[4]) + digits[5];
 | 
			
		||||
  // ok, now we are ready for DATA!
 | 
			
		||||
  if(WiFi.status() != WL_CONNECTED)
 | 
			
		||||
    return doFTPQuit(&cc);
 | 
			
		||||
  WiFiClient *c = createWiFiClient(doSSL);
 | 
			
		||||
  if(!c->connect(ipbuf, dataPort))
 | 
			
		||||
  {
 | 
			
		||||
    doFTPQuit(&c);
 | 
			
		||||
    return doFTPQuit(&cc);
 | 
			
		||||
  }
 | 
			
		||||
  c->setNoDelay(DEFAULT_NO_DELAY);
 | 
			
		||||
  cc->printf("RETR %s\r\n",remotepath);
 | 
			
		||||
  respCode = getFTPResponseCode(cc, NULL);
 | 
			
		||||
  if((respCode < 0)||(respCode > 400))
 | 
			
		||||
    return doFTPQuit(&cc);
 | 
			
		||||
  File f = fs->open(localpath, "w");
 | 
			
		||||
  unsigned long now=millis();
 | 
			
		||||
  while((c->connected()||(c->available()>0)) 
 | 
			
		||||
  && ((millis()-now) < 30000)) // loop for data, with nice long timeout
 | 
			
		||||
  {
 | 
			
		||||
    if(c->available()>=0)
 | 
			
		||||
    {
 | 
			
		||||
      now=millis();
 | 
			
		||||
      uint8_t ch=c->read();
 | 
			
		||||
      //logSocketIn(ch); // this is ALSO not socket input!
 | 
			
		||||
      f.write(ch);
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
      yield();
 | 
			
		||||
  }
 | 
			
		||||
  f.flush();
 | 
			
		||||
  f.close();
 | 
			
		||||
  c->stop();
 | 
			
		||||
  delete c;
 | 
			
		||||
  doFTPQuit(&cc);
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool doFTPPut(File &f, const char *hostIp, int port, const char *remotepath, const char *username, const char *pw, const bool doSSL)
 | 
			
		||||
{
 | 
			
		||||
  WiFiClient *cc = createWiFiClient(doSSL);
 | 
			
		||||
  if(WiFi.status() != WL_CONNECTED)
 | 
			
		||||
    return false;
 | 
			
		||||
  if(!cc->connect(hostIp, port))
 | 
			
		||||
    return doFTPQuit(&cc);
 | 
			
		||||
  cc->setNoDelay(DEFAULT_NO_DELAY);
 | 
			
		||||
  readBytesToSilence(cc);
 | 
			
		||||
  if(username == NULL)
 | 
			
		||||
    cc->printf("USER anonymous\r\n");
 | 
			
		||||
  else
 | 
			
		||||
    cc->printf("USER %s\r\n",username);
 | 
			
		||||
  int respCode = getFTPResponseCode(cc, NULL);
 | 
			
		||||
  if(respCode != 331)
 | 
			
		||||
    return doFTPQuit(&cc);
 | 
			
		||||
  if(pw == NULL)
 | 
			
		||||
    cc->printf("PASS zimodem@zimtime.net\r\n");
 | 
			
		||||
  else
 | 
			
		||||
    cc->printf("PASS %s\r\n",pw);
 | 
			
		||||
  respCode = getFTPResponseCode(cc, NULL);
 | 
			
		||||
  if(respCode != 230)
 | 
			
		||||
    return doFTPQuit(&cc);
 | 
			
		||||
  readBytesToSilence(cc);
 | 
			
		||||
  cc->printf("TYPE I\r\n");
 | 
			
		||||
  respCode = getFTPResponseCode(cc, NULL);
 | 
			
		||||
  if(respCode < 0)
 | 
			
		||||
    return doFTPQuit(&cc);
 | 
			
		||||
  char ipbuf[129];
 | 
			
		||||
  cc->printf("PASV\r\n");
 | 
			
		||||
  debugPrintf("PASV\r\n");
 | 
			
		||||
  respCode = getFTPResponseCode(cc, ipbuf);
 | 
			
		||||
  if(respCode != 227)
 | 
			
		||||
    return doFTPQuit(&cc);
 | 
			
		||||
  // now parse the pasv result in .* (ipv4,ipv4,ipv4,ipv4,
 | 
			
		||||
  char *ipptr = strchr(ipbuf,'(');
 | 
			
		||||
  while((ipptr != NULL) && (strchr(ipptr+1,'(')!= NULL))
 | 
			
		||||
    ipptr=strchr(ipptr+1,'(');
 | 
			
		||||
  if(ipptr == NULL)
 | 
			
		||||
    return doFTPQuit(&cc);
 | 
			
		||||
  int digitCount=0;
 | 
			
		||||
  int digits[10];
 | 
			
		||||
  char *commaPtr=strchr(ipptr+1,',');
 | 
			
		||||
  while((commaPtr != NULL)&&(digitCount < 10))
 | 
			
		||||
  {
 | 
			
		||||
    *commaPtr = 0;
 | 
			
		||||
    digits[digitCount++] = atoi(ipptr+1);
 | 
			
		||||
    ipptr=commaPtr;
 | 
			
		||||
    commaPtr=strchr(ipptr+1,',');
 | 
			
		||||
    if(commaPtr == NULL)
 | 
			
		||||
      commaPtr=strchr(ipptr+1,')');
 | 
			
		||||
  }
 | 
			
		||||
  if(digitCount < 6)
 | 
			
		||||
    return doFTPQuit(&cc);
 | 
			
		||||
  sprintf(ipbuf,"%d.%d.%d.%d",digits[0],digits[1],digits[2],digits[3]);
 | 
			
		||||
  debugPrintf(ipbuf,"%d.%d.%d.%d",digits[0],digits[1],digits[2],digits[3]);
 | 
			
		||||
  int dataPort = (256 * digits[4]) + digits[5];
 | 
			
		||||
  // ok, now we are ready for DATA!
 | 
			
		||||
  if(WiFi.status() != WL_CONNECTED)
 | 
			
		||||
    return doFTPQuit(&cc);
 | 
			
		||||
  WiFiClient *c = createWiFiClient(doSSL);
 | 
			
		||||
  if(!c->connect(ipbuf, dataPort))
 | 
			
		||||
  {
 | 
			
		||||
    doFTPQuit(&c);
 | 
			
		||||
    return doFTPQuit(&cc);
 | 
			
		||||
  }
 | 
			
		||||
  c->setNoDelay(DEFAULT_NO_DELAY);
 | 
			
		||||
  debugPrintf(" STOR %s\r\n",remotepath);
 | 
			
		||||
  cc->printf("STOR %s\r\n",remotepath);
 | 
			
		||||
  respCode = getFTPResponseCode(cc, NULL);
 | 
			
		||||
  if((respCode < 0)||(respCode > 400))
 | 
			
		||||
    return doFTPQuit(&cc);
 | 
			
		||||
  unsigned long now=millis();
 | 
			
		||||
  debugPrintf(" Storing... %d\r\n",f.available());
 | 
			
		||||
  while((c->connected()) 
 | 
			
		||||
  && (f.available()>0) && ((millis()-now) < 30000)) // loop for data, with nice long timeout
 | 
			
		||||
  {
 | 
			
		||||
    if(f.available()>=0)
 | 
			
		||||
    {
 | 
			
		||||
      now=millis();
 | 
			
		||||
      uint8_t ch=f.read();
 | 
			
		||||
      //logSocketIn(ch); // this is ALSO not socket input!
 | 
			
		||||
      c->write(ch);
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
      yield();
 | 
			
		||||
  }
 | 
			
		||||
  debugPrintf("FPUT: Done\r\n");
 | 
			
		||||
  c->flush();
 | 
			
		||||
  c->stop();
 | 
			
		||||
  delete c;
 | 
			
		||||
  doFTPQuit(&cc);
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool doFTPLS(ZSerial *serial, const char *hostIp, int port, const char *remotepath, const char *username, const char *pw, const bool doSSL)
 | 
			
		||||
{
 | 
			
		||||
  WiFiClient *cc = createWiFiClient(doSSL);
 | 
			
		||||
  if(WiFi.status() != WL_CONNECTED)
 | 
			
		||||
    return false;
 | 
			
		||||
  if(!cc->connect(hostIp, port))
 | 
			
		||||
    return doFTPQuit(&cc);
 | 
			
		||||
  cc->setNoDelay(DEFAULT_NO_DELAY);
 | 
			
		||||
  readBytesToSilence(cc);
 | 
			
		||||
  if(username == NULL)
 | 
			
		||||
    cc->printf("USER anonymous\r\n");
 | 
			
		||||
  else
 | 
			
		||||
    cc->printf("USER %s\r\n",username);
 | 
			
		||||
  int respCode = getFTPResponseCode(cc, NULL);
 | 
			
		||||
  if(respCode != 331)
 | 
			
		||||
    return doFTPQuit(&cc);
 | 
			
		||||
  if(pw == NULL)
 | 
			
		||||
    cc->printf("PASS zimodem@zimtime.net\r\n");
 | 
			
		||||
  else
 | 
			
		||||
    cc->printf("PASS %s\r\n",pw);
 | 
			
		||||
  respCode = getFTPResponseCode(cc, NULL);
 | 
			
		||||
  if(respCode != 230)
 | 
			
		||||
    return doFTPQuit(&cc);
 | 
			
		||||
  readBytesToSilence(cc);
 | 
			
		||||
  cc->printf("TYPE A\r\n");
 | 
			
		||||
  respCode = getFTPResponseCode(cc, NULL);
 | 
			
		||||
  if(respCode < 0)
 | 
			
		||||
    return doFTPQuit(&cc);
 | 
			
		||||
  if((remotepath != NULL)&& (*remotepath != NULL))
 | 
			
		||||
  {
 | 
			
		||||
    cc->printf("CWD %s\r\n",remotepath);
 | 
			
		||||
    respCode = getFTPResponseCode(cc, NULL);
 | 
			
		||||
    if((respCode < 0)||(respCode > 400))
 | 
			
		||||
      return doFTPQuit(&cc);
 | 
			
		||||
    readBytesToSilence(cc);
 | 
			
		||||
  }
 | 
			
		||||
  char ipbuf[129];
 | 
			
		||||
  cc->printf("PASV\r\n");
 | 
			
		||||
  respCode = getFTPResponseCode(cc, ipbuf);
 | 
			
		||||
  if(respCode != 227)
 | 
			
		||||
    return doFTPQuit(&cc);
 | 
			
		||||
  // now parse the pasv result in .* (ipv4,ipv4,ipv4,ipv4,
 | 
			
		||||
  char *ipptr = strchr(ipbuf,'(');
 | 
			
		||||
  while((ipptr != NULL) && (strchr(ipptr+1,'(')!= NULL))
 | 
			
		||||
    ipptr=strchr(ipptr+1,'(');
 | 
			
		||||
  if(ipptr == NULL)
 | 
			
		||||
    return doFTPQuit(&cc);
 | 
			
		||||
  int digitCount=0;
 | 
			
		||||
  int digits[10];
 | 
			
		||||
  char *commaPtr=strchr(ipptr+1,',');
 | 
			
		||||
  while((commaPtr != NULL)&&(digitCount < 10))
 | 
			
		||||
  {
 | 
			
		||||
    *commaPtr = 0;
 | 
			
		||||
    digits[digitCount++] = atoi(ipptr+1);
 | 
			
		||||
    ipptr=commaPtr;
 | 
			
		||||
    commaPtr=strchr(ipptr+1,',');
 | 
			
		||||
    if(commaPtr == NULL)
 | 
			
		||||
      commaPtr=strchr(ipptr+1,')');
 | 
			
		||||
  }
 | 
			
		||||
  if(digitCount < 6)
 | 
			
		||||
    return doFTPQuit(&cc);
 | 
			
		||||
  sprintf(ipbuf,"%d.%d.%d.%d",digits[0],digits[1],digits[2],digits[3]);
 | 
			
		||||
  int dataPort = (256 * digits[4]) + digits[5];
 | 
			
		||||
  // ok, now we are ready for DATA!
 | 
			
		||||
  if(WiFi.status() != WL_CONNECTED)
 | 
			
		||||
    return doFTPQuit(&cc);
 | 
			
		||||
  WiFiClient *c = createWiFiClient(doSSL);
 | 
			
		||||
  if(!c->connect(ipbuf, dataPort))
 | 
			
		||||
  {
 | 
			
		||||
    doFTPQuit(&c);
 | 
			
		||||
    return doFTPQuit(&cc);
 | 
			
		||||
  }
 | 
			
		||||
  c->setNoDelay(DEFAULT_NO_DELAY);
 | 
			
		||||
  cc->printf("LIST\r\n",remotepath);
 | 
			
		||||
  respCode = getFTPResponseCode(cc, NULL);
 | 
			
		||||
  if((respCode < 0)||(respCode > 400))
 | 
			
		||||
    return doFTPQuit(&cc);
 | 
			
		||||
  unsigned long now=millis();
 | 
			
		||||
  while((c->connected()||(c->available()>0)) 
 | 
			
		||||
  && ((millis()-now) < 30000)) // loop for data, with nice long timeout
 | 
			
		||||
  {
 | 
			
		||||
    if(c->available()>=0)
 | 
			
		||||
    {
 | 
			
		||||
      now=millis();
 | 
			
		||||
      uint8_t ch=c->read();
 | 
			
		||||
      //logSocketIn(ch); // this is ALSO not socket input!
 | 
			
		||||
      serial->print((char)ch);
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
      yield();
 | 
			
		||||
  }
 | 
			
		||||
  c->stop();
 | 
			
		||||
  delete c;
 | 
			
		||||
  doFTPQuit(&cc);
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,691 @@
 | 
			
		|||
#include <Arduino.h>
 | 
			
		||||
#ifdef INCLUDE_SD_SHELL
 | 
			
		||||
#ifdef INCLUDE_HOSTCM
 | 
			
		||||
/* Converted from Rob Ferguson's code by Bo Zimmerman 
 | 
			
		||||
 * 
 | 
			
		||||
 * Copyright (c) 2013, Robert Ferguson All rights reserved.
 | 
			
		||||
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS 
 | 
			
		||||
 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 
 | 
			
		||||
 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 
 | 
			
		||||
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
 | 
			
		||||
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 
 | 
			
		||||
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 
 | 
			
		||||
 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 
 | 
			
		||||
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
char *basename(char *path)
 | 
			
		||||
{
 | 
			
		||||
  char *base = strrchr(path, '/');
 | 
			
		||||
  return base ? base+1 : path;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
char *dirname(char *path)
 | 
			
		||||
{
 | 
			
		||||
  char *base = strrchr(path, '/');
 | 
			
		||||
  if(base)
 | 
			
		||||
  {
 | 
			
		||||
    *base = 0;
 | 
			
		||||
    return path;
 | 
			
		||||
  }
 | 
			
		||||
  return "";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
HostCM::HostCM(FS *fs)
 | 
			
		||||
{
 | 
			
		||||
  hFS = fs;
 | 
			
		||||
  for(int i=0;i<HCM_MAXFN;i++)
 | 
			
		||||
  {
 | 
			
		||||
    files[i].f = (File)0;
 | 
			
		||||
    files[i].descriptor = 'A' + i;
 | 
			
		||||
    delFileEntry(&files[i]);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
HostCM::~HostCM()
 | 
			
		||||
{
 | 
			
		||||
  closeAllFiles();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
bool HostCM::closeAllFiles()
 | 
			
		||||
{
 | 
			
		||||
  for(int i=0;i<HCM_MAXFN;i++)
 | 
			
		||||
    delFileEntry(&files[i]);
 | 
			
		||||
  if(renameF != 0)
 | 
			
		||||
    renameF.close();
 | 
			
		||||
  renameF = (File)0;
 | 
			
		||||
  if(openDirF != 0)
 | 
			
		||||
    openDirF.close();
 | 
			
		||||
  openDirF = (File)0;
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
HCMFile *HostCM::addNewFileEntry()
 | 
			
		||||
{
 | 
			
		||||
  for(int i=0;i<HCM_MAXFN;i++)
 | 
			
		||||
  {
 | 
			
		||||
    if(files[i].f == 0)
 | 
			
		||||
      return &files[i];
 | 
			
		||||
  }
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void HostCM::delFileEntry(HCMFile *e)
 | 
			
		||||
{
 | 
			
		||||
  if(e->f != 0)
 | 
			
		||||
    e->f.close();
 | 
			
		||||
  char d = e->descriptor;
 | 
			
		||||
  memset(e,sizeof(struct _HCMFile),0);
 | 
			
		||||
  e->descriptor = d;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
HCMFile *HostCM::getFileByDescriptor(char c)
 | 
			
		||||
{
 | 
			
		||||
  for(int i=0;i<HCM_MAXFN;i++)
 | 
			
		||||
  {
 | 
			
		||||
    if(files[i].descriptor == c)
 | 
			
		||||
      return &files[i];
 | 
			
		||||
  }
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int HostCM::numOpenFiles()
 | 
			
		||||
{
 | 
			
		||||
  int n=0;
 | 
			
		||||
  for(int i=0;i<HCM_MAXFN;i++)
 | 
			
		||||
  {
 | 
			
		||||
    if(files[i].f != 0)
 | 
			
		||||
      n++;
 | 
			
		||||
  }
 | 
			
		||||
  return n;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void HostCM::checkDoPlusPlusPlus(const int c, const unsigned long tm)
 | 
			
		||||
{
 | 
			
		||||
  if(c == '+')
 | 
			
		||||
  {
 | 
			
		||||
      if((plussesInARow>0)||((tm-lastNonPlusTm)>800))
 | 
			
		||||
      {
 | 
			
		||||
        plussesInARow++;
 | 
			
		||||
        if(plussesInARow > 2)
 | 
			
		||||
          plusTimeExpire = tm + 800;
 | 
			
		||||
      }
 | 
			
		||||
  }
 | 
			
		||||
  else
 | 
			
		||||
  {
 | 
			
		||||
    plusTimeExpire = 0;
 | 
			
		||||
    lastNonPlusTm = tm;
 | 
			
		||||
    plussesInARow = 0;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool HostCM::checkPlusPlusPlusExpire(const unsigned long tm)
 | 
			
		||||
{
 | 
			
		||||
  if(aborted)
 | 
			
		||||
    return true;
 | 
			
		||||
  if((plusTimeExpire>0)&&(tm>plusTimeExpire)&&(plussesInARow>2))
 | 
			
		||||
  {
 | 
			
		||||
    aborted = true;
 | 
			
		||||
    plusTimeExpire = 0;
 | 
			
		||||
    lastNonPlusTm = tm;
 | 
			
		||||
    plussesInARow = 0;
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
  return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool HostCM::isAborted()
 | 
			
		||||
{
 | 
			
		||||
  return aborted;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void HostCM::protoCloseFile()
 | 
			
		||||
{
 | 
			
		||||
  HCMFile *h = getFileByDescriptor((char)inbuf[1]);
 | 
			
		||||
  if (h==0) {
 | 
			
		||||
    sendError("error: invalid descriptor %c", inbuf[1]);
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  if (h->f == 0)
 | 
			
		||||
  {
 | 
			
		||||
    sendError("error: file not open %c", inbuf[1]); // should this be an error though?
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
  delFileEntry(h);
 | 
			
		||||
  sendACK();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void HostCM::protoPutToFile()
 | 
			
		||||
{
 | 
			
		||||
  HCMFile *h = getFileByDescriptor((char)inbuf[1]);
 | 
			
		||||
  if (h==0) {
 | 
			
		||||
    sendError("error: invalid descriptor %c", inbuf[1]);
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
  uint8_t eor = (uint8_t)lc((char)inbuf[2]);
 | 
			
		||||
  if (h->f == 0)
 | 
			
		||||
  {
 | 
			
		||||
    sendError("error: file not open %c", inbuf[1]);
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
  /*if((h->mode)=='r')||(h->mode=='l'))
 | 
			
		||||
  {
 | 
			
		||||
    sendError("error: read-only file %c", inbuf[1]);
 | 
			
		||||
    return;
 | 
			
		||||
  }*/
 | 
			
		||||
  if(h->format == 'b') 
 | 
			
		||||
  {
 | 
			
		||||
    FROMHEX(&inbuf[3], idex - 4);
 | 
			
		||||
    idex = ((idex - 4) / 2) + 4;
 | 
			
		||||
  }
 | 
			
		||||
  if((eor=='z')
 | 
			
		||||
  &&((h->format == 't')
 | 
			
		||||
     ||(h->type != 'f')))
 | 
			
		||||
  {
 | 
			
		||||
    inbuf[idex-1] = opt.lineend;
 | 
			
		||||
    idex++;
 | 
			
		||||
  } 
 | 
			
		||||
  if(h->f.write(&inbuf[3],idex-4) != idex-4)
 | 
			
		||||
  {
 | 
			
		||||
    sendError("error: write failed to file %c", inbuf[1]);
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
  sendACK();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void HostCM::protoGetFileBytes()
 | 
			
		||||
{
 | 
			
		||||
  int c;
 | 
			
		||||
  HCMFile *h = getFileByDescriptor((char)inbuf[1]);
 | 
			
		||||
  if (h==0) 
 | 
			
		||||
  {
 | 
			
		||||
    sendError("error: invalid descriptor %c", inbuf[1]);
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
  if((h->f == 0)
 | 
			
		||||
  ||((h->mode != 'r') && (h->mode != 'u') && (h->mode != 'l')))
 | 
			
		||||
  {
 | 
			
		||||
    sendError("error: file not open/readable %c", inbuf[1]);
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  odex = 0;
 | 
			
		||||
  outbuf[odex++] = opt.response;
 | 
			
		||||
  if(h->format == 't')
 | 
			
		||||
  {
 | 
			
		||||
    outbuf[odex++] = 'b';
 | 
			
		||||
    outbuf[odex] = 'z';
 | 
			
		||||
    do
 | 
			
		||||
    {
 | 
			
		||||
      odex++;
 | 
			
		||||
      c = h->f.read();
 | 
			
		||||
      outbuf[odex] = (uint8_t)(c & 0xff);
 | 
			
		||||
    }
 | 
			
		||||
    while((c >= 0) && (odex < (HCM_SENDBUF - 2)) && (outbuf[odex] != 0xd));
 | 
			
		||||
    
 | 
			
		||||
    if(c<0)
 | 
			
		||||
    {
 | 
			
		||||
      outbuf[1] = 'e';
 | 
			
		||||
      outbuf[2] = checksum(&outbuf[1], 1);
 | 
			
		||||
      odex=3; // abandon anything between EOL and EOF
 | 
			
		||||
    }
 | 
			
		||||
    else 
 | 
			
		||||
    {
 | 
			
		||||
      if (odex >= (HCM_SENDBUF - 2))
 | 
			
		||||
        outbuf[2] = 'n';
 | 
			
		||||
      outbuf[odex] = checksum(&outbuf[1], odex - 1);
 | 
			
		||||
      odex++;
 | 
			
		||||
    }
 | 
			
		||||
  } 
 | 
			
		||||
  else 
 | 
			
		||||
  if (h->format == 'b') 
 | 
			
		||||
  {
 | 
			
		||||
    int rdcount = HCM_SENDBUF;
 | 
			
		||||
    char eor = 'n';
 | 
			
		||||
    if(h->reclen)
 | 
			
		||||
    {
 | 
			
		||||
      if (h->reclen < HCM_SENDBUF) 
 | 
			
		||||
      {
 | 
			
		||||
        rdcount = h->reclen;
 | 
			
		||||
        eor = 'z';
 | 
			
		||||
      } 
 | 
			
		||||
      else 
 | 
			
		||||
      {
 | 
			
		||||
        int pos = h->f.position();
 | 
			
		||||
        if((pos & h->reclen) > ((pos + rdcount) & h->reclen))
 | 
			
		||||
        {
 | 
			
		||||
          rdcount = ((pos + rdcount) / h->reclen) * h->reclen - pos;
 | 
			
		||||
          eor = 'z';
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    uint8_t rdbuf[rdcount];
 | 
			
		||||
    int n = h->f.read(rdbuf, rdcount);
 | 
			
		||||
    if (n <= 0) 
 | 
			
		||||
    {
 | 
			
		||||
      outbuf[odex++] = 'e';
 | 
			
		||||
      outbuf[odex] = checksum(&outbuf[1], odex - 1);
 | 
			
		||||
      odex++;
 | 
			
		||||
    } 
 | 
			
		||||
    else 
 | 
			
		||||
    {
 | 
			
		||||
      outbuf[odex++] = 'b';
 | 
			
		||||
      outbuf[odex++] = eor;
 | 
			
		||||
      for(int i=0;i<n;i++)
 | 
			
		||||
        memcpy(TOHEX(rdbuf[i]), &outbuf[odex+(i*2)], 2);
 | 
			
		||||
      odex += n * 2;
 | 
			
		||||
      outbuf[odex] = checksum(&outbuf[1], odex - 1);
 | 
			
		||||
      odex++;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  outbuf[odex++] = opt.lineend;
 | 
			
		||||
  outbuf[odex++] = opt.prompt;
 | 
			
		||||
  hserial.write(outbuf, odex);
 | 
			
		||||
  hserial.flush();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void HostCM::protoOpenFile()
 | 
			
		||||
{
 | 
			
		||||
  uint8_t *eobuf = inbuf + idex;
 | 
			
		||||
  int n=numOpenFiles();
 | 
			
		||||
  if(n >= HCM_MAXFN)
 | 
			
		||||
  {
 | 
			
		||||
    sendError("error: too many open files");
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
  if(idex<8)
 | 
			
		||||
  {
 | 
			
		||||
    sendError("error: command too short");
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
  uint8_t mode = (uint8_t)lc((char)inbuf[1]);
 | 
			
		||||
  if(strchr("rlwsua",(char)mode)==0)
 | 
			
		||||
  {
 | 
			
		||||
    sendError("error: illegal mode %c",(char)mode);
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
  bool isRead = strchr("rl",(char)mode)!=0;
 | 
			
		||||
  uint8_t format = (uint8_t)lc((char)inbuf[2]);
 | 
			
		||||
  uint8_t *ptr = (uint8_t *)memchr(inbuf+3, '(', idex-3);
 | 
			
		||||
  if(ptr == 0)
 | 
			
		||||
  {
 | 
			
		||||
    sendError("error: missing (");
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
  uint8_t type = (uint8_t)lc((char)ptr[1]);
 | 
			
		||||
  uint8_t reclen = 0;
 | 
			
		||||
  if(ptr[2]==':')
 | 
			
		||||
    reclen=atoi((char *)(ptr+3));
 | 
			
		||||
  ptr = (uint8_t *)memchr(ptr+2, ')', eobuf-(ptr+1));
 | 
			
		||||
  if(ptr == 0)
 | 
			
		||||
  {
 | 
			
		||||
    sendError("error: missing )");
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
  inbuf[idex - 1] = 0; 
 | 
			
		||||
  uint8_t *fnptr = ptr + 1;
 | 
			
		||||
  HCMFile *newF = addNewFileEntry();
 | 
			
		||||
  if (type == 'f')
 | 
			
		||||
  {
 | 
			
		||||
    char *bn = basename((char *)ptr+1);
 | 
			
		||||
    char *dn = dirname((char *)ptr+1);
 | 
			
		||||
    if(reclen == 0)
 | 
			
		||||
      reclen = 80;
 | 
			
		||||
    snprintf(newF->filename, sizeof(newF->filename), "%s/(f:%d)%s", dn, reclen, bn);
 | 
			
		||||
  } 
 | 
			
		||||
  else
 | 
			
		||||
    strncpy(newF->filename, (char *)ptr+1, sizeof(newF->filename));
 | 
			
		||||
  if(isRead)
 | 
			
		||||
  {
 | 
			
		||||
    newF->f = SD.open(newF->filename);
 | 
			
		||||
    if(newF->f == 0)
 | 
			
		||||
    {
 | 
			
		||||
      if(strchr(basename(newF->filename), ',') == 0) 
 | 
			
		||||
      {
 | 
			
		||||
        if(strlen(newF->filename) + 5 < HCM_FNSIZ) 
 | 
			
		||||
        {
 | 
			
		||||
          if((mode == 'l') || (mode == 's')) 
 | 
			
		||||
            strcat(newF->filename, ",prg");
 | 
			
		||||
          else
 | 
			
		||||
          {
 | 
			
		||||
            if(type == 'f')
 | 
			
		||||
              strcat(newF->filename, ",rel");
 | 
			
		||||
            else
 | 
			
		||||
              strcat(newF->filename, ",seq");  
 | 
			
		||||
          }
 | 
			
		||||
          newF->f = SD.open(newF->filename);
 | 
			
		||||
          if(newF == 0)
 | 
			
		||||
          {
 | 
			
		||||
            sendError("error: file '%s' not found", newF->filename);
 | 
			
		||||
            return;
 | 
			
		||||
          }
 | 
			
		||||
        } 
 | 
			
		||||
      } 
 | 
			
		||||
      else 
 | 
			
		||||
      { 
 | 
			
		||||
        sendError("error: file '%s' not found", newF->filename);
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  else
 | 
			
		||||
  {
 | 
			
		||||
    newF->f = SD.open(newF->filename,FILE_WRITE);
 | 
			
		||||
    if(newF->f == 0)
 | 
			
		||||
    {
 | 
			
		||||
      sendError("error: failed to open '%s'", newF->filename);
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    if(newF->f && (mode == 'a'))
 | 
			
		||||
      newF->f.seek(EOF);
 | 
			
		||||
  }
 | 
			
		||||
  newF->mode = mode;
 | 
			
		||||
  newF->format = format;
 | 
			
		||||
  newF->type = type;
 | 
			
		||||
  newF->reclen = reclen;
 | 
			
		||||
  
 | 
			
		||||
  odex = 0;
 | 
			
		||||
  outbuf[odex++] = opt.response;
 | 
			
		||||
  outbuf[odex++] = 'b';
 | 
			
		||||
  outbuf[odex++] = newF->descriptor;
 | 
			
		||||
  outbuf[odex++] = checksum(&(outbuf[1]), 2);
 | 
			
		||||
  outbuf[odex++] = opt.lineend;
 | 
			
		||||
  outbuf[odex++] = opt.prompt;
 | 
			
		||||
  hserial.write(outbuf, odex);
 | 
			
		||||
  hserial.flush();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void HostCM::protoOpenDir()
 | 
			
		||||
{
 | 
			
		||||
  if(openDirF != 0) 
 | 
			
		||||
  {
 | 
			
		||||
    sendError("error: directory open");
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
  if(idex > 2) 
 | 
			
		||||
    inbuf[idex - 1] = 0;
 | 
			
		||||
  else 
 | 
			
		||||
  {
 | 
			
		||||
    strcpy((char *)&inbuf[1], "/");
 | 
			
		||||
    idex++;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  openDirF = SD.open((char *)&inbuf[1]);
 | 
			
		||||
  if((openDirF == 0)||(!openDirF.isDirectory())) 
 | 
			
		||||
  {
 | 
			
		||||
    sendError("error: directory not found %s",(char *)&inbuf[1]);
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
  sendACK();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void HostCM::protoCloseDir()
 | 
			
		||||
{
 | 
			
		||||
  if(openDirF == 0) 
 | 
			
		||||
  {
 | 
			
		||||
    sendError("error: directory not open"); // should this really be an error?
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
  openDirF.close();
 | 
			
		||||
  openDirF = (File)0;
 | 
			
		||||
  sendACK();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void HostCM::protoNextDirFile()
 | 
			
		||||
{
 | 
			
		||||
  if(openDirF == 0) 
 | 
			
		||||
  {
 | 
			
		||||
    sendError("error: directory not open"); // should this really be an error?
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  odex = 0;
 | 
			
		||||
  outbuf[odex++] = opt.response;
 | 
			
		||||
  
 | 
			
		||||
  File nf = openDirF.openNextFile();
 | 
			
		||||
  if(nf == 0)
 | 
			
		||||
    outbuf[odex++] = 'e';
 | 
			
		||||
  else 
 | 
			
		||||
  {
 | 
			
		||||
    char *fname = (char *)nf.name();
 | 
			
		||||
    char *paren = strchr(fname,')');
 | 
			
		||||
    int reclen = 0;
 | 
			
		||||
    if((strncmp("(f:", fname, 3) == 0) && (paren != 0)) 
 | 
			
		||||
    {
 | 
			
		||||
      fname = paren + 1;
 | 
			
		||||
      reclen = atoi((char *)&fname[3]);
 | 
			
		||||
    }
 | 
			
		||||
    outbuf[odex++] = 'b';
 | 
			
		||||
 | 
			
		||||
    if(reclen) 
 | 
			
		||||
      odex += snprintf((char *)&outbuf[odex], HCM_BUFSIZ - odex, "%-20s  %8llu (%d)", 
 | 
			
		||||
          fname, (unsigned long long)nf.size(), reclen);
 | 
			
		||||
    else 
 | 
			
		||||
    {
 | 
			
		||||
      if(nf.isDirectory()) 
 | 
			
		||||
        odex += snprintf((char *)&outbuf[odex], HCM_BUFSIZ - odex, "%s/", fname);
 | 
			
		||||
      else 
 | 
			
		||||
      {
 | 
			
		||||
        odex += snprintf((char *)&outbuf[odex], HCM_BUFSIZ - odex, "%-20s  %8llu", 
 | 
			
		||||
            fname, (unsigned long long)nf.size());
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  nf.close();
 | 
			
		||||
  outbuf[odex] = checksum(&(outbuf[1]), odex - 1);
 | 
			
		||||
  odex++;
 | 
			
		||||
  outbuf[odex++] = opt.lineend;
 | 
			
		||||
  outbuf[odex++] = opt.prompt;
 | 
			
		||||
  hserial.write(outbuf, odex);
 | 
			
		||||
  hserial.flush();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void HostCM::protoSetRenameFile()
 | 
			
		||||
{
 | 
			
		||||
  if (renameF != 0) 
 | 
			
		||||
  {
 | 
			
		||||
    sendError("error: rename in progress");
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (idex > 2) 
 | 
			
		||||
  {
 | 
			
		||||
    inbuf[idex - 1] = 0;
 | 
			
		||||
    renameF = SD.open((char *)&inbuf[1]);
 | 
			
		||||
  } 
 | 
			
		||||
  else 
 | 
			
		||||
  {
 | 
			
		||||
    sendError("error: missing filename");
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
  sendACK();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void HostCM::protoFinRenameFile()
 | 
			
		||||
{
 | 
			
		||||
  if (renameF == 0) 
 | 
			
		||||
  {
 | 
			
		||||
    sendError("error: rename not started");
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (idex > 2) 
 | 
			
		||||
    inbuf[idex - 1] = 0;
 | 
			
		||||
  else 
 | 
			
		||||
  {
 | 
			
		||||
    sendError("error: missing filename");
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  String on = renameF.name();
 | 
			
		||||
  renameF.close();
 | 
			
		||||
  if(!SD.rename(on,(char *)&inbuf[1]))
 | 
			
		||||
  {
 | 
			
		||||
    renameF = (File)0;
 | 
			
		||||
    sendError("error: rename %s failed",on);
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
  renameF = (File)0;
 | 
			
		||||
  sendACK();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void HostCM::protoEraseFile()
 | 
			
		||||
{
 | 
			
		||||
  if (idex > 2) 
 | 
			
		||||
    inbuf[idex - 1] = 0;
 | 
			
		||||
  else 
 | 
			
		||||
  {
 | 
			
		||||
    sendError("error: missing filename");
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
  if(!SD.remove((char *)&inbuf[1]))
 | 
			
		||||
  {
 | 
			
		||||
    sendError("error: erase %s failed",(char *)&inbuf[1] );
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
  sendACK();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void HostCM::protoSeekFile()
 | 
			
		||||
{
 | 
			
		||||
  HCMFile *h = getFileByDescriptor((char)inbuf[1]);
 | 
			
		||||
  if (h==0) 
 | 
			
		||||
  {
 | 
			
		||||
    sendError("error: invalid descriptor %c", inbuf[1]);
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
  if(h->f == 0)
 | 
			
		||||
  {
 | 
			
		||||
    sendError("error: file not open/readable %c", inbuf[1]);
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  inbuf[idex - 1] = 0;
 | 
			
		||||
 | 
			
		||||
  unsigned long offset = atoi((char *)&inbuf[2]) * ((h->reclen == 0)? 1 : h->reclen);
 | 
			
		||||
  if(!h->f.seek(offset))
 | 
			
		||||
  {
 | 
			
		||||
    sendError("error: seek failed on %s @ %ul", h->f.name(),offset);
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
  sendACK();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
char HostCM::checksum(uint8_t *b, int n)
 | 
			
		||||
{
 | 
			
		||||
  int i, s = 0;
 | 
			
		||||
 | 
			
		||||
  for (i = 0; i < n; i++)
 | 
			
		||||
    s += b[i] & 0xf;
 | 
			
		||||
  return ('A' + (s&0xf));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void HostCM::sendError(const char* format, ...)
 | 
			
		||||
{
 | 
			
		||||
  odex = 0;
 | 
			
		||||
  outbuf[odex++] = opt.response;
 | 
			
		||||
  outbuf[odex++] = 'x';
 | 
			
		||||
  va_list arglist;
 | 
			
		||||
  va_start(arglist, format);
 | 
			
		||||
  odex += vsnprintf((char *)&outbuf[2], 80,  format, arglist); 
 | 
			
		||||
  va_end(arglist);
 | 
			
		||||
  outbuf[odex] = checksum(&outbuf[1], odex - 1);
 | 
			
		||||
  odex++;
 | 
			
		||||
  outbuf[odex++] = opt.lineend;
 | 
			
		||||
  outbuf[odex++] = opt.prompt;
 | 
			
		||||
  hserial.write(outbuf, odex);
 | 
			
		||||
  hserial.flush();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void HostCM::sendNAK()
 | 
			
		||||
{
 | 
			
		||||
  odex = 0;
 | 
			
		||||
  outbuf[odex++] = opt.response;
 | 
			
		||||
  outbuf[odex++] = 'N';
 | 
			
		||||
  outbuf[odex++] = opt.lineend;
 | 
			
		||||
  outbuf[odex++] = opt.prompt;
 | 
			
		||||
  hserial.write(outbuf, odex);
 | 
			
		||||
  hserial.flush();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void HostCM::sendACK()
 | 
			
		||||
{
 | 
			
		||||
  odex = 0;
 | 
			
		||||
  outbuf[odex++] = opt.response;
 | 
			
		||||
  outbuf[odex++] = 'b';
 | 
			
		||||
  outbuf[odex++] = checksum(&(outbuf[1]), 1);
 | 
			
		||||
  outbuf[odex++] = opt.lineend;
 | 
			
		||||
  outbuf[odex++] = opt.prompt;
 | 
			
		||||
  hserial.write(outbuf, odex);
 | 
			
		||||
  hserial.flush();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void HostCM::receiveLoop()
 | 
			
		||||
{
 | 
			
		||||
  serialOutDeque();
 | 
			
		||||
  unsigned long tm = millis();
 | 
			
		||||
  if(checkPlusPlusPlusExpire(tm))
 | 
			
		||||
    return;
 | 
			
		||||
  int c;
 | 
			
		||||
  while(hserial.available() > 0)
 | 
			
		||||
  {
 | 
			
		||||
    c=hserial.read();
 | 
			
		||||
    if(idex<HCM_BUFSIZ)
 | 
			
		||||
      inbuf[idex++]=c;
 | 
			
		||||
    checkDoPlusPlusPlus(c, tm);
 | 
			
		||||
    if(checkPlusPlusPlusExpire(tm))
 | 
			
		||||
      return;
 | 
			
		||||
    yield();
 | 
			
		||||
    if(c==opt.lineend)
 | 
			
		||||
    {
 | 
			
		||||
      inbuf[idex-1]=c;
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  if((idex==0)
 | 
			
		||||
  ||(inbuf[idex-1]!=opt.lineend))
 | 
			
		||||
  {
 | 
			
		||||
    serialOutDeque();
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  idex--;
 | 
			
		||||
  if((idex>1)&&(inbuf[idex-1]!=checksum(inbuf,idex-1)))
 | 
			
		||||
    sendNAK();
 | 
			
		||||
  else
 | 
			
		||||
  {
 | 
			
		||||
    logPrintf("HOSTCM received: %c\n",inbuf[0]);
 | 
			
		||||
    switch(inbuf[0])
 | 
			
		||||
    {
 | 
			
		||||
      case 'N':
 | 
			
		||||
        hserial.write(outbuf, odex);
 | 
			
		||||
        hserial.flush();
 | 
			
		||||
        break;
 | 
			
		||||
      case 'v': sendACK(); break;
 | 
			
		||||
      case 'q': aborted = closeAllFiles(); break;
 | 
			
		||||
      case 'o': protoOpenFile(); break;
 | 
			
		||||
      case 'c': protoCloseFile(); break;
 | 
			
		||||
      case 'p': protoPutToFile(); break;
 | 
			
		||||
      case 'g': protoGetFileBytes(); break;
 | 
			
		||||
      case 'd': protoOpenDir(); break;
 | 
			
		||||
      case 'f': protoNextDirFile(); break;
 | 
			
		||||
      case 'k': protoCloseDir(); break;
 | 
			
		||||
      case 'w': protoSetRenameFile(); break;
 | 
			
		||||
      case 'b': protoFinRenameFile(); break;
 | 
			
		||||
      case 'y': protoEraseFile(); break;
 | 
			
		||||
      case 'r': protoSeekFile(); break;
 | 
			
		||||
      default:
 | 
			
		||||
        sendNAK();
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  idex=0; // we are ready for the next packet!
 | 
			
		||||
  serialOutDeque();
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,399 @@
 | 
			
		|||
#include <Arduino.h>
 | 
			
		||||
/*
 | 
			
		||||
   Copyright 2016-2019 Bo Zimmerman
 | 
			
		||||
 | 
			
		||||
   Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
   you may not use this file except in compliance with the License.
 | 
			
		||||
   You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
     http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
   Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
   distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
   See the License for the specific language governing permissions and
 | 
			
		||||
   limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
bool parseWebUrl(uint8_t *vbuf, char **hostIp, char **req, int *port, bool *doSSL)
 | 
			
		||||
{
 | 
			
		||||
  *doSSL = false;
 | 
			
		||||
  if(strstr((char *)vbuf,"http:")==(char *)vbuf)
 | 
			
		||||
    vbuf = vbuf + 5;
 | 
			
		||||
  else
 | 
			
		||||
  if(strstr((char *)vbuf,"https:")==(char *)vbuf)
 | 
			
		||||
  {
 | 
			
		||||
    vbuf = vbuf + 6;
 | 
			
		||||
    *doSSL = true;
 | 
			
		||||
  }
 | 
			
		||||
  while(*vbuf == '/')
 | 
			
		||||
    vbuf++;
 | 
			
		||||
 | 
			
		||||
  *port= (*doSSL) ? 443 : 80;
 | 
			
		||||
  *hostIp = (char *)vbuf;
 | 
			
		||||
  char *portB=strchr((char *)vbuf,':');
 | 
			
		||||
  *req = strchr((char *)vbuf,'/');
 | 
			
		||||
  if(*req != NULL)
 | 
			
		||||
  {
 | 
			
		||||
    *(*req)=0;
 | 
			
		||||
    (*req)++;
 | 
			
		||||
  }
 | 
			
		||||
  else
 | 
			
		||||
  {
 | 
			
		||||
    int len=strlen((char *)vbuf);
 | 
			
		||||
    *req = (char *)(vbuf + len);
 | 
			
		||||
  }
 | 
			
		||||
  if(portB != NULL)
 | 
			
		||||
  {
 | 
			
		||||
     *portB = 0;
 | 
			
		||||
     portB++;
 | 
			
		||||
     *port = atoi(portB);
 | 
			
		||||
     if(port <= 0)
 | 
			
		||||
       return false;
 | 
			
		||||
  }
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
/*
 | 
			
		||||
 * It just breaks too many things to allow a stream to go forward without
 | 
			
		||||
 * a determined length.  For example: firmware updates, and even at&g returns 
 | 
			
		||||
 * a page length for the client.  Let true clients use sockets and handle
 | 
			
		||||
 * their own chunked encoding.
 | 
			
		||||
class ChunkedStream : public WiFiClient
 | 
			
		||||
{
 | 
			
		||||
private:
 | 
			
		||||
  WiFiClient *wifi = null;
 | 
			
		||||
  int chunkCount = 0;
 | 
			
		||||
  int chunkSize = 0;
 | 
			
		||||
  uint8_t state = 0; //0
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
 | 
			
		||||
    ChunkedStream(WiFiClient *s)
 | 
			
		||||
    {
 | 
			
		||||
      wifi = s;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ~ChunkedStream()
 | 
			
		||||
    {
 | 
			
		||||
      if(wifi != null)
 | 
			
		||||
      {
 | 
			
		||||
        wifi->stop();
 | 
			
		||||
        delete wifi;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    virtual int read()
 | 
			
		||||
    {
 | 
			
		||||
      if(available()==0)
 | 
			
		||||
        return -1;
 | 
			
		||||
      char c=wifi->read();
 | 
			
		||||
      bool gotC = false;
 | 
			
		||||
      int errors = 0;
 | 
			
		||||
      while((!gotC) && (errors < 5000))
 | 
			
		||||
      {
 | 
			
		||||
        switch(state)
 | 
			
		||||
        {
 | 
			
		||||
          case 0:
 | 
			
		||||
            if(c=='0')
 | 
			
		||||
              return '\0';
 | 
			
		||||
            if((c>='0')&&(c<='9'))
 | 
			
		||||
            {
 | 
			
		||||
              chunkSize = (c - '0');
 | 
			
		||||
              state=1;
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            if((c>='a')&&(c<='f'))
 | 
			
		||||
            {
 | 
			
		||||
              chunkSize = 10 + (c-'a');
 | 
			
		||||
              state=1;
 | 
			
		||||
            }
 | 
			
		||||
            break;
 | 
			
		||||
          case 1:
 | 
			
		||||
          {
 | 
			
		||||
            if((c>='0')&&(c<='9'))
 | 
			
		||||
              chunkSize = (chunkSize * 16) + (c - '0');
 | 
			
		||||
            else
 | 
			
		||||
            if((c>='a')&&(c<='f'))
 | 
			
		||||
              chunkSize = (chunkSize * 16) + (c-'a');
 | 
			
		||||
            else
 | 
			
		||||
            if(c=='\r')
 | 
			
		||||
              state=2;
 | 
			
		||||
            break;
 | 
			
		||||
          }
 | 
			
		||||
          case 2:
 | 
			
		||||
            if(c == '\n')
 | 
			
		||||
            {
 | 
			
		||||
              state = 3;
 | 
			
		||||
              chunkCount=0;
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
              state = 0;
 | 
			
		||||
            break;
 | 
			
		||||
          case 3:
 | 
			
		||||
            if(chunkCount < chunkSize)
 | 
			
		||||
            {
 | 
			
		||||
              gotC = true;
 | 
			
		||||
              chunkCount++;
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            if(c == '\r')
 | 
			
		||||
              state = 4;
 | 
			
		||||
            else
 | 
			
		||||
              state = 0;
 | 
			
		||||
            break;
 | 
			
		||||
          case 4:
 | 
			
		||||
            if(c == '\n')
 | 
			
		||||
              state = 0;
 | 
			
		||||
            else
 | 
			
		||||
              state = 0; // what else is there to do?!
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        while((!gotC) && (errors < 5000))
 | 
			
		||||
        {
 | 
			
		||||
            if(available()>0)
 | 
			
		||||
            {
 | 
			
		||||
              c=wifi->read();
 | 
			
		||||
              break;
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            if(++errors > 5000)
 | 
			
		||||
              break;
 | 
			
		||||
            else
 | 
			
		||||
              delay(1);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      return c;
 | 
			
		||||
    }
 | 
			
		||||
    virtual int peek()
 | 
			
		||||
    {
 | 
			
		||||
      return wifi->peek();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    virtual int read(uint8_t *buf, size_t size)
 | 
			
		||||
    {
 | 
			
		||||
      if(size == 0)
 | 
			
		||||
        return 0;
 | 
			
		||||
      int num = available();
 | 
			
		||||
      if(num > size)
 | 
			
		||||
        num=size;
 | 
			
		||||
      for(int i=0;i<num;i++)
 | 
			
		||||
        buf[i]=read();
 | 
			
		||||
      return num;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool getNoDelay()
 | 
			
		||||
    {
 | 
			
		||||
      return wifi->getNoDelay();
 | 
			
		||||
    }
 | 
			
		||||
    void setNoDelay(bool nodelay)
 | 
			
		||||
    {
 | 
			
		||||
      wifi->setNoDelay(nodelay);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    virtual int available()
 | 
			
		||||
    {
 | 
			
		||||
      return wifi->available();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    virtual void stop()
 | 
			
		||||
    {
 | 
			
		||||
      wifi->stop();
 | 
			
		||||
    }
 | 
			
		||||
    virtual uint8_t connected()
 | 
			
		||||
    {
 | 
			
		||||
      return wifi->connected();
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 */
 | 
			
		||||
WiFiClient *doWebGetStream(const char *hostIp, int port, const char *req, bool doSSL, uint32_t *responseSize)
 | 
			
		||||
{
 | 
			
		||||
  *responseSize = 0;
 | 
			
		||||
  if(WiFi.status() != WL_CONNECTED)
 | 
			
		||||
    return null;
 | 
			
		||||
  
 | 
			
		||||
  WiFiClient *c = createWiFiClient(doSSL);
 | 
			
		||||
  if(port == 0)
 | 
			
		||||
    port = 80;
 | 
			
		||||
  if(!c->connect(hostIp, port))
 | 
			
		||||
  {
 | 
			
		||||
    c->stop();
 | 
			
		||||
    delete c;
 | 
			
		||||
    return null;
 | 
			
		||||
  }
 | 
			
		||||
  c->setNoDelay(DEFAULT_NO_DELAY);
 | 
			
		||||
 | 
			
		||||
  const char *root = "";
 | 
			
		||||
  if(req == NULL)
 | 
			
		||||
    req=root;
 | 
			
		||||
  if(*req == '/')
 | 
			
		||||
    req++;
 | 
			
		||||
  
 | 
			
		||||
  c->printf("GET /%s HTTP/1.1\r\n",req);
 | 
			
		||||
  c->printf("User-Agent: Zimodem Firmware\r\n");
 | 
			
		||||
  c->printf("Host: %s\r\n",hostIp);
 | 
			
		||||
  c->printf("Connection: close\r\n\r\n");
 | 
			
		||||
  
 | 
			
		||||
  String ln = "";
 | 
			
		||||
  String reUrl = "";
 | 
			
		||||
  uint32_t respLength = 0;
 | 
			
		||||
  int respCode = -1;
 | 
			
		||||
  bool chunked = false;
 | 
			
		||||
  while(c->connected() || (c->available()>0))
 | 
			
		||||
  {
 | 
			
		||||
    yield();
 | 
			
		||||
    if(c->available()==0)
 | 
			
		||||
      continue;
 | 
			
		||||
 | 
			
		||||
    char ch = (char)c->read();
 | 
			
		||||
    logSocketIn(ch); // this is very much socket input!
 | 
			
		||||
    if(ch == '\r')
 | 
			
		||||
      continue;
 | 
			
		||||
    else
 | 
			
		||||
    if(ch == '\n')
 | 
			
		||||
    {
 | 
			
		||||
      if(ln.length()==0)
 | 
			
		||||
        break;
 | 
			
		||||
      if(respCode < 0)
 | 
			
		||||
      {
 | 
			
		||||
        int sp = ln.indexOf(' ');
 | 
			
		||||
        if(sp<=0)
 | 
			
		||||
          break;
 | 
			
		||||
        ln.remove(0,sp+1);
 | 
			
		||||
        sp = ln.indexOf(' ');
 | 
			
		||||
        if(sp<=0)
 | 
			
		||||
          break;
 | 
			
		||||
        ln.remove(sp);
 | 
			
		||||
        respCode = atoi(ln.c_str());
 | 
			
		||||
      }
 | 
			
		||||
      else
 | 
			
		||||
      {
 | 
			
		||||
        int x=ln.indexOf(':');
 | 
			
		||||
        if(x>0)
 | 
			
		||||
        {
 | 
			
		||||
          String header = ln.substring(0,x);
 | 
			
		||||
          header.toLowerCase();
 | 
			
		||||
          if(header == "content-length")
 | 
			
		||||
          {
 | 
			
		||||
            ln.remove(0,16);
 | 
			
		||||
            respLength = atoi(ln.c_str());
 | 
			
		||||
          }
 | 
			
		||||
          else
 | 
			
		||||
          if(header == "location")
 | 
			
		||||
          {
 | 
			
		||||
            reUrl = ln;
 | 
			
		||||
            reUrl.remove(0,10);
 | 
			
		||||
          }
 | 
			
		||||
          else
 | 
			
		||||
          if(header == "transfer-encoding")
 | 
			
		||||
          {
 | 
			
		||||
              ln.toLowerCase();
 | 
			
		||||
              chunked = ln.indexOf("chunked") > 0;  
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      ln = "";
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
      ln.concat(ch);
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  if((respCode >= 300) 
 | 
			
		||||
  && (respCode <= 399) 
 | 
			
		||||
  && (reUrl.length() > 0)
 | 
			
		||||
  && (reUrl.length() < 1024))
 | 
			
		||||
  {
 | 
			
		||||
    char newUrlBuf[reUrl.length()+1];
 | 
			
		||||
    strcpy(newUrlBuf,reUrl.c_str());
 | 
			
		||||
    char *hostIp2;
 | 
			
		||||
    char *req2;
 | 
			
		||||
    int port2;
 | 
			
		||||
    bool doSSL2;
 | 
			
		||||
    if(parseWebUrl((uint8_t *)newUrlBuf, &hostIp2,&req2,&port2,&doSSL2))
 | 
			
		||||
    {
 | 
			
		||||
        c->stop();
 | 
			
		||||
        delete c;
 | 
			
		||||
        return doWebGetStream(hostIp2,port2,req2,doSSL2,responseSize);
 | 
			
		||||
      
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  *responseSize = respLength;
 | 
			
		||||
  if(((!c->connected())&&(c->available()==0))
 | 
			
		||||
  ||(respCode != 200)
 | 
			
		||||
  ||(respLength <= 0))
 | 
			
		||||
  {
 | 
			
		||||
    c->stop();
 | 
			
		||||
    delete c;
 | 
			
		||||
    return null;
 | 
			
		||||
  }
 | 
			
		||||
  //if(chunked) // technically, if a length was returned, chunked would be ok, but that's not in the cards.
 | 
			
		||||
  //  return new ChunkedStream(c);
 | 
			
		||||
  return c;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool doWebGet(const char *hostIp, int port, FS *fs, const char *filename, const char *req, const bool doSSL)
 | 
			
		||||
{
 | 
			
		||||
  uint32_t respLength=0;
 | 
			
		||||
  WiFiClient *c = doWebGetStream(hostIp, port, req, doSSL, &respLength);
 | 
			
		||||
  if(c==null)
 | 
			
		||||
    return false;
 | 
			
		||||
  uint32_t bytesRead = 0;
 | 
			
		||||
  File f = fs->open(filename, "w");
 | 
			
		||||
  unsigned long now = millis();
 | 
			
		||||
  while((bytesRead < respLength) // this can be removed for chunked encoding support 
 | 
			
		||||
  && (c->connected()||(c->available()>0)) 
 | 
			
		||||
  && ((millis()-now)<10000))
 | 
			
		||||
  {
 | 
			
		||||
    if(c->available()>0)
 | 
			
		||||
    {
 | 
			
		||||
      now=millis();
 | 
			
		||||
      uint8_t ch=c->read();
 | 
			
		||||
      logSocketIn(ch); // this is very much socket input!
 | 
			
		||||
      f.write(ch);
 | 
			
		||||
      bytesRead++;
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
      yield();
 | 
			
		||||
  }
 | 
			
		||||
  f.flush();
 | 
			
		||||
  f.close();
 | 
			
		||||
  c->stop();
 | 
			
		||||
  delete c;
 | 
			
		||||
  return (respLength == 0) || (bytesRead == respLength);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool doWebGetBytes(const char *hostIp, int port, const char *req, const bool doSSL, uint8_t *buf, int *bufSize)
 | 
			
		||||
{
 | 
			
		||||
  *bufSize = -1;
 | 
			
		||||
  uint32_t respLength=0;
 | 
			
		||||
  WiFiClient *c = doWebGetStream(hostIp, port, req, doSSL, &respLength);
 | 
			
		||||
  if(c==null)
 | 
			
		||||
    return false;
 | 
			
		||||
  if(((!c->connected())&&(c->available()==0))
 | 
			
		||||
  ||(respLength > *bufSize))
 | 
			
		||||
  {
 | 
			
		||||
    c->stop();
 | 
			
		||||
    delete c;
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
  *bufSize = (int)respLength;
 | 
			
		||||
  int index=0;
 | 
			
		||||
  unsigned long now = millis();
 | 
			
		||||
  while((index < respLength) // this can be removed for chunked encoding support
 | 
			
		||||
  &&(c->connected()||(c->available()>0)) 
 | 
			
		||||
  && ((millis()-now)<10000))
 | 
			
		||||
  {
 | 
			
		||||
    if(c->available()>0)
 | 
			
		||||
    {
 | 
			
		||||
      uint8_t ch=c->read();
 | 
			
		||||
      now = millis();
 | 
			
		||||
      logSocketIn(ch); // how is this not socket input -- it's coming from a WiFiClient -- that's THE SOCKET!
 | 
			
		||||
      buf[index++] = ch;
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
      yield();
 | 
			
		||||
  }
 | 
			
		||||
  *bufSize = index;
 | 
			
		||||
  c->stop();
 | 
			
		||||
  delete c;
 | 
			
		||||
  return (respLength == 0) || (index == respLength);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,818 @@
 | 
			
		|||
#include <Arduino.h>
 | 
			
		||||
#ifdef INCLUDE_SD_SHELL
 | 
			
		||||
/*
 | 
			
		||||
 *  K e r m i t  File Transfer Utility
 | 
			
		||||
 *
 | 
			
		||||
 *  UNIX Kermit, Columbia University, 1981, 1982, 1983
 | 
			
		||||
 *  Bill Catchings, Bob Cattani, Chris Maio, Frank da Cruz, Alan Crosswell
 | 
			
		||||
 *
 | 
			
		||||
 *  Also:   Jim Guyton, Rand Corporation
 | 
			
		||||
 *      Walter Underwood, Ford Aerospace
 | 
			
		||||
 *      Lauren Weinstein
 | 
			
		||||
 *      
 | 
			
		||||
 *  Adapted for Zimodem by Bo Zimmerman
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
KModem::KModem(FlowControlType commandFlow,
 | 
			
		||||
               int (*recvChar)(ZSerial *ser, int msDelay),
 | 
			
		||||
               void (*sendChar)(ZSerial *ser, char sym),
 | 
			
		||||
               bool (*dataHandler)(File *kfp, unsigned long number, char *buffer, int len),
 | 
			
		||||
               String &errors)
 | 
			
		||||
{
 | 
			
		||||
  this->errStr = &errors;
 | 
			
		||||
  this->sendChar = sendChar;
 | 
			
		||||
  this->recvChar = recvChar;
 | 
			
		||||
  this->dataHandler = dataHandler;  
 | 
			
		||||
  this->kserial.setFlowControlType(FCT_DISABLED);
 | 
			
		||||
  if(commandFlow==FCT_RTSCTS)
 | 
			
		||||
    this->kserial.setFlowControlType(FCT_RTSCTS);
 | 
			
		||||
  this->kserial.setPetsciiMode(false);
 | 
			
		||||
  this->kserial.setXON(true);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void KModem::flushinput()
 | 
			
		||||
{
 | 
			
		||||
  while(kserial.available()>0)
 | 
			
		||||
    logSerialIn(kserial.read());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool KModem::receive()
 | 
			
		||||
{
 | 
			
		||||
  state = 'R';      /* Receive-Init is the start state */
 | 
			
		||||
  n = 0;        /* Initialize message number */
 | 
			
		||||
  numtry = 0;       /* Say no tries yet */
 | 
			
		||||
 | 
			
		||||
  while(TRUE)
 | 
			
		||||
  {
 | 
			
		||||
    if (debug)
 | 
			
		||||
      debugPrintf(" recsw state: %c\n",state);
 | 
			
		||||
    switch(state)     /* Do until done */
 | 
			
		||||
    {
 | 
			
		||||
    case 'R': 
 | 
			
		||||
      state = rinit(); 
 | 
			
		||||
      break; /* Receive-Init */
 | 
			
		||||
    case 'F': 
 | 
			
		||||
      state = rfile(); 
 | 
			
		||||
      break; /* Receive-File */
 | 
			
		||||
    case 'D': 
 | 
			
		||||
      state = rdata(); 
 | 
			
		||||
      break; /* Receive-Data */
 | 
			
		||||
    case 'C': 
 | 
			
		||||
      kserial.flushAlways();
 | 
			
		||||
      return true;   /* Complete state */
 | 
			
		||||
    case 'A': 
 | 
			
		||||
      kserial.flushAlways();
 | 
			
		||||
      return false;    /* "Abort" state */
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
bool KModem::transmit()
 | 
			
		||||
{
 | 
			
		||||
  if (gnxtfl() == FALSE)  /* No more files go? */
 | 
			
		||||
  {
 | 
			
		||||
    kserial.flushAlways();
 | 
			
		||||
    return false;    /* if not, break, EOT, all done */
 | 
			
		||||
  }
 | 
			
		||||
  state = 'S';      /* Send initiate is the start state */
 | 
			
		||||
  n = 0;        /* Initialize message number */
 | 
			
		||||
  numtry = 0;       /* Say no tries yet */
 | 
			
		||||
  while(ZTRUE)       /* Do this as long as necessary */
 | 
			
		||||
  {
 | 
			
		||||
    if (debug) 
 | 
			
		||||
      debugPrintf("sendsw state: %c\n",state);
 | 
			
		||||
    switch(state)
 | 
			
		||||
    {
 | 
			
		||||
    case 'S': 
 | 
			
		||||
      state = sinit();  
 | 
			
		||||
      break; /* Send-Init */
 | 
			
		||||
    case 'F': 
 | 
			
		||||
      state = sfile();  
 | 
			
		||||
      break; /* Send-File */
 | 
			
		||||
    case 'D': 
 | 
			
		||||
      state = sdata();  
 | 
			
		||||
      break; /* Send-Data */
 | 
			
		||||
    case 'Z': 
 | 
			
		||||
      state = seof();   
 | 
			
		||||
      break; /* Send-End-of-File */
 | 
			
		||||
    case 'B': 
 | 
			
		||||
      state = sbreak(); 
 | 
			
		||||
      break; /* Send-Break */
 | 
			
		||||
    case 'C': 
 | 
			
		||||
      kserial.flushAlways();
 | 
			
		||||
      return true;     /* Complete */
 | 
			
		||||
    case 'A': 
 | 
			
		||||
      kserial.flushAlways();
 | 
			
		||||
      return false;    /* "Abort" */
 | 
			
		||||
    default:  
 | 
			
		||||
      kserial.flushAlways();
 | 
			
		||||
      return false;    /* Unknown, fail */
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 *  s i n i t
 | 
			
		||||
 *
 | 
			
		||||
 *  Send Initiate: send this host's parameters and get other side's back.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
char KModem::sinit()
 | 
			
		||||
{
 | 
			
		||||
  int num, len;     /* Packet number, length */
 | 
			
		||||
 | 
			
		||||
  if (numtry++ > MAXTRY) 
 | 
			
		||||
    return('A'); /* If too many tries, give up */
 | 
			
		||||
  spar(packet);     /* Fill up init info packet */
 | 
			
		||||
 | 
			
		||||
  flushinput();     /* Flush pending input */
 | 
			
		||||
 | 
			
		||||
  spack('S',n,6,packet);    /* Send an S packet */
 | 
			
		||||
  switch(rpack(&len,&num,recpkt)) /* What was the reply? */
 | 
			
		||||
  {
 | 
			
		||||
  case 'N':  
 | 
			
		||||
    return(state); /* NAK, try it again */
 | 
			
		||||
 | 
			
		||||
  case 'Y':     /* ACK */
 | 
			
		||||
    if (n != num)   /* If wrong ACK, stay in S state */
 | 
			
		||||
      return(state);    /* and try again */
 | 
			
		||||
    rpar(recpkt);   /* Get other side's init info */
 | 
			
		||||
 | 
			
		||||
    if (eol == 0) 
 | 
			
		||||
      eol = '\n'; /* Check and set defaults */
 | 
			
		||||
    if (quote == 0) 
 | 
			
		||||
      quote = '#';
 | 
			
		||||
 | 
			
		||||
    numtry = 0;     /* Reset try counter */
 | 
			
		||||
    n = (n+1)%64;   /* Bump packet count */
 | 
			
		||||
    return('F');    /* OK, switch state to F */
 | 
			
		||||
 | 
			
		||||
  case 'E':     /* Error packet received */
 | 
			
		||||
    prerrpkt(recpkt);   /* Print it out and */
 | 
			
		||||
    return('A');    /* abort */
 | 
			
		||||
 | 
			
		||||
  case FALSE: 
 | 
			
		||||
    return(state);  /* Receive failure, try again */
 | 
			
		||||
 | 
			
		||||
  default: 
 | 
			
		||||
    return('A');   /* Anything else, just "abort" */
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 *  s f i l e
 | 
			
		||||
 *
 | 
			
		||||
 *  Send File Header.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
char KModem::sfile()
 | 
			
		||||
{
 | 
			
		||||
  int num, len;    /* Packet number, length */
 | 
			
		||||
  char filnam1[MAX_PATH],/* Converted file name */
 | 
			
		||||
       *newfilnam, /* Pointer to file name to send */
 | 
			
		||||
       *cp;        /* char pointer */
 | 
			
		||||
  if (numtry++ > MAXTRY) 
 | 
			
		||||
    return('A'); /* If too many tries, give up */
 | 
			
		||||
 | 
			
		||||
  if (kfpClosed)     /* If not already open, */
 | 
			
		||||
  { 
 | 
			
		||||
    if (debug) 
 | 
			
		||||
      debugPrintf("   Opening %s for sending.\n",filnam);
 | 
			
		||||
    kfp = kfileSystem->open(filnam,"r");   /* open the file to be sent */
 | 
			
		||||
    if (!kfp)     /* If bad file pointer, give up */
 | 
			
		||||
    {
 | 
			
		||||
        debugPrintf("Cannot open file %s",filnam);
 | 
			
		||||
        return('A');
 | 
			
		||||
    }
 | 
			
		||||
    kfpClosed=false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  strcpy(filnam1, filnamo);   /* Copy file name */
 | 
			
		||||
  newfilnam = cp = filnam1;
 | 
			
		||||
  if (!xflg)
 | 
			
		||||
    while (*cp != '\0')   /* Strip off all leading directory */
 | 
			
		||||
      if (*cp++ == '/')   /* names (ie. up to the last /). */
 | 
			
		||||
        newfilnam = cp;
 | 
			
		||||
 | 
			
		||||
  len = strlen(newfilnam);    /* Compute length of new filename */
 | 
			
		||||
 | 
			
		||||
  debugPrintf("Sending %s as %s",filnam,newfilnam);
 | 
			
		||||
 | 
			
		||||
  spack('F',n,len,newfilnam);   /* Send an F packet */
 | 
			
		||||
  switch(rpack(&len,&num,recpkt)) /* What was the reply? */
 | 
			
		||||
  {     
 | 
			
		||||
  case 'N':     /* NAK, just stay in this state, */
 | 
			
		||||
    num = (--num<0 ? 63:num); /* unless it's NAK for next packet */
 | 
			
		||||
    if (n != num)   /* which is just like an ACK for */ 
 | 
			
		||||
      return(state);    /* this packet so fall thru to... */
 | 
			
		||||
  case 'Y':     /* ACK */
 | 
			
		||||
    if (n != num) 
 | 
			
		||||
      return(state); /* If wrong ACK, stay in F state */
 | 
			
		||||
    numtry = 0;     /* Reset try counter */
 | 
			
		||||
    n = (n+1)%64;   /* Bump packet count */
 | 
			
		||||
    size = bufill(packet);  /* Get first data from file */
 | 
			
		||||
    return('D');    /* Switch state to D */
 | 
			
		||||
  case 'E':     /* Error packet received */
 | 
			
		||||
    prerrpkt(recpkt);   /* Print it out and */
 | 
			
		||||
    return('A');    /* abort */
 | 
			
		||||
  case FALSE: 
 | 
			
		||||
    return(state);  /* Receive failure, stay in F state */
 | 
			
		||||
  default:    
 | 
			
		||||
    return('A');  /* Something else, just "abort" */
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 *  s d a t a
 | 
			
		||||
 *
 | 
			
		||||
 *  Send File Data
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
char KModem::sdata()
 | 
			
		||||
{
 | 
			
		||||
  int num, len;     /* Packet number, length */
 | 
			
		||||
 | 
			
		||||
  if (numtry++ > MAXTRY) 
 | 
			
		||||
    return('A'); /* If too many tries, give up */
 | 
			
		||||
  spack('D',n,size,packet);   /* Send a D packet */
 | 
			
		||||
  switch(rpack(&len,&num,recpkt)) /* What was the reply? */
 | 
			
		||||
  {       
 | 
			
		||||
  case 'N':     /* NAK, just stay in this state, */
 | 
			
		||||
    num = (--num<0 ? 63:num); /* unless it's NAK for next packet */
 | 
			
		||||
    if (n != num)   /* which is just like an ACK for */
 | 
			
		||||
      return(state);    /* this packet so fall thru to... */
 | 
			
		||||
  case 'Y':     /* ACK */
 | 
			
		||||
    if (n != num) 
 | 
			
		||||
      return(state); /* If wrong ACK, fail */
 | 
			
		||||
    numtry = 0;     /* Reset try counter */
 | 
			
		||||
    n = (n+1)%64;   /* Bump packet count */
 | 
			
		||||
    if ((size = bufill(packet)) == EOF) /* Get data from file */
 | 
			
		||||
      return('Z');    /* If EOF set state to that */
 | 
			
		||||
    return('D');    /* Got data, stay in state D */
 | 
			
		||||
  case 'E':     /* Error packet received */
 | 
			
		||||
    prerrpkt(recpkt);   /* Print it out and */
 | 
			
		||||
    return('A');    /* abort */
 | 
			
		||||
  case FALSE: 
 | 
			
		||||
    return(state);  /* Receive failure, stay in D */
 | 
			
		||||
  default:    
 | 
			
		||||
    return('A');  /* Anything else, "abort" */
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 *  s e o f
 | 
			
		||||
 *
 | 
			
		||||
 *  Send End-Of-File.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
char KModem::seof()
 | 
			
		||||
{
 | 
			
		||||
  int num, len;     /* Packet number, length */
 | 
			
		||||
  if (numtry++ > MAXTRY) 
 | 
			
		||||
    return('A'); /* If too many tries, "abort" */
 | 
			
		||||
 | 
			
		||||
  spack('Z',n,0,packet);    /* Send a 'Z' packet */
 | 
			
		||||
  switch(rpack(&len,&num,recpkt)) /* What was the reply? */
 | 
			
		||||
  {
 | 
			
		||||
  case 'N':     /* NAK, just stay in this state, */
 | 
			
		||||
    num = (--num<0 ? 63:num); /* unless it's NAK for next packet, */
 | 
			
		||||
    if (n != num)   /* which is just like an ACK for */
 | 
			
		||||
      return(state);    /* this packet so fall thru to... */
 | 
			
		||||
  case 'Y':     /* ACK */
 | 
			
		||||
    if (n != num) 
 | 
			
		||||
      return(state); /* If wrong ACK, hold out */
 | 
			
		||||
    numtry = 0;     /* Reset try counter */
 | 
			
		||||
    n = (n+1)%64;   /* and bump packet count */
 | 
			
		||||
    if (debug) 
 | 
			
		||||
      debugPrintf("   Closing input file %s, ",filnam);
 | 
			
		||||
    kfp.close();     /* Close the input file */
 | 
			
		||||
    kfpClosed = true;      /* Set flag indicating no file open */ 
 | 
			
		||||
    if (debug) 
 | 
			
		||||
      debugPrintf("looking for next file...\n");
 | 
			
		||||
    if (gnxtfl() == FALSE)  /* No more files go? */
 | 
			
		||||
      return('B');    /* if not, break, EOT, all done */
 | 
			
		||||
    if (debug) 
 | 
			
		||||
      debugPrintf("   New file is %s\n",filnam);
 | 
			
		||||
    return('F');    /* More files, switch state to F */
 | 
			
		||||
  case 'E':     /* Error packet received */
 | 
			
		||||
    prerrpkt(recpkt);   /* Print it out and */
 | 
			
		||||
    return('A');    /* abort */
 | 
			
		||||
  case FALSE: 
 | 
			
		||||
    return(state);  /* Receive failure, stay in Z */
 | 
			
		||||
  default:    
 | 
			
		||||
    return('A');  /* Something else, "abort" */
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 *  s b r e a k
 | 
			
		||||
 *
 | 
			
		||||
 *  Send Break (EOT)
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
char KModem::sbreak()
 | 
			
		||||
{
 | 
			
		||||
  int num, len;     /* Packet number, length */
 | 
			
		||||
  if (numtry++ > MAXTRY) 
 | 
			
		||||
    return('A'); /* If too many tries "abort" */
 | 
			
		||||
 | 
			
		||||
  spack('B',n,0,packet);    /* Send a B packet */
 | 
			
		||||
  switch (rpack(&len,&num,recpkt))  /* What was the reply? */
 | 
			
		||||
  {
 | 
			
		||||
  case 'N':     /* NAK, just stay in this state, */
 | 
			
		||||
    num = (--num<0 ? 63:num); /* unless NAK for previous packet, */
 | 
			
		||||
    if (n != num)   /* which is just like an ACK for */
 | 
			
		||||
      return(state);    /* this packet so fall thru to... */
 | 
			
		||||
  case 'Y':     /* ACK */
 | 
			
		||||
    if (n != num) 
 | 
			
		||||
      return(state); /* If wrong ACK, fail */
 | 
			
		||||
    numtry = 0;     /* Reset try counter */
 | 
			
		||||
    n = (n+1)%64;   /* and bump packet count */
 | 
			
		||||
    return('C');    /* Switch state to Complete */
 | 
			
		||||
  case 'E':     /* Error packet received */
 | 
			
		||||
    prerrpkt(recpkt);   /* Print it out and */
 | 
			
		||||
    return('A');    /* abort */
 | 
			
		||||
  case FALSE: 
 | 
			
		||||
    return(state);  /* Receive failure, stay in B */
 | 
			
		||||
  default:    
 | 
			
		||||
    return ('A'); /* Other, "abort" */
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 *  r i n i t
 | 
			
		||||
 *
 | 
			
		||||
 *  Receive Initialization
 | 
			
		||||
 */
 | 
			
		||||
  
 | 
			
		||||
char KModem::rinit()
 | 
			
		||||
{
 | 
			
		||||
  int len, num;     /* Packet length, number */
 | 
			
		||||
 | 
			
		||||
  if (numtry++ > MAXTRY) 
 | 
			
		||||
    return('A'); /* If too many tries, "abort" */
 | 
			
		||||
 | 
			
		||||
  char rs=rpack(&len,&num,packet);
 | 
			
		||||
  if (debug) 
 | 
			
		||||
    debugPrintf(" recsw-rinit state: %c\n",rs);
 | 
			
		||||
  switch(rs) /* Get a packet */
 | 
			
		||||
  {
 | 
			
		||||
  case 'S':     /* Send-Init */
 | 
			
		||||
    rpar(packet);   /* Get the other side's init data */
 | 
			
		||||
    spar(packet);   /* Fill up packet with my init info */
 | 
			
		||||
    spack('Y',n,6,packet);  /* ACK with my parameters */
 | 
			
		||||
    oldtry = numtry;    /* Save old try count */
 | 
			
		||||
    numtry = 0;     /* Start a new counter */
 | 
			
		||||
    n = (n+1)%64;   /* Bump packet number, mod 64 */
 | 
			
		||||
    return('F');    /* Enter File-Receive state */
 | 
			
		||||
  case 'E':     /* Error packet received */
 | 
			
		||||
    prerrpkt(recpkt);   /* Print it out and */
 | 
			
		||||
    return('A');    /* abort */
 | 
			
		||||
  case FALSE:     /* Didn't get packet */
 | 
			
		||||
    spack('N',n,0,0);   /* Return a NAK */
 | 
			
		||||
    return(state);    /* Keep trying */
 | 
			
		||||
  default:
 | 
			
		||||
    return('A'); /* Some other packet type, "abort" */
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 *  r f i l e
 | 
			
		||||
 *
 | 
			
		||||
 *  Receive File Header
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
char KModem::rfile()
 | 
			
		||||
{
 | 
			
		||||
  int num, len;     /* Packet number, length */
 | 
			
		||||
 | 
			
		||||
  if (numtry++ > MAXTRY) 
 | 
			
		||||
    return('A'); /* "abort" if too many tries */
 | 
			
		||||
 | 
			
		||||
  char rs = rpack(&len,&num,packet); 
 | 
			
		||||
  if (debug) 
 | 
			
		||||
    debugPrintf(" recsw-rfile state: %c\n",rs);
 | 
			
		||||
  switch(rs) /* Get a packet */
 | 
			
		||||
  {
 | 
			
		||||
  case 'S':     /* Send-Init, maybe our ACK lost */
 | 
			
		||||
    if (oldtry++ > MAXTRY) 
 | 
			
		||||
      return('A'); /* If too many tries abort */
 | 
			
		||||
    if (num == ((n==0) ? 63:n-1)) /* Previous packet, mod 64? */
 | 
			
		||||
    {       /* Yes, ACK it again with  */
 | 
			
		||||
      spar(packet);   /* our Send-Init parameters */
 | 
			
		||||
      spack('Y',num,6,packet);
 | 
			
		||||
      numtry = 0;   /* Reset try counter */
 | 
			
		||||
      return(state);    /* Stay in this state */
 | 
			
		||||
    }
 | 
			
		||||
    else 
 | 
			
		||||
      return('A');   /* Not previous packet, "abort" */
 | 
			
		||||
  case 'Z':     /* End-Of-File */
 | 
			
		||||
    if (oldtry++ > MAXTRY) 
 | 
			
		||||
      return('A');
 | 
			
		||||
    if (num == ((n==0) ? 63:n-1)) /* Previous packet, mod 64? */
 | 
			
		||||
    {       /* Yes, ACK it again. */
 | 
			
		||||
      spack('Y',num,0,0);
 | 
			
		||||
      numtry = 0;
 | 
			
		||||
      return(state);    /* Stay in this state */
 | 
			
		||||
    }
 | 
			
		||||
    else 
 | 
			
		||||
      return('A');   /* Not previous packet, "abort" */
 | 
			
		||||
  case 'F':     /* File Header (just what we want) */
 | 
			
		||||
    if (num != n) 
 | 
			
		||||
      return('A');  /* The packet number must be right */
 | 
			
		||||
    {
 | 
			
		||||
      char filnam1[MAX_PATH];     /* Holds the converted file name */
 | 
			
		||||
      char *subNam=filnam1;
 | 
			
		||||
      if(rootpath.length()>0)
 | 
			
		||||
      {
 | 
			
		||||
        strcpy(filnam1, rootpath.c_str());
 | 
			
		||||
        subNam += rootpath.length();
 | 
			
		||||
        if(filnam1[strlen(filnam1)-1]!='/')
 | 
			
		||||
        {
 | 
			
		||||
          filnam1[strlen(filnam1)]='/';
 | 
			
		||||
          filnam1[strlen(filnam1)+1]=0;
 | 
			
		||||
          subNam++;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      strcpy(subNam, packet);  /* Copy the file name */
 | 
			
		||||
      kfp = kfileSystem->open(filnam1,FILE_WRITE);
 | 
			
		||||
      if (!kfp) /* Try to open a new file */
 | 
			
		||||
      {
 | 
			
		||||
        if(errStr != 0)
 | 
			
		||||
          (*errStr) += ("Cannot create %s\n",filnam1); /* Give up if can't */
 | 
			
		||||
        return('A');
 | 
			
		||||
      }
 | 
			
		||||
      else      /* OK, give message */
 | 
			
		||||
      {
 | 
			
		||||
        debugPrintf("Receiving %s as %s\n",packet,filnam1);
 | 
			
		||||
        kfpClosed=false;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    spack('Y',n,0,0);   /* Acknowledge the file header */
 | 
			
		||||
    oldtry = numtry;    /* Reset try counters */
 | 
			
		||||
    numtry = 0;     /* ... */
 | 
			
		||||
    n = (n+1)%64;   /* Bump packet number, mod 64 */
 | 
			
		||||
    return('D');    /* Switch to Data state */
 | 
			
		||||
  case 'B':     /* Break transmission (EOT) */
 | 
			
		||||
    if (num != n) 
 | 
			
		||||
      return ('A'); /* Need right packet number here */
 | 
			
		||||
    spack('Y',n,0,0);   /* Say OK */
 | 
			
		||||
    return('C');    /* Go to complete state */
 | 
			
		||||
  case 'E':     /* Error packet received */
 | 
			
		||||
    prerrpkt(recpkt);   /* Print it out and */
 | 
			
		||||
    return('A');    /* abort */
 | 
			
		||||
  case FALSE:     /* Didn't get packet */
 | 
			
		||||
    spack('N',n,0,0);   /* Return a NAK */
 | 
			
		||||
    return(state);    /* Keep trying */
 | 
			
		||||
  default:    
 | 
			
		||||
    return ('A'); /* Some other packet, "abort" */
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 *  r d a t a
 | 
			
		||||
 *
 | 
			
		||||
 *  Receive Data
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
char KModem::rdata()
 | 
			
		||||
{
 | 
			
		||||
  int num, len;     /* Packet number, length */
 | 
			
		||||
  if (numtry++ > MAXTRY) 
 | 
			
		||||
    return('A'); /* "abort" if too many tries */
 | 
			
		||||
 | 
			
		||||
  char rs=rpack(&len,&num,packet);
 | 
			
		||||
  if (debug) 
 | 
			
		||||
    debugPrintf(" recsw-rdata state: %c\n",rs);
 | 
			
		||||
  switch(rs) /* Get packet */
 | 
			
		||||
  {
 | 
			
		||||
  case 'D':     /* Got Data packet */
 | 
			
		||||
    if (num != n)   /* Right packet? */
 | 
			
		||||
    {       /* No */
 | 
			
		||||
      if (oldtry++ > MAXTRY)
 | 
			
		||||
        return('A'); /* If too many tries, abort */
 | 
			
		||||
      if (num == ((n==0) ? 63:n-1)) /* Else check packet number */
 | 
			
		||||
      {     /* Previous packet again? */
 | 
			
		||||
        spack('Y',num,6,packet); /* Yes, re-ACK it */
 | 
			
		||||
        numtry = 0;   /* Reset try counter */
 | 
			
		||||
        return(state);  /* Don't write out data! */
 | 
			
		||||
      }
 | 
			
		||||
      else
 | 
			
		||||
         return('A'); /* sorry, wrong number */
 | 
			
		||||
    }
 | 
			
		||||
    /* Got data with right packet number */
 | 
			
		||||
    bufemp(packet,len);   /* Write the data to the file */
 | 
			
		||||
    spack('Y',n,0,0);   /* Acknowledge the packet */
 | 
			
		||||
    oldtry = numtry;    /* Reset the try counters */
 | 
			
		||||
    numtry = 0;     /* ... */
 | 
			
		||||
    n = (n+1)%64;   /* Bump packet number, mod 64 */
 | 
			
		||||
    return('D');    /* Remain in data state */
 | 
			
		||||
  case 'F':     /* Got a File Header */
 | 
			
		||||
    if (oldtry++ > MAXTRY)
 | 
			
		||||
      return('A');    /* If too many tries, "abort" */
 | 
			
		||||
    if (num == ((n==0) ? 63:n-1)) /* Else check packet number */
 | 
			
		||||
    {       /* It was the previous one */
 | 
			
		||||
      spack('Y',num,0,0); /* ACK it again */
 | 
			
		||||
      numtry = 0;   /* Reset try counter */
 | 
			
		||||
      return(state);    /* Stay in Data state */
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
      return('A');    /* Not previous packet, "abort" */
 | 
			
		||||
  case 'Z':     /* End-Of-File */
 | 
			
		||||
    if (num != n) 
 | 
			
		||||
      return('A');  /* Must have right packet number */
 | 
			
		||||
    spack('Y',n,0,0);   /* OK, ACK it. */
 | 
			
		||||
    kfp.close();     /* Close the file */
 | 
			
		||||
    kfpClosed=true;
 | 
			
		||||
    n = (n+1)%64;   /* Bump packet number */
 | 
			
		||||
    return('F');    /* Go back to Receive File state */
 | 
			
		||||
  case 'E':     /* Error packet received */
 | 
			
		||||
    prerrpkt(recpkt);   /* Print it out and */
 | 
			
		||||
    return('A');    /* abort */
 | 
			
		||||
  case FALSE:     /* Didn't get packet */
 | 
			
		||||
    spack('N',n,0,0);   /* Return a NAK */
 | 
			
		||||
    return(state);    /* Keep trying */
 | 
			
		||||
  default:
 | 
			
		||||
    return('A');    /* Some other packet, "abort" */
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 *  s p a c k
 | 
			
		||||
 *
 | 
			
		||||
 *  Send a Packet
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
int KModem::spack(char type, int num, int len, char *data)
 | 
			
		||||
{
 | 
			
		||||
  int i;        /* Character loop counter */
 | 
			
		||||
  char chksum, buffer[100];   /* Checksum, packet buffer */
 | 
			
		||||
  char *bufp;    /* Buffer pointer */
 | 
			
		||||
 | 
			
		||||
  if (debug>1)      /* Display outgoing packet */
 | 
			
		||||
  {
 | 
			
		||||
    if (data != NULL)
 | 
			
		||||
      data[len] = '\0';   /* Null-terminate data to print it */
 | 
			
		||||
    debugPrintf("\n  spack type: %c\n",type);
 | 
			
		||||
    debugPrintf("   num:  %d\n",num);
 | 
			
		||||
    debugPrintf("   len:  %d\n",len);
 | 
			
		||||
    if (data != NULL)
 | 
			
		||||
      debugPrintf("      data: \"%s\"\n",data);
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  bufp = buffer;      /* Set up buffer pointer */
 | 
			
		||||
  for (i=1; i<=pad; i++) 
 | 
			
		||||
    sendChar(&kserial,padchar); /* Issue any padding */
 | 
			
		||||
 | 
			
		||||
  *bufp++ = SOH;      /* Packet marker, ASCII 1 (SOH) */
 | 
			
		||||
  *bufp++ = (len+3+' ');    /* Send the character count */
 | 
			
		||||
  chksum  = (len+3+' ');    /* Initialize the checksum */
 | 
			
		||||
  *bufp++ = (num+' ');    /* Packet number */
 | 
			
		||||
  chksum += (num+' ');    /* Update checksum */
 | 
			
		||||
  *bufp++ = type;     /* Packet type */
 | 
			
		||||
  chksum += type;     /* Update checksum */
 | 
			
		||||
 | 
			
		||||
  for (i=0; i<len; i++)   /* Loop for all data characters */
 | 
			
		||||
  {
 | 
			
		||||
    *bufp++ = data[i];    /* Get a character */
 | 
			
		||||
    chksum += data[i];    /* Update checksum */
 | 
			
		||||
  }
 | 
			
		||||
  chksum = (((chksum&0300) >> 6)+chksum)&077; /* Compute final checksum */
 | 
			
		||||
  *bufp++ = (chksum+' ');   /* Put it in the packet */
 | 
			
		||||
  if ( mflg ) 
 | 
			
		||||
    *bufp++ = eol;    /* MacKermit needs this */
 | 
			
		||||
  *bufp = eol;      /* Extra-packet line terminator */
 | 
			
		||||
  for(i=0;i<bufp-buffer+1;i++) /* Send the packet */
 | 
			
		||||
    sendChar(&kserial,buffer[i]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 *  r p a c k
 | 
			
		||||
 *
 | 
			
		||||
 *  Read a Packet
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
int KModem::rpack(int *len, int *num, char *data)
 | 
			
		||||
{
 | 
			
		||||
  int i, done;  /* Data character number, loop exit */
 | 
			
		||||
  char t,       /* Current input character */
 | 
			
		||||
       type,    /* Packet type */
 | 
			
		||||
       cchksum, /* Our (computed) checksum */
 | 
			
		||||
       rchksum; /* Checksum received from other host */
 | 
			
		||||
 | 
			
		||||
  if ((timint > MAXTIM) || (timint < MINTIM)) 
 | 
			
		||||
    timint = MYTIME;
 | 
			
		||||
  
 | 
			
		||||
  while (t != SOH)      /* Wait for packet header */
 | 
			
		||||
  {
 | 
			
		||||
    if((t=recvChar(&kserial,timint))<0)
 | 
			
		||||
      return('A');
 | 
			
		||||
    t &= 0177;      /* Handle parity */
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  done = FALSE;     /* Got SOH, init loop */
 | 
			
		||||
  while (!done)     /* Loop to get a packet */
 | 
			
		||||
  {
 | 
			
		||||
    if((t=recvChar(&kserial,timint))<0)
 | 
			
		||||
      return('A');
 | 
			
		||||
    if (!image) 
 | 
			
		||||
      t &= 0177;    /* Handle parity */
 | 
			
		||||
    if (t == SOH) 
 | 
			
		||||
      continue;   /* Resynchronize if SOH */
 | 
			
		||||
    cchksum = t;      /* Start the checksum */
 | 
			
		||||
    *len = (t-' ')-3;   /* Character count */
 | 
			
		||||
 | 
			
		||||
    if((t=recvChar(&kserial,timint))<0)
 | 
			
		||||
      return('A');
 | 
			
		||||
    if (!image) 
 | 
			
		||||
      t &= 0177;    /* Handle parity */
 | 
			
		||||
    if (t == SOH) 
 | 
			
		||||
      continue;   /* Resynchronize if SOH */
 | 
			
		||||
    cchksum = cchksum + t;    /* Update checksum */
 | 
			
		||||
    *num = (t-' ');   /* Packet number */
 | 
			
		||||
 | 
			
		||||
    if((t=recvChar(&kserial,timint))<0)
 | 
			
		||||
      return('A');
 | 
			
		||||
    if (!image) 
 | 
			
		||||
      t &= 0177;    /* Handle parity */
 | 
			
		||||
    if (t == SOH) 
 | 
			
		||||
      continue;   /* Resynchronize if SOH */
 | 
			
		||||
    cchksum = cchksum + t;    /* Update checksum */
 | 
			
		||||
    type = t;     /* Packet type */
 | 
			
		||||
 | 
			
		||||
    for (i=0; i<*len; i++)    /* The data itself, if any */
 | 
			
		||||
    {       /* Loop for character count */
 | 
			
		||||
      if((t=recvChar(&kserial,timint))<0)
 | 
			
		||||
        return('A');
 | 
			
		||||
      if (!image) 
 | 
			
		||||
        t &= 0177;  /* Handle parity */
 | 
			
		||||
      if (t == SOH) 
 | 
			
		||||
        continue; /* Resynch if SOH */
 | 
			
		||||
      cchksum = cchksum + t;  /* Update checksum */
 | 
			
		||||
      data[i] = t;    /* Put it in the data buffer */
 | 
			
		||||
    }
 | 
			
		||||
    data[*len] = 0;     /* Mark the end of the data */
 | 
			
		||||
 | 
			
		||||
    if((t=recvChar(&kserial,timint))<0)
 | 
			
		||||
      return('A');
 | 
			
		||||
    rchksum = (t-' ');    /* Convert to numeric */
 | 
			
		||||
    if((t=recvChar(&kserial,timint))<0)
 | 
			
		||||
      return('A');
 | 
			
		||||
    if (!image) 
 | 
			
		||||
      t &= 0177;    /* Handle parity */
 | 
			
		||||
    if (t == SOH) 
 | 
			
		||||
      continue;   /* Resynchronize if SOH */
 | 
			
		||||
    done = TRUE;      /* Got checksum, done */
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (debug>1)      /* Display incoming packet */
 | 
			
		||||
  {
 | 
			
		||||
    if (data != NULL)
 | 
			
		||||
      data[*len] = '\0';    /* Null-terminate data to print it */
 | 
			
		||||
    debugPrintf("\n  rpack type: %c\n",type);
 | 
			
		||||
    debugPrintf("   num:  %d\n",*num);
 | 
			
		||||
    debugPrintf("   len:  %d\n",*len);
 | 
			
		||||
    if (data != NULL)
 | 
			
		||||
      debugPrintf("      data: \"%s\"\n",data);
 | 
			
		||||
  }
 | 
			
		||||
          /* Fold in bits 7,8 to compute */
 | 
			
		||||
  cchksum = (((cchksum&0300) >> 6)+cchksum)&077; /* final checksum */
 | 
			
		||||
 | 
			
		||||
  if (cchksum != rchksum) 
 | 
			
		||||
    return(FALSE);
 | 
			
		||||
 | 
			
		||||
  return(type);     /* All OK, return packet type */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 *  b u f i l l
 | 
			
		||||
 *
 | 
			
		||||
 *  Get a bufferful of data from the file that's being sent.
 | 
			
		||||
 *  Only control-quoting is done; 8-bit & repeat count prefixes are
 | 
			
		||||
 *  not handled.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
int KModem::bufill(char buffer[])
 | 
			
		||||
{
 | 
			
		||||
  int i;        /* Loop index */
 | 
			
		||||
  char t;        /* Char read from file */
 | 
			
		||||
  char t7;      /* 7-bit version of above */
 | 
			
		||||
 | 
			
		||||
  i = 0;        /* Init data buffer pointer */
 | 
			
		||||
  while(dataHandler(&kfp,0,&t,1))  /* Get the next character */
 | 
			
		||||
  {
 | 
			
		||||
    t7 = t & 0177;      /* Get low order 7 bits */
 | 
			
		||||
    if (t7 < SP || t7==DEL || t7==quote) /* Does this char require */
 | 
			
		||||
    {           /* special handling? */
 | 
			
		||||
      if (t=='\n' && !image)
 | 
			
		||||
      {       /* Do LF->CRLF mapping if !image */
 | 
			
		||||
        buffer[i++] = quote;
 | 
			
		||||
        buffer[i++] = '\r' ^ 64;
 | 
			
		||||
      }
 | 
			
		||||
      buffer[i++] = quote;  /* Quote the character */
 | 
			
		||||
      if (t7 != quote)
 | 
			
		||||
      {
 | 
			
		||||
        t = (t ^ 64);   /* and uncontrolify */
 | 
			
		||||
        t7 = (t7 ^ 64);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    if (image)
 | 
			
		||||
      buffer[i++] = t;    /* Deposit the character itself */
 | 
			
		||||
    else
 | 
			
		||||
      buffer[i++] = t7;
 | 
			
		||||
    if (i >= spsiz-8) 
 | 
			
		||||
      return(i);  /* Check length */
 | 
			
		||||
  }
 | 
			
		||||
  if (i==0) 
 | 
			
		||||
    return(EOF);    /* Wind up here only on EOF */
 | 
			
		||||
  return(i);        /* Handle partial buffer */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void KModem::bufemp(char buffer[], int len)
 | 
			
		||||
{
 | 
			
		||||
  int i;        /* Counter */
 | 
			
		||||
  char t;       /* Character holder */
 | 
			
		||||
 | 
			
		||||
  for (i=0; i<len; i++)   /* Loop thru the data field */
 | 
			
		||||
  {
 | 
			
		||||
    t = buffer[i];      /* Get character */
 | 
			
		||||
    if (t == MYQUOTE)   /* Control quote? */
 | 
			
		||||
    {       /* Yes */
 | 
			
		||||
      t = buffer[++i];    /* Get the quoted character */
 | 
			
		||||
      if ((t & 0177) != MYQUOTE)  /* Low order bits match quote char? */
 | 
			
		||||
        t = t ^ 64;   /* No, uncontrollify it */
 | 
			
		||||
    }
 | 
			
		||||
    if (t==CR && !image)    /* Don't pass CR if in image mode */
 | 
			
		||||
      continue;
 | 
			
		||||
    dataHandler(&kfp,0,&t,1);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int KModem::gnxtfl()
 | 
			
		||||
{
 | 
			
		||||
  if (filecount-- == 0) 
 | 
			
		||||
    return FALSE; /* If no more, fail */
 | 
			
		||||
  filnam = (char *)filelist[filenum++]->c_str();
 | 
			
		||||
  filnamo = filnam;
 | 
			
		||||
  if (debug) 
 | 
			
		||||
    debugPrintf("   gnxtfl: filelist = \"%s\"\n",filnam);
 | 
			
		||||
  return TRUE;      /* else succeed */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void KModem::spar(char data[])
 | 
			
		||||
{
 | 
			
		||||
    data[0] = (MAXPACKSIZ + ' ');    /* Biggest packet I can receive */
 | 
			
		||||
    data[1] = (MYTIME + ' ');   /* When I want to be timed out */
 | 
			
		||||
    data[2] = (MYPAD + ' ');    /* How much padding I need */
 | 
			
		||||
    data[3] = (MYPCHAR  ^ 64);   /* Padding character I want */
 | 
			
		||||
    data[4] = (MYEOL + ' ');    /* End-Of-Line character I want */
 | 
			
		||||
    data[5] = MYQUOTE;      /* Control-Quote character I send */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void KModem::setTransmitList(String **fileList, int numFiles)
 | 
			
		||||
{
 | 
			
		||||
  filelist = fileList;
 | 
			
		||||
  filecount = numFiles;
 | 
			
		||||
  filenum = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*  r p a r
 | 
			
		||||
 *
 | 
			
		||||
 *  Get the other host's send-init parameters
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
void KModem::rpar(char data[])
 | 
			
		||||
{
 | 
			
		||||
    spsiz = (data[0]- ' ');    /* Maximum send packet size */
 | 
			
		||||
    timint = (data[1]- ' ');   /* When I should time out */
 | 
			
		||||
    pad = (data[2]- ' ');    /* Number of pads to send */
 | 
			
		||||
    padchar = (data[3] ^ 64);   /* Padding character to send */
 | 
			
		||||
    eol = (data[4]- ' ');    /* EOL character I must send */
 | 
			
		||||
    quote = data[5];      /* Incoming data quote character */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 *  p r e r r p k t
 | 
			
		||||
 *
 | 
			
		||||
 *  Print contents of error packet received from remote host.
 | 
			
		||||
 */
 | 
			
		||||
void KModem::prerrpkt(char *msg)
 | 
			
		||||
{
 | 
			
		||||
  if(errStr != 0)
 | 
			
		||||
  {
 | 
			
		||||
    (*errStr)+=msg;
 | 
			
		||||
    debugPrintf("kermit: %s\n",msg);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,90 @@
 | 
			
		|||
#include <Arduino.h>
 | 
			
		||||
#ifdef INCLUDE_PING
 | 
			
		||||
/*
 | 
			
		||||
   Copyright 2023-2023 Bo Zimmerman
 | 
			
		||||
 | 
			
		||||
   Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
   you may not use this file except in compliance with the License.
 | 
			
		||||
   You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
     http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
   Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
   distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
   See the License for the specific language governing permissions and
 | 
			
		||||
   limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
#include "lwip/netdb.h"
 | 
			
		||||
#include "lwip/sockets.h"
 | 
			
		||||
#include "lwip/ip.h"
 | 
			
		||||
#include "lwip/icmp.h"
 | 
			
		||||
#include "lwip/inet_chksum.h"
 | 
			
		||||
#include "lwip/inet.h"
 | 
			
		||||
 | 
			
		||||
static int ping(char *host)
 | 
			
		||||
{
 | 
			
		||||
  IPAddress hostIp((uint32_t)0);
 | 
			
		||||
  if(!WiFiGenericClass::hostByName(host, hostIp)){
 | 
			
		||||
      return 1;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  const int socketfd = socket(AF_INET, SOCK_RAW, IP_PROTO_ICMP);
 | 
			
		||||
  if(socketfd < 0)
 | 
			
		||||
    return socketfd;
 | 
			
		||||
 | 
			
		||||
  const size_t pingpktLen = 10 + sizeof(struct icmp_echo_hdr);
 | 
			
		||||
  struct icmp_echo_hdr *pingpkt = (struct icmp_echo_hdr *)malloc(pingpktLen);
 | 
			
		||||
  ICMPH_TYPE_SET(pingpkt, ICMP_ECHO);
 | 
			
		||||
  ICMPH_CODE_SET(pingpkt, 0);
 | 
			
		||||
  pingpkt->id = 65535;
 | 
			
		||||
  pingpkt->seqno = htons(1);
 | 
			
		||||
  pingpkt->chksum = 0;
 | 
			
		||||
  pingpkt->chksum = inet_chksum(pingpkt, pingpktLen);
 | 
			
		||||
 | 
			
		||||
  ip4_addr_t outaddr;
 | 
			
		||||
  outaddr.addr = hostIp;
 | 
			
		||||
 | 
			
		||||
  struct sockaddr_in sockout;
 | 
			
		||||
  sockout.sin_len = sizeof(sockout);
 | 
			
		||||
  sockout.sin_family = AF_INET;
 | 
			
		||||
  inet_addr_from_ip4addr(&sockout.sin_addr, &outaddr);
 | 
			
		||||
  int ok = sendto(socketfd, pingpkt, pingpktLen, 0, (struct sockaddr*)&sockout, sizeof(sockout));
 | 
			
		||||
  free(pingpkt);
 | 
			
		||||
  if (ok == 0)
 | 
			
		||||
  {
 | 
			
		||||
    closesocket(socketfd);
 | 
			
		||||
    return -1;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  struct timeval timev;
 | 
			
		||||
  timev.tv_sec = 5;
 | 
			
		||||
  timev.tv_usec = 0;
 | 
			
		||||
  if(setsockopt(socketfd, SOL_SOCKET, SO_RCVTIMEO, &timev, sizeof(timev)) < 0)
 | 
			
		||||
  {
 | 
			
		||||
    closesocket(socketfd);
 | 
			
		||||
    return -1;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  uint8_t recvBuf[256];
 | 
			
		||||
  struct sockaddr_in inaddr;
 | 
			
		||||
  socklen_t inlen = 0;
 | 
			
		||||
  unsigned long time = millis();
 | 
			
		||||
 | 
			
		||||
  if(recvfrom(socketfd, recvBuf, 256, 0, (struct sockaddr*)&inaddr, &inlen) > 0)
 | 
			
		||||
  {
 | 
			
		||||
    unsigned long now = millis();
 | 
			
		||||
    if(now > time)
 | 
			
		||||
      time = now - time;
 | 
			
		||||
    else
 | 
			
		||||
      time = now;
 | 
			
		||||
    if(time > 65536)
 | 
			
		||||
      time = 65536;
 | 
			
		||||
  } else {
 | 
			
		||||
    closesocket(socketfd);
 | 
			
		||||
    return -1;
 | 
			
		||||
  }
 | 
			
		||||
  closesocket(socketfd);
 | 
			
		||||
  return (int)time;
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,364 @@
 | 
			
		|||
#include <Arduino.h>
 | 
			
		||||
/*
 | 
			
		||||
   Copyright 2018-2019 Bo Zimmerman
 | 
			
		||||
 | 
			
		||||
   Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
   you may not use this file except in compliance with the License.
 | 
			
		||||
   You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
     http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
   Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
   distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
   See the License for the specific language governing permissions and
 | 
			
		||||
   limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
#ifdef INCLUDE_SD_SHELL
 | 
			
		||||
 | 
			
		||||
XModem::XModem(File &f,
 | 
			
		||||
               FlowControlType commandFlow, 
 | 
			
		||||
               int (*recvChar)(ZSerial *ser, int msDelay), 
 | 
			
		||||
               void (*sendChar)(ZSerial *ser, char sym), 
 | 
			
		||||
               bool (*dataHandler)(File *xfile, unsigned long number, char *buffer, int len))
 | 
			
		||||
{
 | 
			
		||||
  this->xfile = &f;
 | 
			
		||||
  this->sendChar = sendChar;
 | 
			
		||||
  this->recvChar = recvChar;
 | 
			
		||||
  this->dataHandler = dataHandler;  
 | 
			
		||||
  this->xserial.setFlowControlType(FCT_DISABLED);
 | 
			
		||||
  if(commandFlow==FCT_RTSCTS)
 | 
			
		||||
    this->xserial.setFlowControlType(FCT_RTSCTS);
 | 
			
		||||
  this->xserial.setPetsciiMode(false);
 | 
			
		||||
  this->xserial.setXON(true);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool XModem::dataAvail(int delay)
 | 
			
		||||
{
 | 
			
		||||
  if (this->byte != -1)
 | 
			
		||||
    return true;
 | 
			
		||||
  if ((this->byte = this->recvChar(&xserial,delay)) != -1)
 | 
			
		||||
    return true;
 | 
			
		||||
  else
 | 
			
		||||
    return false;    
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int XModem::dataRead(int delay)
 | 
			
		||||
{
 | 
			
		||||
  int b;
 | 
			
		||||
  if(this->byte != -1)
 | 
			
		||||
  {
 | 
			
		||||
    b = this->byte;
 | 
			
		||||
    this->byte = -1;
 | 
			
		||||
    return b;
 | 
			
		||||
  }
 | 
			
		||||
  return this->recvChar(&xserial,delay);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void XModem::dataWrite(char symbol)
 | 
			
		||||
{
 | 
			
		||||
  this->sendChar(&xserial,symbol);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool XModem::receiveFrameNo()
 | 
			
		||||
{
 | 
			
		||||
  unsigned char num = (unsigned char)this->dataRead(XModem::receiveDelay);
 | 
			
		||||
  unsigned char invnum = (unsigned char)this-> dataRead(XModem::receiveDelay);
 | 
			
		||||
  this->repeatedBlock = false;
 | 
			
		||||
  //check for repeated block
 | 
			
		||||
  if (invnum == (255-num) && num == this->blockNo-1) {
 | 
			
		||||
    this->repeatedBlock = true;
 | 
			
		||||
    return true;  
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  if(num != this-> blockNo || invnum != (255-num))
 | 
			
		||||
    return false;
 | 
			
		||||
  else
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool XModem::receiveData()
 | 
			
		||||
{
 | 
			
		||||
  for(int i = 0; i < 128; i++) {
 | 
			
		||||
    int byte = this->dataRead(XModem::receiveDelay);
 | 
			
		||||
    if(byte != -1)
 | 
			
		||||
      this->buffer[i] = (unsigned char)byte;
 | 
			
		||||
    else
 | 
			
		||||
      return false;
 | 
			
		||||
  }
 | 
			
		||||
  return true;  
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool XModem::checkCrc()
 | 
			
		||||
{
 | 
			
		||||
  unsigned short frame_crc = ((unsigned char)this->dataRead(XModem::receiveDelay)) << 8;
 | 
			
		||||
  
 | 
			
		||||
  frame_crc |= (unsigned char)this->dataRead(XModem::receiveDelay);
 | 
			
		||||
  //now calculate crc on data
 | 
			
		||||
  unsigned short crc = this->crc16_ccitt(this->buffer, 128);
 | 
			
		||||
  
 | 
			
		||||
  if(frame_crc != crc)
 | 
			
		||||
    return false;
 | 
			
		||||
  else
 | 
			
		||||
    return true;  
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool XModem::checkChkSum()
 | 
			
		||||
{
 | 
			
		||||
  unsigned char frame_chksum = (unsigned char)this->dataRead(XModem::receiveDelay);
 | 
			
		||||
  //calculate chksum
 | 
			
		||||
  unsigned char chksum = 0;
 | 
			
		||||
  for(int i = 0; i< 128; i++) {
 | 
			
		||||
    chksum += this->buffer[i];
 | 
			
		||||
  }
 | 
			
		||||
  if(frame_chksum == chksum)
 | 
			
		||||
    return true;
 | 
			
		||||
  else
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool XModem::sendNack()
 | 
			
		||||
{
 | 
			
		||||
  this->dataWrite(XModem::XMO_NACK);  
 | 
			
		||||
  this->retries++;
 | 
			
		||||
  if(this->retries < XModem::rcvRetryLimit)
 | 
			
		||||
    return true;
 | 
			
		||||
  else
 | 
			
		||||
    return false;  
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool XModem::receiveFrames(transfer_t transfer)
 | 
			
		||||
{
 | 
			
		||||
  this->blockNo = 1;
 | 
			
		||||
  this->blockNoExt = 1;
 | 
			
		||||
  this->retries = 0;
 | 
			
		||||
  while (1) {
 | 
			
		||||
    char cmd = this->dataRead(1000);
 | 
			
		||||
    switch(cmd){
 | 
			
		||||
      case XModem::XMO_SOH:
 | 
			
		||||
        if (!this->receiveFrameNo()) {
 | 
			
		||||
          if (this->sendNack())
 | 
			
		||||
            break;
 | 
			
		||||
          else
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        if (!this->receiveData()) { 
 | 
			
		||||
          if (this->sendNack())
 | 
			
		||||
            break;
 | 
			
		||||
          else
 | 
			
		||||
            return false;          
 | 
			
		||||
        };
 | 
			
		||||
        if (transfer == Crc) {
 | 
			
		||||
          if (!this->checkCrc()) {
 | 
			
		||||
            if (this->sendNack())
 | 
			
		||||
              break;
 | 
			
		||||
            else
 | 
			
		||||
              return false;
 | 
			
		||||
          }
 | 
			
		||||
        } else {
 | 
			
		||||
          if(!this->checkChkSum()) {
 | 
			
		||||
            if (this->sendNack())
 | 
			
		||||
              break;
 | 
			
		||||
            else
 | 
			
		||||
              return false;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
        //callback
 | 
			
		||||
        if(this->dataHandler != NULL && this->repeatedBlock == false)
 | 
			
		||||
          if(!this->dataHandler(xfile,this->blockNoExt, this->buffer, 128)) {
 | 
			
		||||
            return false;
 | 
			
		||||
          }
 | 
			
		||||
        //ack
 | 
			
		||||
        this->dataWrite(XModem::XMO_ACK);
 | 
			
		||||
        if(this->repeatedBlock == false)
 | 
			
		||||
        {
 | 
			
		||||
          this->blockNo++;
 | 
			
		||||
          this->blockNoExt++;
 | 
			
		||||
        }
 | 
			
		||||
        break;
 | 
			
		||||
      case XModem::XMO_EOT:
 | 
			
		||||
        this->dataWrite(XModem::XMO_ACK);
 | 
			
		||||
        return true;
 | 
			
		||||
      case XModem::XMO_CAN:
 | 
			
		||||
        //wait second CAN
 | 
			
		||||
        if(this->dataRead(XModem::receiveDelay) ==XModem::XMO_CAN) 
 | 
			
		||||
        {
 | 
			
		||||
          this->dataWrite(XModem::XMO_ACK);
 | 
			
		||||
          //this->flushInput();
 | 
			
		||||
          return false;
 | 
			
		||||
        }
 | 
			
		||||
        //something wrong
 | 
			
		||||
        this->dataWrite(XModem::XMO_CAN);
 | 
			
		||||
        this->dataWrite(XModem::XMO_CAN);
 | 
			
		||||
        this->dataWrite(XModem::XMO_CAN);
 | 
			
		||||
        return false;
 | 
			
		||||
      default:
 | 
			
		||||
        //something wrong
 | 
			
		||||
        this->dataWrite(XModem::XMO_CAN);
 | 
			
		||||
        this->dataWrite(XModem::XMO_CAN);
 | 
			
		||||
        this->dataWrite(XModem::XMO_CAN);
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void XModem::init()
 | 
			
		||||
{
 | 
			
		||||
  //set preread byte    
 | 
			
		||||
  this->byte = -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool XModem::receive()
 | 
			
		||||
{
 | 
			
		||||
  this->init();
 | 
			
		||||
  
 | 
			
		||||
  for (int i =0; i <  16; i++)
 | 
			
		||||
  {
 | 
			
		||||
    this->dataWrite('C'); 
 | 
			
		||||
    if (this->dataAvail(1500)) 
 | 
			
		||||
    {
 | 
			
		||||
      bool ok = receiveFrames(Crc);
 | 
			
		||||
      xserial.flushAlways();
 | 
			
		||||
      return ok;
 | 
			
		||||
    }
 | 
			
		||||
  
 | 
			
		||||
  }
 | 
			
		||||
  for (int i =0; i <  16; i++)
 | 
			
		||||
  {
 | 
			
		||||
    this->dataWrite(XModem::XMO_NACK);  
 | 
			
		||||
    if (this->dataAvail(1500)) 
 | 
			
		||||
    {
 | 
			
		||||
      bool ok = receiveFrames(ChkSum);
 | 
			
		||||
      xserial.flushAlways();
 | 
			
		||||
      return ok;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
unsigned short XModem::crc16_ccitt(char *buf, int size)
 | 
			
		||||
{
 | 
			
		||||
  unsigned short crc = 0;
 | 
			
		||||
  while (--size >= 0) {
 | 
			
		||||
    int i;
 | 
			
		||||
    crc ^= (unsigned short) *buf++ << 8;
 | 
			
		||||
    for (i = 0; i < 8; i++)
 | 
			
		||||
      if (crc & 0x8000)
 | 
			
		||||
        crc = crc << 1 ^ 0x1021;
 | 
			
		||||
      else
 | 
			
		||||
        crc <<= 1;
 | 
			
		||||
  }
 | 
			
		||||
  return crc;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
unsigned char XModem::generateChkSum(void)
 | 
			
		||||
{
 | 
			
		||||
  //calculate chksum
 | 
			
		||||
  unsigned char chksum = 0;
 | 
			
		||||
  for(int i = 0; i< 128; i++) {
 | 
			
		||||
    chksum += this->buffer[i];
 | 
			
		||||
  }
 | 
			
		||||
  return chksum;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool XModem::transmitFrames(transfer_t transfer)
 | 
			
		||||
{
 | 
			
		||||
  this->blockNo = 1;
 | 
			
		||||
  this->blockNoExt = 1;
 | 
			
		||||
  // use this only in unit tetsing
 | 
			
		||||
  //memset(this->buffer, 'A', 128);
 | 
			
		||||
  while(1)
 | 
			
		||||
  {
 | 
			
		||||
    //get data
 | 
			
		||||
    if (this->dataHandler != NULL)
 | 
			
		||||
    {
 | 
			
		||||
      if( false == this->dataHandler(xfile,this->blockNoExt, this->buffer, 128))
 | 
			
		||||
      {
 | 
			
		||||
        //end of transfer
 | 
			
		||||
        this->sendChar(&xserial,XModem::XMO_EOT);
 | 
			
		||||
        //wait ACK
 | 
			
		||||
        if (this->dataRead(XModem::receiveDelay) == XModem::XMO_ACK)
 | 
			
		||||
          return true;
 | 
			
		||||
        else
 | 
			
		||||
          return false;
 | 
			
		||||
      }           
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
      //cancel transfer - send CAN twice
 | 
			
		||||
      this->sendChar(&xserial,XModem::XMO_CAN);
 | 
			
		||||
      this->sendChar(&xserial,XModem::XMO_CAN);
 | 
			
		||||
      //wait ACK
 | 
			
		||||
      if (this->dataRead(XModem::receiveDelay) == XModem::XMO_ACK)
 | 
			
		||||
        return true;
 | 
			
		||||
      else
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
    //send SOH
 | 
			
		||||
    this->sendChar(&xserial,XModem::XMO_SOH);
 | 
			
		||||
    //send frame number 
 | 
			
		||||
    this->sendChar(&xserial,this->blockNo);
 | 
			
		||||
    //send inv frame number
 | 
			
		||||
    this->sendChar(&xserial,(unsigned char)(255-(this->blockNo)));
 | 
			
		||||
    //send data
 | 
			
		||||
    for(int i = 0; i <128; i++)
 | 
			
		||||
      this->sendChar(&xserial,this->buffer[i]);
 | 
			
		||||
    //send checksum or crc
 | 
			
		||||
    if (transfer == ChkSum) {
 | 
			
		||||
      this->sendChar(&xserial,this->generateChkSum());
 | 
			
		||||
    } else {
 | 
			
		||||
      unsigned short crc;
 | 
			
		||||
      crc = this->crc16_ccitt(this->buffer, 128);
 | 
			
		||||
      
 | 
			
		||||
      this->sendChar(&xserial,(unsigned char)(crc >> 8));
 | 
			
		||||
      this->sendChar(&xserial,(unsigned char)(crc));
 | 
			
		||||
       
 | 
			
		||||
    }
 | 
			
		||||
   //TO DO - wait NACK or CAN or ACK
 | 
			
		||||
    int ret = this->dataRead(XModem::receiveDelay);
 | 
			
		||||
    switch(ret)
 | 
			
		||||
    {
 | 
			
		||||
      case XModem::XMO_ACK: //data is ok - go to next chunk
 | 
			
		||||
        this->blockNo++;
 | 
			
		||||
        this->blockNoExt++;
 | 
			
		||||
        continue;
 | 
			
		||||
      case XModem::XMO_NACK: //resend data
 | 
			
		||||
        continue;
 | 
			
		||||
      case XModem::XMO_CAN: //abort transmision
 | 
			
		||||
        return false;
 | 
			
		||||
    }  
 | 
			
		||||
  }
 | 
			
		||||
  return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool XModem::transmit()
 | 
			
		||||
{
 | 
			
		||||
  int retry = 0;
 | 
			
		||||
  int sym;
 | 
			
		||||
  this->init();
 | 
			
		||||
  
 | 
			
		||||
  //wait for CRC transfer
 | 
			
		||||
  while(retry < 32)
 | 
			
		||||
  {
 | 
			
		||||
    if(this->dataAvail(1000))
 | 
			
		||||
    {
 | 
			
		||||
      sym = this->dataRead(1); //data is here - no delay
 | 
			
		||||
      if(sym == 'C')
 | 
			
		||||
      {
 | 
			
		||||
        bool ok = this->transmitFrames(Crc);
 | 
			
		||||
        xserial.flushAlways();
 | 
			
		||||
        return ok;
 | 
			
		||||
      }
 | 
			
		||||
      if(sym == XModem::XMO_NACK)
 | 
			
		||||
      {
 | 
			
		||||
        bool ok = this->transmitFrames(ChkSum);
 | 
			
		||||
        xserial.flushAlways();
 | 
			
		||||
        return ok;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    retry++;
 | 
			
		||||
  } 
 | 
			
		||||
  return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| 
						 | 
				
			
			@ -0,0 +1,703 @@
 | 
			
		|||
#include <Arduino.h>
 | 
			
		||||
/*
 | 
			
		||||
   Copyright 2016-2019 Bo Zimmerman
 | 
			
		||||
 | 
			
		||||
   Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
   you may not use this file except in compliance with the License.
 | 
			
		||||
   You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
     http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
   Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
   distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
   See the License for the specific language governing permissions and
 | 
			
		||||
   limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
#include <math.h>
 | 
			
		||||
#define htonl(x) ( ((x)<<24 & 0xFF000000UL) | \
 | 
			
		||||
                   ((x)<< 8 & 0x00FF0000UL) | \
 | 
			
		||||
                   ((x)>> 8 & 0x0000FF00UL) | \
 | 
			
		||||
                   ((x)>>24 & 0x000000FFUL) )
 | 
			
		||||
 | 
			
		||||
const int NTP_PACKET_SIZE = 48;
 | 
			
		||||
 | 
			
		||||
uint8_t DAYS_IN_MONTH[13] PROGMEM = {
 | 
			
		||||
    31,28,31,30,31,30,31,31,30,31,30,31
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
char *uintToStr( const uint64_t num, char *str )
 | 
			
		||||
{
 | 
			
		||||
  uint8_t i = 0;
 | 
			
		||||
  uint64_t n = num;
 | 
			
		||||
  do
 | 
			
		||||
    i++;
 | 
			
		||||
  while ( n /= 10 );
 | 
			
		||||
  str[i] = '\0';
 | 
			
		||||
  n = num;
 | 
			
		||||
  do
 | 
			
		||||
    str[--i] = ( n % 10 ) + '0';
 | 
			
		||||
  while ( n /= 10 );
 | 
			
		||||
  return str;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DateTimeClock::DateTimeClock() : DateTimeClock(0)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
DateTimeClock::DateTimeClock(uint32_t epochSecs)
 | 
			
		||||
{
 | 
			
		||||
  setByUnixEpoch(epochSecs);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DateTimeClock::DateTimeClock(int y, int m, int d, int h, int mn, int s, int mi)
 | 
			
		||||
{
 | 
			
		||||
  year=y;
 | 
			
		||||
  month=m;
 | 
			
		||||
  day=d;
 | 
			
		||||
  hour=h;
 | 
			
		||||
  min=mn;
 | 
			
		||||
  sec=s;
 | 
			
		||||
  milsec=mi;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
RealTimeClock::RealTimeClock(uint32_t epochSecs) : DateTimeClock(epochSecs)
 | 
			
		||||
{
 | 
			
		||||
  lastMillis = millis();
 | 
			
		||||
  nextNTPMillis = millis();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
RealTimeClock::RealTimeClock() : DateTimeClock()
 | 
			
		||||
{
 | 
			
		||||
  lastMillis = millis();
 | 
			
		||||
  nextNTPMillis = millis();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
RealTimeClock::RealTimeClock(int y, int m, int d, int h, int mn, int s, int mi) :
 | 
			
		||||
    DateTimeClock(y,m,d,h,mn,s,mi)
 | 
			
		||||
{
 | 
			
		||||
  lastMillis = millis();
 | 
			
		||||
  nextNTPMillis = millis();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void RealTimeClock::startUdp()
 | 
			
		||||
{
 | 
			
		||||
  if(!udpStarted)
 | 
			
		||||
  {
 | 
			
		||||
    udpStarted=udp.begin(2390);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void RealTimeClock::tick()
 | 
			
		||||
{
 | 
			
		||||
  if(disabled)
 | 
			
		||||
    return;
 | 
			
		||||
  if(udpStarted)
 | 
			
		||||
  {
 | 
			
		||||
    int cb = udp.parsePacket();
 | 
			
		||||
    if (cb) 
 | 
			
		||||
    {
 | 
			
		||||
      // adapted from code by  by Michael Margolis, Tom Igoe, and Ivan Grokhotkov
 | 
			
		||||
      //debugPrint("Packet received, length=%d\n\r",cb);
 | 
			
		||||
      byte packetBuffer[ NTP_PACKET_SIZE];
 | 
			
		||||
      udp.read(packetBuffer, NTP_PACKET_SIZE); // read the packet into the buffer
 | 
			
		||||
      // combine the four bytes (two words) into a long integer
 | 
			
		||||
      // this is NTP time (seconds since Jan 1 1900):
 | 
			
		||||
      uint32_t secsSince1900 = htonl(*((uint32_t *)(packetBuffer + 40))); 
 | 
			
		||||
      // Unix time starts on Jan 1 1970. In seconds, that's 2208988800:
 | 
			
		||||
      const uint32_t seventyYears = 2208988800UL;
 | 
			
		||||
      // subtract seventy years:
 | 
			
		||||
      uint32_t epoch = secsSince1900 - seventyYears;
 | 
			
		||||
      lastMillis = millis();
 | 
			
		||||
      // now to apply the timezone.  Ugh;
 | 
			
		||||
      setByUnixEpoch(epoch);
 | 
			
		||||
      String tz="";
 | 
			
		||||
      {
 | 
			
		||||
        char s=0;
 | 
			
		||||
        char c=pgm_read_byte_near(&(TimeZones[tzCode][1][s]));
 | 
			
		||||
        while(c != 0)
 | 
			
		||||
        {
 | 
			
		||||
          tz += c;
 | 
			
		||||
          c=pgm_read_byte_near(&(TimeZones[tzCode][1][++s]));
 | 
			
		||||
        }
 | 
			
		||||
        String otz=tz;
 | 
			
		||||
        int x=tz.indexOf("/");
 | 
			
		||||
        if(x > 0)
 | 
			
		||||
        {
 | 
			
		||||
          if(isInStandardTime())
 | 
			
		||||
            tz = tz.substring(0,x);
 | 
			
		||||
          else
 | 
			
		||||
            tz = tz.substring(x+1);
 | 
			
		||||
        }
 | 
			
		||||
        x=tz.indexOf(":");
 | 
			
		||||
        int mm=0;
 | 
			
		||||
        if(x > 0)
 | 
			
		||||
        {
 | 
			
		||||
          mm = atoi(tz.substring(x+1).c_str());
 | 
			
		||||
          tz = tz.substring(0,x);
 | 
			
		||||
        }
 | 
			
		||||
        uint32_t echg = (atoi(tz.c_str()) * 3600);
 | 
			
		||||
        echg += ((echg < 0)?(-(mm * 60)):(mm * 60));
 | 
			
		||||
        setByUnixEpoch(epoch + echg);
 | 
			
		||||
        debugPrintf("Received NTP: %d/%d/%d %d:%d:%d\n\r",(int)getMonth(),(int)getDay(),(int)getYear(),(int)getHour(),(int)getMinute(),(int)getSecond());
 | 
			
		||||
      }
 | 
			
		||||
      nextNTPMillis = millis() + ntpPeriodLongMillis; // one hour
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
      uint32_t now=millis();
 | 
			
		||||
      if(nextNTPMillis >= now)
 | 
			
		||||
      {
 | 
			
		||||
        if(((nextNTPMillis - now) > ntpPeriodLongMillis)
 | 
			
		||||
        ||(nextNTPMillis == now))
 | 
			
		||||
          forceUpdate();
 | 
			
		||||
      }
 | 
			
		||||
      else
 | 
			
		||||
      if((now - nextNTPMillis) > ntpPeriodLongMillis)
 | 
			
		||||
        forceUpdate();
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void RealTimeClock::forceUpdate()
 | 
			
		||||
{
 | 
			
		||||
  if(!disabled)
 | 
			
		||||
  {
 | 
			
		||||
    nextNTPMillis = millis() + ntpPeriodMillis;
 | 
			
		||||
    startUdp();
 | 
			
		||||
    sendTimeRequest();
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool RealTimeClock::isTimeSet()
 | 
			
		||||
{
 | 
			
		||||
  return (year > 1000);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool RealTimeClock::reset()
 | 
			
		||||
{
 | 
			
		||||
  year=0;
 | 
			
		||||
  month=0;
 | 
			
		||||
  day=0;
 | 
			
		||||
  hour=0;
 | 
			
		||||
  min=0;
 | 
			
		||||
  sec=0;
 | 
			
		||||
  milsec=0;
 | 
			
		||||
  lastMillis = millis();
 | 
			
		||||
  nextNTPMillis = millis();
 | 
			
		||||
  tzCode = 0;
 | 
			
		||||
  format="%M/%d/%yyyy %h:%mm:%ss%aa %z";
 | 
			
		||||
  ntpServerName = "time.nist.gov";
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int DateTimeClock::getYear()
 | 
			
		||||
{
 | 
			
		||||
  return year;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void DateTimeClock::setYear(int y)
 | 
			
		||||
{
 | 
			
		||||
  year=y;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void DateTimeClock::addYear(uint32_t y)
 | 
			
		||||
{
 | 
			
		||||
  year+=y;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int DateTimeClock::getMonth()
 | 
			
		||||
{
 | 
			
		||||
  return month + 1; // because 0 based
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void DateTimeClock::setMonth(int m)
 | 
			
		||||
{
 | 
			
		||||
  month = m % 12;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void DateTimeClock::addMonth(uint32_t m)
 | 
			
		||||
{
 | 
			
		||||
  m = month + m;
 | 
			
		||||
  if(m > 11)
 | 
			
		||||
    addYear(floor(m / 12));
 | 
			
		||||
  setMonth(m);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int DateTimeClock::getDay()
 | 
			
		||||
{
 | 
			
		||||
  return day + 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void DateTimeClock::setDay(int d)
 | 
			
		||||
{
 | 
			
		||||
  day = d % getDaysInThisMonth();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void DateTimeClock::addDay(uint32_t d)
 | 
			
		||||
{
 | 
			
		||||
  d = day + d;
 | 
			
		||||
  if(d >= getDaysInThisMonth())
 | 
			
		||||
  {
 | 
			
		||||
    while(d > (isLeapYear()?366:365))
 | 
			
		||||
    {
 | 
			
		||||
      d=d-(isLeapYear()?366:365);
 | 
			
		||||
      addYear(1);
 | 
			
		||||
    }
 | 
			
		||||
    while(d >= getDaysInThisMonth())
 | 
			
		||||
    {
 | 
			
		||||
      d=d-getDaysInThisMonth();
 | 
			
		||||
      addMonth(1);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  setDay(d);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int DateTimeClock::getHour()
 | 
			
		||||
{
 | 
			
		||||
  return hour;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void DateTimeClock::setHour(int h)
 | 
			
		||||
{
 | 
			
		||||
  hour=h % 24;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void DateTimeClock::addHour(uint32_t h)
 | 
			
		||||
{
 | 
			
		||||
  h=hour + h;
 | 
			
		||||
  if(h > 23)
 | 
			
		||||
    addDay(floor(h / 24));
 | 
			
		||||
  setHour(h);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int DateTimeClock::getMinute()
 | 
			
		||||
{
 | 
			
		||||
  return min;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void DateTimeClock::setMinute(int mm)
 | 
			
		||||
{
 | 
			
		||||
  min=mm % 60;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void DateTimeClock::addMinute(uint32_t mm)
 | 
			
		||||
{
 | 
			
		||||
  mm = min+mm;
 | 
			
		||||
  if(mm > 59)
 | 
			
		||||
    addHour(floor(mm / 60));
 | 
			
		||||
  setMinute(mm);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int DateTimeClock::getSecond()
 | 
			
		||||
{
 | 
			
		||||
  return sec;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void DateTimeClock::setSecond(int s)
 | 
			
		||||
{
 | 
			
		||||
  sec=s % 60;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void DateTimeClock::addSecond(uint32_t s)
 | 
			
		||||
{
 | 
			
		||||
  s = sec + s;
 | 
			
		||||
  if(s > 59)
 | 
			
		||||
    addMinute(floor(s / 60));
 | 
			
		||||
  setSecond(s);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int DateTimeClock::getMillis()
 | 
			
		||||
{
 | 
			
		||||
  return milsec;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void DateTimeClock::setMillis(int s)
 | 
			
		||||
{
 | 
			
		||||
  milsec=s % 1000;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void DateTimeClock::addMillis(uint64_t s)
 | 
			
		||||
{
 | 
			
		||||
  s = milsec+s;
 | 
			
		||||
  if(s > 999)
 | 
			
		||||
    addSecond(floor(s / 1000));
 | 
			
		||||
  setMillis(s);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool DateTimeClock::isLeapYear()
 | 
			
		||||
{
 | 
			
		||||
  if(year % 4 == 0)
 | 
			
		||||
  {
 | 
			
		||||
    if(year % 100 == 0)
 | 
			
		||||
    {
 | 
			
		||||
      if(year % 400 == 0)
 | 
			
		||||
        return true;
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
  return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint8_t DateTimeClock::getDaysInThisMonth()
 | 
			
		||||
{
 | 
			
		||||
  if(month != 1) // feb exception
 | 
			
		||||
    return pgm_read_byte_near(DAYS_IN_MONTH + month);
 | 
			
		||||
  return (isLeapYear() ? 29 : 28);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void DateTimeClock::setTime(DateTimeClock &clock)
 | 
			
		||||
{
 | 
			
		||||
  year=clock.year;
 | 
			
		||||
  month=clock.month;
 | 
			
		||||
  day=clock.day;
 | 
			
		||||
  hour=clock.hour;
 | 
			
		||||
  min=clock.min;
 | 
			
		||||
  sec=clock.sec;
 | 
			
		||||
  milsec=clock.milsec;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
DateTimeClock &RealTimeClock::getCurrentTime()
 | 
			
		||||
{
 | 
			
		||||
  adjClock.setTime(*this);
 | 
			
		||||
  uint32_t now=millis();
 | 
			
		||||
  if(lastMillis <= now)
 | 
			
		||||
    adjClock.addMillis(now - lastMillis);
 | 
			
		||||
  else
 | 
			
		||||
    adjClock.addMillis(now + (0xffffffff - lastMillis));
 | 
			
		||||
  return adjClock;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void DateTimeClock::setByUnixEpoch(uint32_t unisex)
 | 
			
		||||
{
 | 
			
		||||
  setYear(1970);
 | 
			
		||||
  setMonth(0);
 | 
			
		||||
  setDay(0);
 | 
			
		||||
  setHour(0);
 | 
			
		||||
  setMinute(0);
 | 
			
		||||
  setSecond(0);
 | 
			
		||||
  setMillis(0);
 | 
			
		||||
  uint64_t ms = unisex;
 | 
			
		||||
  ms *= 1000L;
 | 
			
		||||
  addMillis(ms);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint32_t DateTimeClock::getUnixEpoch()
 | 
			
		||||
{
 | 
			
		||||
  if(year < 1970)
 | 
			
		||||
    return 0;
 | 
			
		||||
  uint32_t val = sec + (min * 60) + (hour * 60 * 60);
 | 
			
		||||
  //TODO:
 | 
			
		||||
  return val;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool RealTimeClock::sendTimeRequest()
 | 
			
		||||
{
 | 
			
		||||
  if((WiFi.status() == WL_CONNECTED)&&(udpStarted))
 | 
			
		||||
  {
 | 
			
		||||
    // adapted from code by  by Michael Margolis, Tom Igoe, and Ivan Grokhotkov
 | 
			
		||||
    debugPrintf("Sending NTP Packet...");
 | 
			
		||||
    byte packetBuffer[ NTP_PACKET_SIZE];
 | 
			
		||||
    memset(packetBuffer, 0, NTP_PACKET_SIZE);
 | 
			
		||||
    packetBuffer[0] = 0b11100011;   // LI, Version, Mode
 | 
			
		||||
    packetBuffer[1] = 0;     // Stratum, or type of clock
 | 
			
		||||
    packetBuffer[2] = 6;     // Polling Interval
 | 
			
		||||
    packetBuffer[3] = 0xEC;  // Peer Clock Precision
 | 
			
		||||
    // 8 bytes of zero for Root Delay & Root Dispersion
 | 
			
		||||
    packetBuffer[12]  = 49;
 | 
			
		||||
    packetBuffer[13]  = 0x4E;
 | 
			
		||||
    packetBuffer[14]  = 49;
 | 
			
		||||
    packetBuffer[15]  = 52;
 | 
			
		||||
    IPAddress timeServerIP;
 | 
			
		||||
    String host = ntpServerName;
 | 
			
		||||
    int port=123;
 | 
			
		||||
    int pi=host.indexOf(':');
 | 
			
		||||
    if(pi>0)
 | 
			
		||||
    {
 | 
			
		||||
      port=atoi(host.substring(pi+1).c_str());
 | 
			
		||||
      host = host.substring(0,pi);
 | 
			
		||||
    }
 | 
			
		||||
    WiFi.hostByName(ntpServerName.c_str(), timeServerIP);
 | 
			
		||||
    udp.beginPacket(timeServerIP, port); //NTP requests are to port 123
 | 
			
		||||
    udp.write(packetBuffer, NTP_PACKET_SIZE);
 | 
			
		||||
    udp.endPacket();
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
  return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int DateTimeClock::getDoWNumber()
 | 
			
		||||
{
 | 
			
		||||
  uint16_t x= (getMonth() + 9) % 12;
 | 
			
		||||
  uint16_t y = getYear() - x/10;
 | 
			
		||||
  uint32_t z= 365*y + y/4 - y/100 + y/400 + (x*306 + 5)/10 + (getDay() - 1);
 | 
			
		||||
  z=z%7;
 | 
			
		||||
  if(z>3)
 | 
			
		||||
    return z-4;
 | 
			
		||||
  else
 | 
			
		||||
    return z+3;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const char *DateTimeClock::getDoW()
 | 
			
		||||
{
 | 
			
		||||
  int num=getDoWNumber();
 | 
			
		||||
  switch(num)
 | 
			
		||||
  {
 | 
			
		||||
  case 0:return "Sunday";
 | 
			
		||||
  case 1:return "Monday";
 | 
			
		||||
  case 2:return "Tuesday";
 | 
			
		||||
  case 3:return "Wednesday";
 | 
			
		||||
  case 4:return "Thursday";
 | 
			
		||||
  case 5:return "Friday";
 | 
			
		||||
  case 6:return "Saturday";
 | 
			
		||||
  default: return "Broken";
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool DateTimeClock::isInStandardTime()
 | 
			
		||||
{
 | 
			
		||||
  uint8_t m=getMonth();
 | 
			
		||||
  if(m<3)
 | 
			
		||||
    return true;
 | 
			
		||||
  if(m==3)
 | 
			
		||||
  {
 | 
			
		||||
    uint8_t d=getDay();
 | 
			
		||||
    uint8_t dow=getDoWNumber();
 | 
			
		||||
    while(dow-- > 0)
 | 
			
		||||
      d--;
 | 
			
		||||
    if(d<14)
 | 
			
		||||
      return true;
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
  if((m>3)&&(m<11))
 | 
			
		||||
    return false;
 | 
			
		||||
  if(m==11)
 | 
			
		||||
  {
 | 
			
		||||
    uint8_t d=getDay();
 | 
			
		||||
    uint8_t dow=getDoWNumber();
 | 
			
		||||
    while(dow-- > 0)
 | 
			
		||||
      d--;
 | 
			
		||||
    if(d<7)
 | 
			
		||||
      return false;
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool DateTimeClock::isInDaylightSavingsTime()
 | 
			
		||||
{
 | 
			
		||||
  return !isInStandardTime();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int RealTimeClock::getTimeZoneCode()
 | 
			
		||||
{
 | 
			
		||||
  return tzCode;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void RealTimeClock::setTimeZoneCode(int val)
 | 
			
		||||
{
 | 
			
		||||
  if((tzCode >= 0)&&(tzCode < 243))
 | 
			
		||||
  {
 | 
			
		||||
    tzCode = val;
 | 
			
		||||
    forceUpdate();
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool RealTimeClock::setTimeZone(String str)
 | 
			
		||||
{
 | 
			
		||||
  str.toUpperCase();
 | 
			
		||||
  if(str.length()==0)
 | 
			
		||||
    return false;
 | 
			
		||||
  for(int i=0;i<243;i++)
 | 
			
		||||
  {
 | 
			
		||||
    for(int s=0;s<=str.length();s++)
 | 
			
		||||
    {
 | 
			
		||||
      char c=pgm_read_byte_near(&(TimeZones[i][0][s]));
 | 
			
		||||
      if(s==str.length())
 | 
			
		||||
      {
 | 
			
		||||
        if(c==0)
 | 
			
		||||
        {
 | 
			
		||||
          tzCode = i;
 | 
			
		||||
          forceUpdate();
 | 
			
		||||
          return true;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      else
 | 
			
		||||
      if((c==0)||(c != str[s]))
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
String RealTimeClock::getFormat()
 | 
			
		||||
{
 | 
			
		||||
  return format;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void RealTimeClock::setFormat(String fmt)
 | 
			
		||||
{
 | 
			
		||||
  fmt.replace(',','.');
 | 
			
		||||
  format = fmt;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool RealTimeClock::isDisabled()
 | 
			
		||||
{
 | 
			
		||||
  return disabled;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void RealTimeClock::setDisabled(bool tf)
 | 
			
		||||
{
 | 
			
		||||
  disabled=tf;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
String RealTimeClock::getCurrentTimeFormatted()
 | 
			
		||||
{
 | 
			
		||||
  //String format="%M/%D/%YYYY %h:%mm:%ss%a"
 | 
			
		||||
  DateTimeClock c = getCurrentTime();
 | 
			
		||||
  String f=format;
 | 
			
		||||
  if(f.indexOf("%yyyy")>=0)
 | 
			
		||||
  {
 | 
			
		||||
    sprintf(str,"%04d",(int)c.getYear());
 | 
			
		||||
    f.replace("%yyyy",str);
 | 
			
		||||
  }
 | 
			
		||||
  if(f.indexOf("%yy")>=0)
 | 
			
		||||
  {
 | 
			
		||||
    int y=c.getYear();
 | 
			
		||||
    y -= (floor(y/100)*100);
 | 
			
		||||
    sprintf(str,"%02d",y);
 | 
			
		||||
    f.replace("%yy",str);
 | 
			
		||||
  }
 | 
			
		||||
  if(f.indexOf("%y")>=0)
 | 
			
		||||
  {
 | 
			
		||||
    sprintf(str,"%d",(int)c.getYear());
 | 
			
		||||
    f.replace("%y",str);
 | 
			
		||||
  }
 | 
			
		||||
  if(f.indexOf("%MM")>=0)
 | 
			
		||||
  {
 | 
			
		||||
    sprintf(str,"%02d",(int)c.getMonth());
 | 
			
		||||
    f.replace("%MM",str);
 | 
			
		||||
  }
 | 
			
		||||
  if(f.indexOf("%M")>=0)
 | 
			
		||||
  {
 | 
			
		||||
    sprintf(str,"%d",(int)c.getMonth());
 | 
			
		||||
    f.replace("%M",str);
 | 
			
		||||
  }
 | 
			
		||||
  if(f.indexOf("%dd")>=0)
 | 
			
		||||
  {
 | 
			
		||||
    sprintf(str,"%02d",(int)c.getDay());
 | 
			
		||||
    f.replace("%dd",str);
 | 
			
		||||
  }
 | 
			
		||||
  if(f.indexOf("%d")>=0)
 | 
			
		||||
  {
 | 
			
		||||
    sprintf(str,"%d",(int)c.getDay());
 | 
			
		||||
    f.replace("%d",str);
 | 
			
		||||
  }
 | 
			
		||||
  if(f.indexOf("%ee")>=0)
 | 
			
		||||
  {
 | 
			
		||||
    f.replace("%ee",c.getDoW());
 | 
			
		||||
  }
 | 
			
		||||
  if(f.indexOf("%e")>=0)
 | 
			
		||||
  {
 | 
			
		||||
    String dow=c.getDoW();
 | 
			
		||||
    dow = dow.substring(0,3);
 | 
			
		||||
    sprintf(str,"%d",dow.c_str());
 | 
			
		||||
    f.replace("%e",str);
 | 
			
		||||
  }
 | 
			
		||||
  if(f.indexOf("%HH")>=0)
 | 
			
		||||
  {
 | 
			
		||||
    sprintf(str,"%02d",(int)c.getHour());
 | 
			
		||||
    f.replace("%HH",str);
 | 
			
		||||
  }
 | 
			
		||||
  if(f.indexOf("%H")>=0)
 | 
			
		||||
  {
 | 
			
		||||
    sprintf(str,"%d",(int)c.getHour());
 | 
			
		||||
    f.replace("%H",str);
 | 
			
		||||
  }
 | 
			
		||||
  if(f.indexOf("%hh")>=0)
 | 
			
		||||
  {
 | 
			
		||||
    if((c.getHour()%12)==0)
 | 
			
		||||
      strcpy(str,"12");
 | 
			
		||||
    else
 | 
			
		||||
      sprintf(str,"%02d",c.getHour()%12);
 | 
			
		||||
    f.replace("%hh",str);
 | 
			
		||||
  }
 | 
			
		||||
  if(f.indexOf("%h")>=0)
 | 
			
		||||
  {
 | 
			
		||||
    if((c.getHour()%12)==0)
 | 
			
		||||
      strcpy(str,"12");
 | 
			
		||||
    else
 | 
			
		||||
      sprintf(str,"%d",(int)(c.getHour() % 12));
 | 
			
		||||
    f.replace("%h",str);
 | 
			
		||||
  }
 | 
			
		||||
  if(f.indexOf("%mm")>=0)
 | 
			
		||||
  {
 | 
			
		||||
    sprintf(str,"%02d",(int)c.getMinute());
 | 
			
		||||
    f.replace("%mm",str);
 | 
			
		||||
  }
 | 
			
		||||
  if(f.indexOf("%m")>=0)
 | 
			
		||||
  {
 | 
			
		||||
    sprintf(str,"%d",(int)c.getMinute());
 | 
			
		||||
    f.replace("%m",str);
 | 
			
		||||
  }
 | 
			
		||||
  if(f.indexOf("%ss")>=0)
 | 
			
		||||
  {
 | 
			
		||||
    sprintf(str,"%02d",(int)c.getSecond());
 | 
			
		||||
    f.replace("%ss",str);
 | 
			
		||||
  }
 | 
			
		||||
  if(f.indexOf("%s")>=0)
 | 
			
		||||
  {
 | 
			
		||||
    sprintf(str,"%d",(int)c.getSecond());
 | 
			
		||||
    f.replace("%s",str);
 | 
			
		||||
  }
 | 
			
		||||
  if(f.indexOf("%AA")>=0)
 | 
			
		||||
    f.replace("%AA",(c.getHour()<12)?"AM":"PM");
 | 
			
		||||
  if(f.indexOf("%aa")>=0)
 | 
			
		||||
    f.replace("%aa",(c.getHour()<12)?"am":"pm");
 | 
			
		||||
  if(f.indexOf("%A")>=0)
 | 
			
		||||
    f.replace("%A",(c.getHour()<12)?"A":"P");
 | 
			
		||||
  if(f.indexOf("%a")>=0)
 | 
			
		||||
    f.replace("%a",(c.getHour()<12)?"a":"p");
 | 
			
		||||
  if(f.indexOf("%z")>=0)
 | 
			
		||||
  {
 | 
			
		||||
    String z="";
 | 
			
		||||
    char s=0;
 | 
			
		||||
    char c=pgm_read_byte_near(&(TimeZones[tzCode][0][s]));
 | 
			
		||||
    while(c != 0)
 | 
			
		||||
    {
 | 
			
		||||
      z += c;
 | 
			
		||||
      c=pgm_read_byte_near(&(TimeZones[tzCode][0][++s]));
 | 
			
		||||
    }
 | 
			
		||||
    z.toLowerCase();
 | 
			
		||||
    f.replace("%z",z.c_str());
 | 
			
		||||
  }
 | 
			
		||||
  if(f.indexOf("%Z")>=0)
 | 
			
		||||
  {
 | 
			
		||||
    String z="";
 | 
			
		||||
    char s=0;
 | 
			
		||||
    char c=pgm_read_byte_near(&(TimeZones[tzCode][0][s]));
 | 
			
		||||
    while(c != 0)
 | 
			
		||||
    {
 | 
			
		||||
      z += c;
 | 
			
		||||
      c=pgm_read_byte_near(&(TimeZones[tzCode][0][++s]));
 | 
			
		||||
    }
 | 
			
		||||
    f.replace("%Z",z.c_str());
 | 
			
		||||
  }
 | 
			
		||||
  return f;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
String RealTimeClock::getNtpServerHost()
 | 
			
		||||
{
 | 
			
		||||
  return ntpServerName;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void RealTimeClock::setNtpServerHost(String newHost)
 | 
			
		||||
{
 | 
			
		||||
  newHost.replace(',','.');
 | 
			
		||||
  ntpServerName = newHost;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,455 @@
 | 
			
		|||
#include <Arduino.h>
 | 
			
		||||
/*
 | 
			
		||||
   Copyright 2016-2019 Bo Zimmerman
 | 
			
		||||
 | 
			
		||||
   Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
   you may not use this file except in compliance with the License.
 | 
			
		||||
   You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
     http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
   Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
   distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
   See the License for the specific language governing permissions and
 | 
			
		||||
   limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#include <cstring>
 | 
			
		||||
 | 
			
		||||
static void serialDirectWrite(uint8_t c)
 | 
			
		||||
{
 | 
			
		||||
  HWSerial.write(c);
 | 
			
		||||
  if(serialDelayMs > 0)
 | 
			
		||||
    delay(serialDelayMs);
 | 
			
		||||
  logSerialOut(c);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void hwSerialFlush()
 | 
			
		||||
{
 | 
			
		||||
#ifdef ZIMODEM_ESP8266
 | 
			
		||||
  HWSerial.flush();
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void serialOutDeque()
 | 
			
		||||
{
 | 
			
		||||
#ifdef ZIMODEM_ESP32
 | 
			
		||||
  while((TBUFhead != TBUFtail)
 | 
			
		||||
  &&((SER_BUFSIZE - HWSerial.availableForWrite())<dequeSize))
 | 
			
		||||
#else
 | 
			
		||||
  if((TBUFhead != TBUFtail)
 | 
			
		||||
  &&(HWSerial.availableForWrite()>=SER_BUFSIZE)) // necessary for esp8266 flow control
 | 
			
		||||
#endif
 | 
			
		||||
  {
 | 
			
		||||
    serialDirectWrite(TBUF[TBUFhead]);
 | 
			
		||||
    TBUFhead++;
 | 
			
		||||
    if(TBUFhead >= SER_WRITE_BUFSIZE)
 | 
			
		||||
      TBUFhead = 0;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int serialOutBufferBytesRemaining()
 | 
			
		||||
{
 | 
			
		||||
  if(TBUFtail == TBUFhead)
 | 
			
		||||
    return SER_WRITE_BUFSIZE-1;
 | 
			
		||||
  else
 | 
			
		||||
  if(TBUFtail > TBUFhead)
 | 
			
		||||
  {
 | 
			
		||||
    int used = TBUFtail - TBUFhead;
 | 
			
		||||
    return SER_WRITE_BUFSIZE - used -1;
 | 
			
		||||
  }
 | 
			
		||||
  else
 | 
			
		||||
    return TBUFhead - TBUFtail - 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void enqueSerialOut(uint8_t c)
 | 
			
		||||
{
 | 
			
		||||
  TBUF[TBUFtail] = c;
 | 
			
		||||
  TBUFtail++;
 | 
			
		||||
  if(TBUFtail >= SER_WRITE_BUFSIZE)
 | 
			
		||||
    TBUFtail = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void clearSerialOutBuffer()
 | 
			
		||||
{
 | 
			
		||||
  TBUFtail=TBUFhead;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ensureSerialBytes(int num)
 | 
			
		||||
{
 | 
			
		||||
  if(serialOutBufferBytesRemaining()<1)
 | 
			
		||||
  {
 | 
			
		||||
    serialOutDeque();
 | 
			
		||||
    while(serialOutBufferBytesRemaining()<1)
 | 
			
		||||
      yield();
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void flushSerial()
 | 
			
		||||
{
 | 
			
		||||
  while(TBUFtail != TBUFhead)
 | 
			
		||||
  {
 | 
			
		||||
    serialOutDeque();
 | 
			
		||||
    yield();
 | 
			
		||||
  }
 | 
			
		||||
  hwSerialFlush();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ZSerial::ZSerial()
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ZSerial::setPetsciiMode(bool petscii)
 | 
			
		||||
{
 | 
			
		||||
  petsciiMode = petscii;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool ZSerial::isPetsciiMode()
 | 
			
		||||
{
 | 
			
		||||
  return petsciiMode;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ZSerial::setFlowControlType(FlowControlType type)
 | 
			
		||||
{
 | 
			
		||||
  flowControlType = type;
 | 
			
		||||
#ifdef ZIMODEM_ESP32
 | 
			
		||||
  if(flowControlType == FCT_RTSCTS)
 | 
			
		||||
  {
 | 
			
		||||
    uart_set_hw_flow_ctrl(UART_NUM_2,UART_HW_FLOWCTRL_DISABLE,0);
 | 
			
		||||
    uint32_t invertMask = 0;
 | 
			
		||||
    if(pinSupport[pinCTS])
 | 
			
		||||
    {
 | 
			
		||||
      uart_set_pin(UART_NUM_2, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, /*cts_io_num*/pinCTS);
 | 
			
		||||
      // cts is input to me, output to true RS232
 | 
			
		||||
      if(ctsActive == HIGH)
 | 
			
		||||
#       ifdef UART_INVERSE_CTS
 | 
			
		||||
          invertMask = invertMask | UART_INVERSE_CTS;
 | 
			
		||||
#       else
 | 
			
		||||
          invertMask = invertMask | UART_SIGNAL_CTS_INV;
 | 
			
		||||
#       endif
 | 
			
		||||
    }
 | 
			
		||||
    if(pinSupport[pinRTS])
 | 
			
		||||
    {
 | 
			
		||||
      uart_set_pin(UART_NUM_2, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, /*rts_io_num*/ pinRTS, UART_PIN_NO_CHANGE);
 | 
			
		||||
      s_pinWrite(pinRTS, rtsActive);
 | 
			
		||||
      // rts is output to me, input to true RS232
 | 
			
		||||
      if(rtsActive == HIGH)
 | 
			
		||||
#       ifdef UART_INVERSE_RTS
 | 
			
		||||
          invertMask = invertMask | UART_INVERSE_RTS;
 | 
			
		||||
#       else
 | 
			
		||||
          invertMask = invertMask | UART_SIGNAL_RTS_INV;
 | 
			
		||||
#       endif
 | 
			
		||||
    }
 | 
			
		||||
    //debugPrintf("invert = %d magic values = %d %d, RTS_HIGH=%d, RTS_LOW=%d HIGHHIGH=%d LOWLOW=%d\n",invertMask,ctsActive,rtsActive, DEFAULT_RTS_HIGH, DEFAULT_RTS_LOW, HIGH, LOW);
 | 
			
		||||
    if(invertMask != 0)
 | 
			
		||||
      uart_set_line_inverse(UART_NUM_2, invertMask);
 | 
			
		||||
    const int CUTOFF = 100;
 | 
			
		||||
    if(pinSupport[pinRTS])
 | 
			
		||||
    {
 | 
			
		||||
      if(pinSupport[pinCTS])
 | 
			
		||||
        uart_set_hw_flow_ctrl(UART_NUM_2,UART_HW_FLOWCTRL_CTS_RTS,CUTOFF);
 | 
			
		||||
      else
 | 
			
		||||
        uart_set_hw_flow_ctrl(UART_NUM_2,UART_HW_FLOWCTRL_CTS_RTS,CUTOFF);
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    if(pinSupport[pinCTS])
 | 
			
		||||
      uart_set_hw_flow_ctrl(UART_NUM_2,UART_HW_FLOWCTRL_CTS_RTS,CUTOFF);
 | 
			
		||||
  }
 | 
			
		||||
  else
 | 
			
		||||
    uart_set_hw_flow_ctrl(UART_NUM_2,UART_HW_FLOWCTRL_DISABLE,0);
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
FlowControlType ZSerial::getFlowControlType()
 | 
			
		||||
{
 | 
			
		||||
  return flowControlType;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ZSerial::setXON(bool isXON)
 | 
			
		||||
{
 | 
			
		||||
  XON_STATE = isXON;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int ZSerial::getConfigFlagBitmap()
 | 
			
		||||
{
 | 
			
		||||
  return 
 | 
			
		||||
       (isPetsciiMode()?FLAG_PETSCII:0)
 | 
			
		||||
      |((getFlowControlType()==FCT_RTSCTS)?FLAG_RTSCTS:0)
 | 
			
		||||
      |((getFlowControlType()==FCT_NORMAL)?FLAG_XONXOFF:0)
 | 
			
		||||
      |((getFlowControlType()==FCT_AUTOOFF)?FLAG_XONXOFF:0)
 | 
			
		||||
      |((getFlowControlType()==FCT_MANUAL)?FLAG_XONXOFF:0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool ZSerial::isXON()
 | 
			
		||||
{
 | 
			
		||||
  return XON_STATE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool ZSerial::isSerialOut()
 | 
			
		||||
{
 | 
			
		||||
  switch(flowControlType)
 | 
			
		||||
  {
 | 
			
		||||
  case FCT_RTSCTS:
 | 
			
		||||
    if(pinSupport[pinCTS])
 | 
			
		||||
    {
 | 
			
		||||
      //debugPrintf("CTS: pin %d (%d == %d)\n",pinCTS,digitalRead(pinCTS),ctsActive);
 | 
			
		||||
      return (digitalRead(pinCTS) == ctsActive);
 | 
			
		||||
    }
 | 
			
		||||
    return true;
 | 
			
		||||
  case FCT_NORMAL:
 | 
			
		||||
  case FCT_AUTOOFF:
 | 
			
		||||
  case FCT_MANUAL:
 | 
			
		||||
    break;
 | 
			
		||||
  case FCT_DISABLED:
 | 
			
		||||
    return true;
 | 
			
		||||
  case FCT_INVALID:
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
  return XON_STATE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool ZSerial::isSerialCancelled()
 | 
			
		||||
{
 | 
			
		||||
  if(flowControlType == FCT_RTSCTS)
 | 
			
		||||
  {
 | 
			
		||||
    if(pinSupport[pinCTS])
 | 
			
		||||
    {
 | 
			
		||||
      //debugPrintf("CTS: pin %d (%d == %d)\n",pinCTS,digitalRead(pinCTS),ctsActive);
 | 
			
		||||
      return (digitalRead(pinCTS) == ctsInactive);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool ZSerial::isSerialHalted()
 | 
			
		||||
{
 | 
			
		||||
  return !isSerialOut();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ZSerial::enqueByte(uint8_t c)
 | 
			
		||||
{
 | 
			
		||||
  if(TBUFtail == TBUFhead)
 | 
			
		||||
  {
 | 
			
		||||
    switch(flowControlType)
 | 
			
		||||
    {
 | 
			
		||||
    case FCT_DISABLED:
 | 
			
		||||
    case FCT_INVALID:
 | 
			
		||||
#ifndef ZIMODEM_ESP32
 | 
			
		||||
      if((HWSerial.availableForWrite() > 0)
 | 
			
		||||
      &&(HWSerial.available() == 0))
 | 
			
		||||
#endif
 | 
			
		||||
      {
 | 
			
		||||
        serialDirectWrite(c);
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
      break;
 | 
			
		||||
    case FCT_RTSCTS:
 | 
			
		||||
#ifdef ZIMODEM_ESP32
 | 
			
		||||
      if(isSerialOut())
 | 
			
		||||
#else
 | 
			
		||||
      if((HWSerial.availableForWrite() >= SER_BUFSIZE) // necessary for esp8266 flow control
 | 
			
		||||
      &&(isSerialOut()))
 | 
			
		||||
#endif
 | 
			
		||||
      {
 | 
			
		||||
        serialDirectWrite(c);
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
      break;
 | 
			
		||||
    case FCT_NORMAL:
 | 
			
		||||
    case FCT_AUTOOFF:
 | 
			
		||||
    case FCT_MANUAL:
 | 
			
		||||
      if((HWSerial.availableForWrite() >= SER_BUFSIZE)
 | 
			
		||||
      &&(HWSerial.available() == 0)
 | 
			
		||||
      &&(XON_STATE))
 | 
			
		||||
      {
 | 
			
		||||
        serialDirectWrite(c);
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  // the car jam of blocked bytes stops HERE
 | 
			
		||||
  //debugPrintf("%d\n",serialOutBufferBytesRemaining());
 | 
			
		||||
  while(serialOutBufferBytesRemaining()<1)
 | 
			
		||||
  {
 | 
			
		||||
    if(!isSerialOut())
 | 
			
		||||
      delay(1);
 | 
			
		||||
    else
 | 
			
		||||
      serialOutDeque();
 | 
			
		||||
    yield();
 | 
			
		||||
  }
 | 
			
		||||
  enqueSerialOut(c);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ZSerial::prints(const char *expr)
 | 
			
		||||
{
 | 
			
		||||
  if(!petsciiMode)
 | 
			
		||||
  {
 | 
			
		||||
    for(int i=0;expr[i]!=0;i++)
 | 
			
		||||
    {
 | 
			
		||||
      enqueByte(expr[i]);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  else
 | 
			
		||||
  {
 | 
			
		||||
    for(int i=0;expr[i]!=0;i++)
 | 
			
		||||
    {
 | 
			
		||||
      enqueByte(ascToPetcii(expr[i]));
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ZSerial::printi(int i)
 | 
			
		||||
{
 | 
			
		||||
  char buf[12];
 | 
			
		||||
  prints(itoa(i, buf, 10));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ZSerial::printd(double f)
 | 
			
		||||
{
 | 
			
		||||
  char buf[12];
 | 
			
		||||
  prints(dtostrf(f, 2, 2, buf));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ZSerial::printc(const char c)
 | 
			
		||||
{
 | 
			
		||||
  if(!petsciiMode)
 | 
			
		||||
    enqueByte(c);
 | 
			
		||||
  else
 | 
			
		||||
    enqueByte(ascToPetcii(c));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ZSerial::printc(uint8_t c)
 | 
			
		||||
{
 | 
			
		||||
  if(!petsciiMode)
 | 
			
		||||
    enqueByte(c);
 | 
			
		||||
  else
 | 
			
		||||
    enqueByte(ascToPetcii(c));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ZSerial::printb(uint8_t c)
 | 
			
		||||
{
 | 
			
		||||
  enqueByte(c);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
size_t ZSerial::write(uint8_t c)
 | 
			
		||||
{
 | 
			
		||||
  enqueByte(c);
 | 
			
		||||
  return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
size_t ZSerial::write(uint8_t *buf, int bufSz)
 | 
			
		||||
{
 | 
			
		||||
  for(int i=0;i<bufSz;i++)
 | 
			
		||||
    enqueByte(buf[i]);
 | 
			
		||||
  return bufSz;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ZSerial::prints(String str)
 | 
			
		||||
{
 | 
			
		||||
  prints(str.c_str());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void ZSerial::printf(const char* format, ...) 
 | 
			
		||||
{
 | 
			
		||||
  int ret;
 | 
			
		||||
  va_list arglist;
 | 
			
		||||
  va_start(arglist, format);
 | 
			
		||||
  vsnprintf(FBUF, sizeof(FBUF), format, arglist);
 | 
			
		||||
  prints(FBUF);
 | 
			
		||||
  va_end(arglist);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ZSerial::flushAlways()
 | 
			
		||||
{
 | 
			
		||||
  while(TBUFtail != TBUFhead)
 | 
			
		||||
  {
 | 
			
		||||
    hwSerialFlush();
 | 
			
		||||
    serialOutDeque();
 | 
			
		||||
    yield();
 | 
			
		||||
    delay(1);
 | 
			
		||||
  }
 | 
			
		||||
  hwSerialFlush();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ZSerial::flush()
 | 
			
		||||
{
 | 
			
		||||
  while((TBUFtail != TBUFhead) && (isSerialOut()))
 | 
			
		||||
  {
 | 
			
		||||
    hwSerialFlush();
 | 
			
		||||
    serialOutDeque();
 | 
			
		||||
    yield();
 | 
			
		||||
    delay(1);
 | 
			
		||||
  }
 | 
			
		||||
  hwSerialFlush();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int ZSerial::availableForWrite()
 | 
			
		||||
{
 | 
			
		||||
  return serialOutBufferBytesRemaining();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
char ZSerial::drainForXonXoff()
 | 
			
		||||
{
 | 
			
		||||
  char ch = '\0';
 | 
			
		||||
  while(HWSerial.available()>0)
 | 
			
		||||
  {
 | 
			
		||||
    ch=HWSerial.read();
 | 
			
		||||
    logSerialIn(ch);
 | 
			
		||||
    if(ch == 3)
 | 
			
		||||
      break;
 | 
			
		||||
    switch(flowControlType)
 | 
			
		||||
    {
 | 
			
		||||
      case FCT_NORMAL:
 | 
			
		||||
        if((!XON_STATE) && (ch == 17))
 | 
			
		||||
          XON_STATE=true;
 | 
			
		||||
        else
 | 
			
		||||
        if((XON_STATE) && (ch == 19))
 | 
			
		||||
          XON_STATE=false;
 | 
			
		||||
        break;
 | 
			
		||||
      case FCT_AUTOOFF:
 | 
			
		||||
      case FCT_MANUAL:
 | 
			
		||||
        if((!XON_STATE) && (ch == 17))
 | 
			
		||||
          XON_STATE=true;
 | 
			
		||||
        else
 | 
			
		||||
          XON_STATE=false;
 | 
			
		||||
        break;
 | 
			
		||||
      case FCT_INVALID:
 | 
			
		||||
        break;
 | 
			
		||||
      case FCT_RTSCTS:
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  return ch;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int ZSerial::available() 
 | 
			
		||||
{ 
 | 
			
		||||
  int avail = HWSerial.available();
 | 
			
		||||
  if(avail == 0)
 | 
			
		||||
  {
 | 
			
		||||
      if((TBUFtail != TBUFhead) && isSerialOut())
 | 
			
		||||
        serialOutDeque();
 | 
			
		||||
  }
 | 
			
		||||
  return avail;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int ZSerial::read() 
 | 
			
		||||
{ 
 | 
			
		||||
  int c=HWSerial.read();
 | 
			
		||||
  if(c == -1)
 | 
			
		||||
  {
 | 
			
		||||
    if((TBUFtail != TBUFhead) && isSerialOut())
 | 
			
		||||
      serialOutDeque();
 | 
			
		||||
  }
 | 
			
		||||
  else
 | 
			
		||||
    logSerialIn(c);
 | 
			
		||||
  return c;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int ZSerial::peek() 
 | 
			
		||||
{ 
 | 
			
		||||
  return HWSerial.peek(); 
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,506 @@
 | 
			
		|||
#include <Arduino.h>
 | 
			
		||||
/*
 | 
			
		||||
   Copyright 2016-2019 Bo Zimmerman
 | 
			
		||||
 | 
			
		||||
   Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
   you may not use this file except in compliance with the License.
 | 
			
		||||
   You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
	   http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
   Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
   distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
   See the License for the specific language governing permissions and
 | 
			
		||||
   limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
void WiFiClientNode::finishConnectionLink()
 | 
			
		||||
{
 | 
			
		||||
  wasConnected=true;
 | 
			
		||||
  if(conns == null)
 | 
			
		||||
    conns = this;
 | 
			
		||||
  else
 | 
			
		||||
  {
 | 
			
		||||
    WiFiClientNode *last = conns;
 | 
			
		||||
    while(last->next != null)
 | 
			
		||||
      last = last->next;
 | 
			
		||||
    last->next = this;
 | 
			
		||||
  }
 | 
			
		||||
  checkOpenConnections();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void WiFiClientNode::constructNode()
 | 
			
		||||
{
 | 
			
		||||
  id=++WiFiNextClientId;
 | 
			
		||||
  setCharArray(&delimiters,"");
 | 
			
		||||
  setCharArray(&maskOuts,"");
 | 
			
		||||
  setCharArray(&stateMachine,"");
 | 
			
		||||
  machineState = stateMachine;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void WiFiClientNode::constructNode(char *hostIp, int newport, int flagsBitmap, int ringDelay)
 | 
			
		||||
{
 | 
			
		||||
  constructNode();
 | 
			
		||||
  port=newport;
 | 
			
		||||
  host=new char[strlen(hostIp)+1];
 | 
			
		||||
  strcpy(host,hostIp);
 | 
			
		||||
  this->flagsBitmap = flagsBitmap;
 | 
			
		||||
  answered=(ringDelay == 0);
 | 
			
		||||
  if(ringDelay > 0)
 | 
			
		||||
  {
 | 
			
		||||
    ringsRemain = ringDelay;
 | 
			
		||||
    nextRingMillis = millis() + 3000;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void WiFiClientNode::constructNode(char *hostIp, int newport, char *username, char *password, int flagsBitmap, int ringDelay)
 | 
			
		||||
{
 | 
			
		||||
  constructNode(hostIp, newport, flagsBitmap, ringDelay);
 | 
			
		||||
# ifdef INCLUDE_SSH
 | 
			
		||||
  if(((flagsBitmap&FLAG_SECURE)==FLAG_SECURE)
 | 
			
		||||
  && (username != 0))
 | 
			
		||||
  {
 | 
			
		||||
    WiFiSSHClient *c = new WiFiSSHClient();
 | 
			
		||||
    c->setLogin(username, password);
 | 
			
		||||
    clientPtr = c;
 | 
			
		||||
  }
 | 
			
		||||
  else
 | 
			
		||||
#endif
 | 
			
		||||
    clientPtr = createWiFiClient((flagsBitmap&FLAG_SECURE)==FLAG_SECURE);
 | 
			
		||||
  client = *clientPtr;
 | 
			
		||||
  if(!clientPtr->connect(hostIp, newport))
 | 
			
		||||
  {
 | 
			
		||||
    // deleted when it returns and is deleted
 | 
			
		||||
  }
 | 
			
		||||
  else
 | 
			
		||||
  {
 | 
			
		||||
    clientPtr->setNoDelay(DEFAULT_NO_DELAY);
 | 
			
		||||
    finishConnectionLink();
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
WiFiClientNode::WiFiClientNode(char *hostIp, int newport, char *username, char *password, int flagsBitmap)
 | 
			
		||||
{
 | 
			
		||||
  constructNode(hostIp, newport, username, password, flagsBitmap, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
WiFiClientNode::WiFiClientNode(char *hostIp, int newport, int flagsBitmap)
 | 
			
		||||
{
 | 
			
		||||
  constructNode(hostIp, newport, 0, 0, flagsBitmap, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void WiFiClientNode:: setNoDelay(bool tf)
 | 
			
		||||
{
 | 
			
		||||
  if(clientPtr != 0)
 | 
			
		||||
    clientPtr->setNoDelay(tf);
 | 
			
		||||
  else
 | 
			
		||||
    client.setNoDelay(tf);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
WiFiClientNode::WiFiClientNode(WiFiClient newClient, int flagsBitmap, int ringDelay)
 | 
			
		||||
{
 | 
			
		||||
  constructNode();
 | 
			
		||||
  this->flagsBitmap = flagsBitmap;
 | 
			
		||||
  clientPtr=null;
 | 
			
		||||
  newClient.setNoDelay(DEFAULT_NO_DELAY);
 | 
			
		||||
  port=newClient.localPort();
 | 
			
		||||
  String remoteIPStr = newClient.remoteIP().toString();
 | 
			
		||||
  const char *remoteIP=remoteIPStr.c_str();
 | 
			
		||||
  host=new char[remoteIPStr.length()+1];
 | 
			
		||||
  strcpy(host,remoteIP);
 | 
			
		||||
  client = newClient;
 | 
			
		||||
  answered=(ringDelay == 0);
 | 
			
		||||
  if(ringDelay > 0)
 | 
			
		||||
  {
 | 
			
		||||
    ringsRemain = ringDelay;
 | 
			
		||||
    nextRingMillis = millis() + 3000;
 | 
			
		||||
  }
 | 
			
		||||
  finishConnectionLink();
 | 
			
		||||
  serverClient=true;
 | 
			
		||||
}
 | 
			
		||||
    
 | 
			
		||||
WiFiClientNode::~WiFiClientNode()
 | 
			
		||||
{
 | 
			
		||||
  lastPacket[0].len=0;
 | 
			
		||||
  lastPacket[1].len=0;
 | 
			
		||||
  if(host!=null)
 | 
			
		||||
  {
 | 
			
		||||
    if(clientPtr != null)
 | 
			
		||||
      clientPtr->stop();
 | 
			
		||||
    else
 | 
			
		||||
      client.stop();
 | 
			
		||||
    delete host;
 | 
			
		||||
    host=null;
 | 
			
		||||
  }
 | 
			
		||||
  if(clientPtr != null)
 | 
			
		||||
  {
 | 
			
		||||
    delete clientPtr;
 | 
			
		||||
    clientPtr = null;
 | 
			
		||||
  }
 | 
			
		||||
  if(conns == this)
 | 
			
		||||
    conns = next;
 | 
			
		||||
  else
 | 
			
		||||
  {
 | 
			
		||||
    WiFiClientNode *last = conns;
 | 
			
		||||
    while((last != null) && (last->next != this)) // don't change this!
 | 
			
		||||
      last = last->next;
 | 
			
		||||
    if(last != null)
 | 
			
		||||
      last->next = next;
 | 
			
		||||
  }
 | 
			
		||||
  if(commandMode.current == this)
 | 
			
		||||
    commandMode.current = conns;
 | 
			
		||||
  if(commandMode.nextConn == this)
 | 
			
		||||
    commandMode.nextConn = conns;
 | 
			
		||||
  //underflowBuf.len = 0;
 | 
			
		||||
  freeCharArray(&delimiters);
 | 
			
		||||
  freeCharArray(&maskOuts);
 | 
			
		||||
  freeCharArray(&stateMachine);
 | 
			
		||||
  machineState = NULL;
 | 
			
		||||
  next=null;
 | 
			
		||||
  checkOpenConnections();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool WiFiClientNode::isConnected()
 | 
			
		||||
{
 | 
			
		||||
  return (host != null) && (clientPtr != null) && clientPtr->connected();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool WiFiClientNode::isPETSCII()
 | 
			
		||||
{
 | 
			
		||||
  return (flagsBitmap & FLAG_PETSCII) == FLAG_PETSCII;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool WiFiClientNode::isEcho()
 | 
			
		||||
{
 | 
			
		||||
  return (flagsBitmap & FLAG_ECHO) == FLAG_ECHO;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
FlowControlType WiFiClientNode::getFlowControl()
 | 
			
		||||
{
 | 
			
		||||
  if((flagsBitmap & FLAG_RTSCTS) == FLAG_RTSCTS)
 | 
			
		||||
    return FCT_RTSCTS;
 | 
			
		||||
  if((flagsBitmap & FLAG_XONXOFF) == FLAG_XONXOFF)
 | 
			
		||||
    return FCT_NORMAL;
 | 
			
		||||
  return FCT_DISABLED;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool WiFiClientNode::isTelnet()
 | 
			
		||||
{
 | 
			
		||||
  return (flagsBitmap & FLAG_TELNET) == FLAG_TELNET;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool WiFiClientNode::isDisconnectedOnStreamExit()
 | 
			
		||||
{
 | 
			
		||||
  return (flagsBitmap & FLAG_DISCONNECT_ON_EXIT) == FLAG_DISCONNECT_ON_EXIT;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void WiFiClientNode::setDisconnectOnStreamExit(bool tf)
 | 
			
		||||
{
 | 
			
		||||
  if(tf)
 | 
			
		||||
    flagsBitmap = flagsBitmap | FLAG_DISCONNECT_ON_EXIT;
 | 
			
		||||
  else
 | 
			
		||||
    flagsBitmap = flagsBitmap & ~FLAG_DISCONNECT_ON_EXIT;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void WiFiClientNode::fillUnderflowBuf()
 | 
			
		||||
{
 | 
			
		||||
  /*
 | 
			
		||||
  //underflow buf is deprecated
 | 
			
		||||
  int newAvail = client.available();
 | 
			
		||||
  if(newAvail > 0)
 | 
			
		||||
  {
 | 
			
		||||
    int maxBufAvail = PACKET_BUF_SIZE-underflowBuf.len;
 | 
			
		||||
    if(newAvail>maxBufAvail)
 | 
			
		||||
      newAvail=maxBufAvail;
 | 
			
		||||
    if(newAvail > 0)
 | 
			
		||||
      underflowBuf.len += client.read(underflowBuf.buf+underflowBuf.len, newAvail);
 | 
			
		||||
  }
 | 
			
		||||
  */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int WiFiClientNode::read()
 | 
			
		||||
{
 | 
			
		||||
  if((host == null)||(!answered))
 | 
			
		||||
    return 0;
 | 
			
		||||
  /*
 | 
			
		||||
  // underflow buf is no longer needed
 | 
			
		||||
  if(underflowBuf.len > 0)
 | 
			
		||||
  {
 | 
			
		||||
    int b = underflowBuf.buf[0];
 | 
			
		||||
    memcpy(underflowBuf.buf,underflowBuf.buf+1,--underflowBuf.len);
 | 
			
		||||
    return b;
 | 
			
		||||
  }
 | 
			
		||||
   */
 | 
			
		||||
  int c;
 | 
			
		||||
  if(clientPtr != null)
 | 
			
		||||
    c = clientPtr->read();
 | 
			
		||||
  else
 | 
			
		||||
    c= client.read();
 | 
			
		||||
  //fillUnderflowBuf();
 | 
			
		||||
  return c;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int WiFiClientNode::peek()
 | 
			
		||||
{
 | 
			
		||||
  if((host == null)||(!answered))
 | 
			
		||||
    return 0;
 | 
			
		||||
  /*
 | 
			
		||||
  // underflow buf is no longer needed
 | 
			
		||||
  if(underflowBuf.len > 0)
 | 
			
		||||
    return underflowBuf.buf[0];
 | 
			
		||||
  */
 | 
			
		||||
  if(clientPtr != null)
 | 
			
		||||
    return clientPtr->peek();
 | 
			
		||||
  else
 | 
			
		||||
    return client.peek();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void WiFiClientNode::flush()
 | 
			
		||||
{
 | 
			
		||||
  if((host != null)&&(clientPtr != null) && (clientPtr->available()==0))
 | 
			
		||||
    flushAlways();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void WiFiClientNode::flushAlways()
 | 
			
		||||
{
 | 
			
		||||
  if(host != null)
 | 
			
		||||
  {
 | 
			
		||||
    flushOverflowBuffer();
 | 
			
		||||
    if(clientPtr != null)
 | 
			
		||||
      clientPtr->flush();
 | 
			
		||||
    else
 | 
			
		||||
      client.flush();
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int WiFiClientNode::available()
 | 
			
		||||
{
 | 
			
		||||
  if((host == null)||(!answered))
 | 
			
		||||
    return 0;
 | 
			
		||||
  if(clientPtr != null)
 | 
			
		||||
    return clientPtr->available();
 | 
			
		||||
  else
 | 
			
		||||
    return client.available(); // +underflowBuf.len;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int WiFiClientNode::read(uint8_t *buf, size_t size)
 | 
			
		||||
{
 | 
			
		||||
  if((host == null)||(!answered))
 | 
			
		||||
    return 0;
 | 
			
		||||
  // this whole underflow buf len thing is to get around yet another
 | 
			
		||||
  // problem in the underlying library where a socket disconnection
 | 
			
		||||
  // eats away any stray available bytes in their buffers.
 | 
			
		||||
  /*
 | 
			
		||||
  // this was changed to be handled a different, so underBuf is also deprecated;
 | 
			
		||||
  int previouslyRead = 0;
 | 
			
		||||
  if(underflowBuf.len > 0)
 | 
			
		||||
  {
 | 
			
		||||
    if(underflowBuf.len <= size)
 | 
			
		||||
    {
 | 
			
		||||
      previouslyRead += underflowBuf.len;
 | 
			
		||||
      memcpy(buf,underflowBuf.buf,underflowBuf.len);
 | 
			
		||||
      size -= underflowBuf.len;
 | 
			
		||||
      underflowBuf.len = 0;
 | 
			
		||||
      buf += previouslyRead;
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
      memcpy(buf,underflowBuf.buf,size);
 | 
			
		||||
      underflowBuf.len -= size;
 | 
			
		||||
      memcpy(underflowBuf.buf,underflowBuf.buf+size,underflowBuf.len);
 | 
			
		||||
      return size;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  if(size == 0)
 | 
			
		||||
    return previouslyRead;
 | 
			
		||||
   */
 | 
			
		||||
 | 
			
		||||
  int bytesRead;
 | 
			
		||||
  if(clientPtr != null)
 | 
			
		||||
    bytesRead = clientPtr->read(buf,size);
 | 
			
		||||
  else
 | 
			
		||||
    bytesRead = client.read(buf,size);
 | 
			
		||||
  //fillUnderflowBuf();
 | 
			
		||||
  return bytesRead;// + previouslyRead;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int WiFiClientNode::flushOverflowBuffer()
 | 
			
		||||
{
 | 
			
		||||
  /*
 | 
			
		||||
   * I've never gotten any of this to trigger, and could use those
 | 
			
		||||
   * extra 260 bytes per connection
 | 
			
		||||
  if(overflowBufLen > 0)
 | 
			
		||||
  {
 | 
			
		||||
    // because overflowBuf is not a const char* for some reason
 | 
			
		||||
    // we need to explicitly declare that we want one
 | 
			
		||||
    // The simplest thing to do is pin down the first character of the
 | 
			
		||||
    // array and call it a day.
 | 
			
		||||
    // This avoids client.write<T>(buffer, length) from being seen by the
 | 
			
		||||
    // compiler as a better way to poke at it. 
 | 
			
		||||
    const uint8_t* overflowbuf_ptr = &overflowBuf[0];
 | 
			
		||||
    int bufWrite=client.write(overflowbuf_ptr,overflowBufLen);
 | 
			
		||||
    if(bufWrite >= overflowBufLen)
 | 
			
		||||
    {
 | 
			
		||||
      overflowBufLen = 0;
 | 
			
		||||
      s_pinWrite(pinRTS,rtsActive);
 | 
			
		||||
      // fall-through
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
      if(bufWrite > 0)
 | 
			
		||||
      {
 | 
			
		||||
        for(int i=bufWrite;i<overflowBufLen;i++)
 | 
			
		||||
          overflowBuf[i-bufWrite]=overflowBuf[i];
 | 
			
		||||
        overflowBufLen -= bufWrite;
 | 
			
		||||
      }
 | 
			
		||||
      s_pinWrite(pinRTS,rtsInactive);
 | 
			
		||||
      return bufWrite;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
   */
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
size_t WiFiClientNode::write(const uint8_t *buf, size_t size)
 | 
			
		||||
{
 | 
			
		||||
  int written = 0;
 | 
			
		||||
  /* overflow buf is pretty much useless now
 | 
			
		||||
  if(host == null)
 | 
			
		||||
  {
 | 
			
		||||
    if(overflowBufLen>0)
 | 
			
		||||
    {
 | 
			
		||||
      s_pinWrite(pinRTS,rtsActive);
 | 
			
		||||
    }
 | 
			
		||||
    overflowBufLen=0;
 | 
			
		||||
    return 0;
 | 
			
		||||
  }
 | 
			
		||||
  written += flushOverflowBuffer();
 | 
			
		||||
  if(written > 0)
 | 
			
		||||
  {
 | 
			
		||||
    for(int i=0;i<size && overflowBufLen<OVERFLOW_BUF_SIZE;i++,overflowBufLen++)
 | 
			
		||||
      overflowBuf[overflowBufLen]=buf[i];
 | 
			
		||||
    return written;
 | 
			
		||||
  }
 | 
			
		||||
  */
 | 
			
		||||
  if(clientPtr != null)
 | 
			
		||||
    written += clientPtr->write(buf, size);
 | 
			
		||||
  else
 | 
			
		||||
    written += client.write(buf, size);
 | 
			
		||||
  /*
 | 
			
		||||
  if(written < size)
 | 
			
		||||
  {
 | 
			
		||||
    for(int i=written;i<size && overflowBufLen<OVERFLOW_BUF_SIZE;i++,overflowBufLen++)
 | 
			
		||||
      overflowBuf[overflowBufLen]=buf[i];
 | 
			
		||||
    s_pinWrite(pinRTS,rtsInactive);
 | 
			
		||||
  }
 | 
			
		||||
  */
 | 
			
		||||
  return written;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void WiFiClientNode::print(String s)
 | 
			
		||||
{
 | 
			
		||||
  int size=s.length();
 | 
			
		||||
  write((const uint8_t *)s.c_str(),size);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
String WiFiClientNode::readLine(unsigned int timeout)
 | 
			
		||||
{
 | 
			
		||||
  unsigned long now=millis();
 | 
			
		||||
  String line = "";
 | 
			
		||||
  while(((millis()-now < timeout) || (available()>0)))
 | 
			
		||||
  {
 | 
			
		||||
    yield();
 | 
			
		||||
    if(available()>0)
 | 
			
		||||
    {
 | 
			
		||||
      char c=read();
 | 
			
		||||
      if((c=='\n')||(c=='\r'))
 | 
			
		||||
      {
 | 
			
		||||
          if(line.length()>0)
 | 
			
		||||
            return line;
 | 
			
		||||
      }
 | 
			
		||||
      else
 | 
			
		||||
      if((c >= 32 ) && (c <= 127))
 | 
			
		||||
        line += c;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  return line;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void WiFiClientNode::answer()
 | 
			
		||||
{
 | 
			
		||||
  answered=true;
 | 
			
		||||
  ringsRemain=0;
 | 
			
		||||
  nextRingMillis=0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool WiFiClientNode::isAnswered()
 | 
			
		||||
{
 | 
			
		||||
  return answered;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int WiFiClientNode::ringsRemaining(int delta)
 | 
			
		||||
{
 | 
			
		||||
  ringsRemain += delta;
 | 
			
		||||
  return ringsRemain;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
unsigned long WiFiClientNode::nextRingTime(long delta)
 | 
			
		||||
{
 | 
			
		||||
  nextRingMillis += delta;
 | 
			
		||||
  return nextRingMillis;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
size_t WiFiClientNode::write(uint8_t c)
 | 
			
		||||
{
 | 
			
		||||
  const uint8_t one[] = {c};
 | 
			
		||||
  write(one,1);
 | 
			
		||||
  return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int WiFiClientNode::getNumOpenWiFiConnections()
 | 
			
		||||
{
 | 
			
		||||
  int num = 0;
 | 
			
		||||
  WiFiClientNode *conn = conns;
 | 
			
		||||
  while(conn != null)
 | 
			
		||||
  {
 | 
			
		||||
    WiFiClientNode *chkConn = conn;
 | 
			
		||||
    conn = conn->next;
 | 
			
		||||
    if((chkConn->nextDisconnect != 0)
 | 
			
		||||
    &&(millis() > chkConn->nextDisconnect))
 | 
			
		||||
      delete(chkConn);
 | 
			
		||||
    else
 | 
			
		||||
    if((chkConn->isConnected()
 | 
			
		||||
     ||(chkConn->available()>0)
 | 
			
		||||
     ||((chkConn == conns)
 | 
			
		||||
       &&((serialOutBufferBytesRemaining() <SER_WRITE_BUFSIZE-1)
 | 
			
		||||
         ||(HWSerial.availableForWrite()<SER_BUFSIZE))))
 | 
			
		||||
    && chkConn->isAnswered())
 | 
			
		||||
      num++;
 | 
			
		||||
  }
 | 
			
		||||
  return num;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void WiFiClientNode::markForDisconnect()
 | 
			
		||||
{
 | 
			
		||||
  if(nextDisconnect == 0)
 | 
			
		||||
    nextDisconnect = millis() + 5000; // 5 sec
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool WiFiClientNode::isMarkedForDisconnect()
 | 
			
		||||
{
 | 
			
		||||
  return nextDisconnect != 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void WiFiClientNode::checkForAutoDisconnections()
 | 
			
		||||
{
 | 
			
		||||
  WiFiClientNode *conn = conns;
 | 
			
		||||
  while(conn != null)
 | 
			
		||||
  {
 | 
			
		||||
    WiFiClientNode *chkConn = conn;
 | 
			
		||||
    conn = conn->next;
 | 
			
		||||
    if((chkConn->nextDisconnect != 0)
 | 
			
		||||
    &&(millis() > chkConn->nextDisconnect))
 | 
			
		||||
      delete(chkConn);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,291 @@
 | 
			
		|||
#include <Arduino.h>
 | 
			
		||||
/*
 | 
			
		||||
   Copyright 2016-2019 Bo Zimmerman
 | 
			
		||||
 | 
			
		||||
   Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
   you may not use this file except in compliance with the License.
 | 
			
		||||
   You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
	   http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
   Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
   distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
   See the License for the specific language governing permissions and
 | 
			
		||||
   limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
WiFiServerSpec::WiFiServerSpec()
 | 
			
		||||
{
 | 
			
		||||
  setCharArray(&delimiters,"");
 | 
			
		||||
  setCharArray(&maskOuts,"");
 | 
			
		||||
  setCharArray(&stateMachine,"");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
WiFiServerSpec::~WiFiServerSpec()
 | 
			
		||||
{
 | 
			
		||||
  freeCharArray(&delimiters);
 | 
			
		||||
  freeCharArray(&maskOuts);
 | 
			
		||||
  freeCharArray(&stateMachine);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
WiFiServerSpec::WiFiServerSpec(WiFiServerSpec ©)
 | 
			
		||||
{
 | 
			
		||||
  port=copy.port;
 | 
			
		||||
  flagsBitmap = copy.flagsBitmap;
 | 
			
		||||
  setCharArray(&delimiters,copy.delimiters);
 | 
			
		||||
  setCharArray(&maskOuts,copy.maskOuts);
 | 
			
		||||
  setCharArray(&stateMachine,copy.stateMachine);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
WiFiServerSpec& WiFiServerSpec::operator=(const WiFiServerSpec ©)
 | 
			
		||||
{
 | 
			
		||||
  if(this != ©)
 | 
			
		||||
  {
 | 
			
		||||
    port=copy.port;
 | 
			
		||||
    flagsBitmap = copy.flagsBitmap;
 | 
			
		||||
    setCharArray(&delimiters,copy.delimiters);
 | 
			
		||||
    setCharArray(&maskOuts,copy.maskOuts);
 | 
			
		||||
    setCharArray(&stateMachine,copy.stateMachine);
 | 
			
		||||
  }
 | 
			
		||||
  return *this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
WiFiServerNode::WiFiServerNode(int newport, int flagsBitmap)
 | 
			
		||||
{
 | 
			
		||||
  id=++WiFiNextClientId;
 | 
			
		||||
  port=newport;
 | 
			
		||||
  this->flagsBitmap = flagsBitmap;
 | 
			
		||||
  server = new WiFiServer((uint16_t)newport);
 | 
			
		||||
  //BZ:server->setNoDelay(DEFAULT_NO_DELAY);
 | 
			
		||||
  server->begin();
 | 
			
		||||
  if(servs==null)
 | 
			
		||||
    servs=this;
 | 
			
		||||
  else
 | 
			
		||||
  {
 | 
			
		||||
    WiFiServerNode *s=servs;
 | 
			
		||||
    while(s->next != null)
 | 
			
		||||
      s=s->next;
 | 
			
		||||
    s->next=this;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
WiFiServerNode::~WiFiServerNode()
 | 
			
		||||
{
 | 
			
		||||
  if(server != null)
 | 
			
		||||
  {
 | 
			
		||||
    server->stop();
 | 
			
		||||
    server->close();
 | 
			
		||||
    delete server;
 | 
			
		||||
  }
 | 
			
		||||
  if(servs == this)
 | 
			
		||||
    servs = next;
 | 
			
		||||
  else
 | 
			
		||||
  {
 | 
			
		||||
    WiFiServerNode *last = servs;
 | 
			
		||||
    while((last != null) && (last->next != this)) // don't change this!
 | 
			
		||||
      last = last->next;
 | 
			
		||||
    if(last != null)
 | 
			
		||||
      last->next = next;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool WiFiServerNode::hasClient()
 | 
			
		||||
{
 | 
			
		||||
  if(server != null)
 | 
			
		||||
    return server->hasClient();
 | 
			
		||||
  return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool WiFiServerNode::ReadWiFiServer(File &f, WiFiServerSpec &node)
 | 
			
		||||
{
 | 
			
		||||
  if(f.available()>0)
 | 
			
		||||
  {
 | 
			
		||||
    String str="";
 | 
			
		||||
    char c=f.read();
 | 
			
		||||
    while((c != ',') && (f.available()>0))
 | 
			
		||||
    {
 | 
			
		||||
      str += c;
 | 
			
		||||
      c=f.read();
 | 
			
		||||
    }
 | 
			
		||||
    if(str.length()==0)
 | 
			
		||||
      return false;
 | 
			
		||||
    node.port = atoi(str.c_str());
 | 
			
		||||
    str = "";
 | 
			
		||||
    c=f.read();
 | 
			
		||||
    while((c != '\n') && (f.available()>0))
 | 
			
		||||
    {
 | 
			
		||||
      str += c;
 | 
			
		||||
      c=f.read();
 | 
			
		||||
    }
 | 
			
		||||
    if(str.length()==0)
 | 
			
		||||
      return false;
 | 
			
		||||
    node.flagsBitmap = atoi(str.c_str());
 | 
			
		||||
    str = "";
 | 
			
		||||
    c=f.read();
 | 
			
		||||
    while((c != ',') && (f.available()>0))
 | 
			
		||||
    {
 | 
			
		||||
      str += c;
 | 
			
		||||
      c=f.read();
 | 
			
		||||
    }
 | 
			
		||||
    if(str.length()==0)
 | 
			
		||||
      return false;
 | 
			
		||||
    int chars=atoi(str.c_str());
 | 
			
		||||
    str = "";
 | 
			
		||||
    for(int i=0;i<chars && f.available()>0;i++)
 | 
			
		||||
    {
 | 
			
		||||
      c=f.read();
 | 
			
		||||
      str += c;
 | 
			
		||||
    }
 | 
			
		||||
    setCharArray(&node.maskOuts,str.c_str());
 | 
			
		||||
    if(f.available()<=0 || f.read()!='\n')
 | 
			
		||||
      return false;
 | 
			
		||||
    str = "";
 | 
			
		||||
    c=f.read();
 | 
			
		||||
    while((c != ',') && (f.available()>0))
 | 
			
		||||
    {
 | 
			
		||||
      str += c;
 | 
			
		||||
      c=f.read();
 | 
			
		||||
    }
 | 
			
		||||
    if(str.length()==0)
 | 
			
		||||
      return false;
 | 
			
		||||
    chars=atoi(str.c_str());
 | 
			
		||||
    str = "";
 | 
			
		||||
    for(int i=0;i<chars && f.available()>0;i++)
 | 
			
		||||
    {
 | 
			
		||||
      c=f.read();
 | 
			
		||||
      str += c;
 | 
			
		||||
    }
 | 
			
		||||
    setCharArray(&node.delimiters,str.c_str());
 | 
			
		||||
    if(f.available()<=0 || f.read()!='\n')
 | 
			
		||||
      return true;
 | 
			
		||||
    str = "";
 | 
			
		||||
    c=f.read();
 | 
			
		||||
    while((c != ',') && (f.available()>0))
 | 
			
		||||
    {
 | 
			
		||||
      str += c;
 | 
			
		||||
      c=f.read();
 | 
			
		||||
    }
 | 
			
		||||
    if(str.length()==0)
 | 
			
		||||
      return false;
 | 
			
		||||
    chars=atoi(str.c_str());
 | 
			
		||||
    str = "";
 | 
			
		||||
    for(int i=0;i<chars && f.available()>0;i++)
 | 
			
		||||
    {
 | 
			
		||||
      str += c;
 | 
			
		||||
      c=f.read();
 | 
			
		||||
    }
 | 
			
		||||
    setCharArray(&node.stateMachine,str.c_str());
 | 
			
		||||
  }
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void WiFiServerNode::SaveWiFiServers()
 | 
			
		||||
{
 | 
			
		||||
  SPIFFS.remove("/zlisteners.txt");
 | 
			
		||||
  delay(500);
 | 
			
		||||
  File f = SPIFFS.open("/zlisteners.txt", "w");
 | 
			
		||||
  int ct=0;
 | 
			
		||||
  WiFiServerNode *serv = servs;
 | 
			
		||||
  while(serv != null)
 | 
			
		||||
  {
 | 
			
		||||
    f.printf("%d,%d\n",serv->port,serv->flagsBitmap);
 | 
			
		||||
    if(serv->maskOuts == NULL)
 | 
			
		||||
      f.printf("0,\n");
 | 
			
		||||
    else
 | 
			
		||||
      f.printf("%d,%s\n",strlen(serv->maskOuts),serv->maskOuts);
 | 
			
		||||
    if(serv->delimiters == NULL)
 | 
			
		||||
      f.printf("0,\n");
 | 
			
		||||
    else
 | 
			
		||||
      f.printf("%d,%s\n",strlen(serv->delimiters),serv->delimiters);
 | 
			
		||||
    if(serv->stateMachine == NULL)
 | 
			
		||||
      f.printf("0,\n");
 | 
			
		||||
    else
 | 
			
		||||
      f.printf("%d,%s\n",strlen(serv->stateMachine),serv->stateMachine);
 | 
			
		||||
    ct++;
 | 
			
		||||
    serv=serv->next;
 | 
			
		||||
  }
 | 
			
		||||
  f.close();
 | 
			
		||||
  delay(500);
 | 
			
		||||
  if(SPIFFS.exists("/zlisteners.txt"))
 | 
			
		||||
  {
 | 
			
		||||
    File f = SPIFFS.open("/zlisteners.txt", "r");
 | 
			
		||||
    bool fail=false;
 | 
			
		||||
    while(f.available()>5)
 | 
			
		||||
    {
 | 
			
		||||
      WiFiServerSpec snode;
 | 
			
		||||
      if(!ReadWiFiServer(f,snode))
 | 
			
		||||
      {
 | 
			
		||||
        fail=true;
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    f.close();
 | 
			
		||||
    if(fail)
 | 
			
		||||
    {
 | 
			
		||||
      delay(100);
 | 
			
		||||
      SaveWiFiServers();
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void WiFiServerNode::DestroyAllServers()
 | 
			
		||||
{
 | 
			
		||||
  while(servs != null)
 | 
			
		||||
  {
 | 
			
		||||
    WiFiServerNode *s=servs;
 | 
			
		||||
    delete s;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
WiFiServerNode *WiFiServerNode::FindServer(int port)
 | 
			
		||||
{
 | 
			
		||||
  WiFiServerNode *s=servs;
 | 
			
		||||
  while(s != null)
 | 
			
		||||
  {
 | 
			
		||||
    if(s->port == port)
 | 
			
		||||
      return s;
 | 
			
		||||
    s=s->next;
 | 
			
		||||
  }
 | 
			
		||||
  return null;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void WiFiServerNode::RestoreWiFiServers()
 | 
			
		||||
{
 | 
			
		||||
  if(SPIFFS.exists("/zlisteners.txt"))
 | 
			
		||||
  {
 | 
			
		||||
    File f = SPIFFS.open("/zlisteners.txt", "r");
 | 
			
		||||
    bool fail=false;
 | 
			
		||||
    while(f.available()>0)
 | 
			
		||||
    {
 | 
			
		||||
      WiFiServerSpec snode;
 | 
			
		||||
      if(!ReadWiFiServer(f,snode))
 | 
			
		||||
      {
 | 
			
		||||
        debugPrintf("Server: FAIL\n");
 | 
			
		||||
        fail=true;
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
      WiFiServerNode *s=servs;
 | 
			
		||||
      while(s != null)
 | 
			
		||||
      {
 | 
			
		||||
        if(s->port == snode.port)
 | 
			
		||||
          break;
 | 
			
		||||
        s=s->next;
 | 
			
		||||
      }
 | 
			
		||||
      if(s==null)
 | 
			
		||||
      {
 | 
			
		||||
        WiFiServerNode *node = new WiFiServerNode(snode.port, snode.flagsBitmap);
 | 
			
		||||
        setCharArray(&node->delimiters,snode.delimiters);
 | 
			
		||||
        setCharArray(&node->maskOuts,snode.maskOuts);
 | 
			
		||||
        setCharArray(&node->stateMachine,snode.stateMachine);
 | 
			
		||||
        debugPrintf("Server: %d, %d: '%s' '%s'\n",node->port,node->flagsBitmap,node->delimiters,node->maskOuts);
 | 
			
		||||
      }
 | 
			
		||||
      else
 | 
			
		||||
        debugPrintf("Server: DUP %d\n",snode.port);
 | 
			
		||||
    }
 | 
			
		||||
    f.close();
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,302 @@
 | 
			
		|||
#include <Arduino.h>
 | 
			
		||||
#ifdef INCLUDE_SSH
 | 
			
		||||
/*
 | 
			
		||||
   Copyright 2023-2023 Bo Zimmerman
 | 
			
		||||
 | 
			
		||||
   Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
   you may not use this file except in compliance with the License.
 | 
			
		||||
   You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
     http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
   Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
   distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
   See the License for the specific language governing permissions and
 | 
			
		||||
   limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
WiFiSSHClient::WiFiSSHClient()
 | 
			
		||||
{
 | 
			
		||||
  libssh2_init(0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
WiFiSSHClient::~WiFiSSHClient()
 | 
			
		||||
{
 | 
			
		||||
  closeSSH();
 | 
			
		||||
  libssh2_exit();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void WiFiSSHClient::closeSSH()
 | 
			
		||||
{
 | 
			
		||||
  if(channel) {
 | 
			
		||||
    libssh2_channel_send_eof(channel);
 | 
			
		||||
    libssh2_channel_close(channel);
 | 
			
		||||
    libssh2_channel_free(channel);
 | 
			
		||||
    channel = null;
 | 
			
		||||
  }
 | 
			
		||||
  if(session) {
 | 
			
		||||
      libssh2_session_disconnect(session, "exit");
 | 
			
		||||
      libssh2_session_free(session);
 | 
			
		||||
      session = null;
 | 
			
		||||
  }
 | 
			
		||||
  if(sock) {
 | 
			
		||||
    close(sock);
 | 
			
		||||
    sock = null;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
WiFiSSHClient &WiFiSSHClient::operator=(const WiFiSSHClient &other)
 | 
			
		||||
{
 | 
			
		||||
  _username = other._username;
 | 
			
		||||
  _password = other._password;
 | 
			
		||||
  sock = other.sock;
 | 
			
		||||
  session = other.session;
 | 
			
		||||
  channel = other.channel;
 | 
			
		||||
  ibufSz = other.ibufSz;
 | 
			
		||||
  memcpy(ibuf, other.ibuf, INTERNAL_BUF_SIZE);
 | 
			
		||||
  return *this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void WiFiSSHClient::stop()
 | 
			
		||||
{
 | 
			
		||||
  closeSSH();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
int WiFiSSHClient::connect(IPAddress ip, uint16_t port)
 | 
			
		||||
{
 | 
			
		||||
  sock = socket(AF_INET, SOCK_STREAM, 0);
 | 
			
		||||
 | 
			
		||||
  struct sockaddr_in sin;
 | 
			
		||||
  sin.sin_family = AF_INET;
 | 
			
		||||
  sin.sin_port = htons(port);
 | 
			
		||||
  sin.sin_addr.s_addr = ip;
 | 
			
		||||
  if(::connect(sock, (struct sockaddr*)(&sin), sizeof(struct sockaddr_in)) != 0)
 | 
			
		||||
    return false;
 | 
			
		||||
  session = libssh2_session_init();
 | 
			
		||||
  if(libssh2_session_handshake(session, sock))
 | 
			
		||||
  {
 | 
			
		||||
    debugPrintf("wifisshclient: failed handshake\n\r");
 | 
			
		||||
    closeSSH();
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
  if(!finishLogin())
 | 
			
		||||
  {
 | 
			
		||||
    debugPrintf("wifisshclient: failed login\n\r");
 | 
			
		||||
    closeSSH();
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
  channel = libssh2_channel_open_session(session);
 | 
			
		||||
  if(!channel)
 | 
			
		||||
  {
 | 
			
		||||
    debugPrintf("wifisshclient: failed session\n\r");
 | 
			
		||||
    closeSSH();
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
  if(libssh2_channel_request_pty(channel, "vanilla")) 
 | 
			
		||||
  {
 | 
			
		||||
    debugPrintf("wifisshclient: failed pty\n\r");
 | 
			
		||||
    closeSSH();
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
  if(libssh2_channel_shell(channel)) {
 | 
			
		||||
    debugPrintf("wifisshclient: failed shell\n\r");
 | 
			
		||||
    closeSSH();
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
  ssize_t err = libssh2_channel_read(channel, ibuf, INTERNAL_BUF_SIZE);
 | 
			
		||||
  if((err > 0) && (err != LIBSSH2_ERROR_EAGAIN)) {
 | 
			
		||||
    ibufSz += err;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
int WiFiSSHClient::connect(IPAddress ip, uint16_t port, int32_t timeout_ms)
 | 
			
		||||
{
 | 
			
		||||
  return connect(ip, port);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int WiFiSSHClient::connect(const char *host, uint16_t port)
 | 
			
		||||
{
 | 
			
		||||
  if(host == null)
 | 
			
		||||
    return false;
 | 
			
		||||
  IPAddress hostIp((uint32_t)0);
 | 
			
		||||
  if(!WiFiGenericClass::hostByName(host, hostIp))
 | 
			
		||||
    return false;
 | 
			
		||||
  return connect(hostIp, port);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int WiFiSSHClient::connect(const char *host, uint16_t port, int32_t timeout_ms)
 | 
			
		||||
{
 | 
			
		||||
  return connect(host, port);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static char _secret[256];
 | 
			
		||||
static    void      kbd_callback(const char *name, int name_len, const char *instruction, int instruction_len,
 | 
			
		||||
                                 int num_prompts, const struct _LIBSSH2_USERAUTH_KBDINT_PROMPT *prompts,
 | 
			
		||||
                                 struct _LIBSSH2_USERAUTH_KBDINT_RESPONSE *responses, void **abstract)
 | 
			
		||||
{
 | 
			
		||||
  (void)name;
 | 
			
		||||
  (void)name_len;
 | 
			
		||||
  (void)instruction;
 | 
			
		||||
  (void)instruction_len;
 | 
			
		||||
  if(num_prompts == 1) {
 | 
			
		||||
      responses[0].text = strdup(_secret);
 | 
			
		||||
      responses[0].length = strlen(_secret);
 | 
			
		||||
  }
 | 
			
		||||
  (void)prompts;
 | 
			
		||||
  (void)abstract;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool WiFiSSHClient::finishLogin()
 | 
			
		||||
{
 | 
			
		||||
  if(_username.length()==0)
 | 
			
		||||
    return true;
 | 
			
		||||
  char *userauthlist;
 | 
			
		||||
  /* check what authentication methods are available */
 | 
			
		||||
  userauthlist = libssh2_userauth_list(session, _username.c_str(), strlen(_username.c_str()));
 | 
			
		||||
  if(strstr(userauthlist, "password") != NULL)
 | 
			
		||||
  {
 | 
			
		||||
    if(libssh2_userauth_password(session, _username.c_str(), _password.c_str()))
 | 
			
		||||
      return false;
 | 
			
		||||
    return true;
 | 
			
		||||
  }
 | 
			
		||||
  else
 | 
			
		||||
  if(strstr(userauthlist, "keyboard-interactive") != NULL)
 | 
			
		||||
  {
 | 
			
		||||
    strcpy(_secret,_password.c_str());
 | 
			
		||||
    if(libssh2_userauth_keyboard_interactive(session, _username.c_str(), &kbd_callback) )
 | 
			
		||||
      return false;
 | 
			
		||||
    else
 | 
			
		||||
      return true;
 | 
			
		||||
  }
 | 
			
		||||
  else
 | 
			
		||||
  if(strstr(userauthlist, "publickey") != NULL)
 | 
			
		||||
  {
 | 
			
		||||
    /*
 | 
			
		||||
      size_t fn1sz, fn2sz;
 | 
			
		||||
      char *fn1, *fn2;
 | 
			
		||||
      char const *h = getenv("HOME");
 | 
			
		||||
      if(!h || !*h)
 | 
			
		||||
          h = ".";
 | 
			
		||||
      fn1sz = strlen(h) + strlen(keyfile1) + 2;
 | 
			
		||||
      fn2sz = strlen(h) + strlen(keyfile2) + 2;
 | 
			
		||||
      fn1 = (char *)malloc(fn1sz);
 | 
			
		||||
      fn2 = (char *)malloc(fn2sz);
 | 
			
		||||
      // Using asprintf() here would be much cleaner, but less portable
 | 
			
		||||
      snprintf(fn1, fn1sz, "%s/%s", h, keyfile1);
 | 
			
		||||
      snprintf(fn2, fn2sz, "%s/%s", h, keyfile2);
 | 
			
		||||
 | 
			
		||||
      if(libssh2_userauth_publickey_fromfile(session, username, fn1,
 | 
			
		||||
                                             fn2, password)) {
 | 
			
		||||
          free(fn2);
 | 
			
		||||
          free(fn1);
 | 
			
		||||
          return false;
 | 
			
		||||
          goto shutdown;
 | 
			
		||||
      }
 | 
			
		||||
      free(fn2);
 | 
			
		||||
      free(fn1);
 | 
			
		||||
      return true;
 | 
			
		||||
    */
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
  else
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void WiFiSSHClient::setLogin(String username, String password)
 | 
			
		||||
{
 | 
			
		||||
  _username = username;
 | 
			
		||||
  _password = password;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void WiFiSSHClient::intern_buffer_fill()
 | 
			
		||||
{
 | 
			
		||||
  if((session != null) && (channel != null))
 | 
			
		||||
  {
 | 
			
		||||
    const size_t bufRemain = INTERNAL_BUF_SIZE - ibufSz;
 | 
			
		||||
    if(bufRemain > 0)
 | 
			
		||||
    {
 | 
			
		||||
      libssh2_session_set_blocking(session, 0);
 | 
			
		||||
      ssize_t err = libssh2_channel_read(channel, ibuf + ibufSz, bufRemain);
 | 
			
		||||
      libssh2_session_set_blocking(session, 1);
 | 
			
		||||
      if((err > 0) && (err != LIBSSH2_ERROR_EAGAIN)) {
 | 
			
		||||
        ibufSz += err;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int WiFiSSHClient::peek()
 | 
			
		||||
{
 | 
			
		||||
  intern_buffer_fill();
 | 
			
		||||
  if(ibufSz > 0)
 | 
			
		||||
    return ibuf[0];
 | 
			
		||||
  return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
size_t WiFiSSHClient::write(uint8_t data)
 | 
			
		||||
{
 | 
			
		||||
  return write(&data, 1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int WiFiSSHClient::read()
 | 
			
		||||
{
 | 
			
		||||
  uint8_t b[1];
 | 
			
		||||
  size_t num = read(b, 1);
 | 
			
		||||
  if(num > 0)
 | 
			
		||||
    return b[0];
 | 
			
		||||
  return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
size_t WiFiSSHClient::write(const uint8_t *buf, size_t size)
 | 
			
		||||
{
 | 
			
		||||
  if(channel != null)
 | 
			
		||||
    return libssh2_channel_write(channel, (const char *)buf, size);
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int WiFiSSHClient::read(uint8_t *buf, size_t size)
 | 
			
		||||
{
 | 
			
		||||
  size_t bytesRead = 0;
 | 
			
		||||
  while(bytesRead < size)
 | 
			
		||||
  {
 | 
			
		||||
    intern_buffer_fill();
 | 
			
		||||
    if(ibufSz == 0)
 | 
			
		||||
      break;
 | 
			
		||||
    size_t bytesToTake = size - bytesRead;
 | 
			
		||||
    if(bytesToTake > ibufSz)
 | 
			
		||||
      bytesToTake = ibufSz;
 | 
			
		||||
    memcpy(buf, ibuf, bytesToTake);
 | 
			
		||||
    if(ibufSz > bytesToTake) // if there are still buffer bytes remaining
 | 
			
		||||
      memcpy(ibuf, ibuf + bytesToTake, ibufSz - bytesToTake);
 | 
			
		||||
    ibufSz -= bytesToTake;
 | 
			
		||||
    bytesRead += bytesToTake;
 | 
			
		||||
  }
 | 
			
		||||
  return (int)bytesRead;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int WiFiSSHClient::available()
 | 
			
		||||
{
 | 
			
		||||
  intern_buffer_fill();
 | 
			
		||||
  return ibufSz;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint8_t WiFiSSHClient::connected()
 | 
			
		||||
{
 | 
			
		||||
  if(ibufSz > 0)
 | 
			
		||||
    return true;
 | 
			
		||||
  intern_buffer_fill();
 | 
			
		||||
  if(ibufSz > 0)
 | 
			
		||||
    return true;
 | 
			
		||||
  if(channel == null)
 | 
			
		||||
    return false;
 | 
			
		||||
  return !libssh2_channel_eof(channel);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int WiFiSSHClient::fd() const
 | 
			
		||||
{
 | 
			
		||||
  return sock;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| 
						 | 
				
			
			@ -0,0 +1,875 @@
 | 
			
		|||
#include <Arduino.h>
 | 
			
		||||
/*
 | 
			
		||||
   Copyright 2016-2019 Bo Zimmerman
 | 
			
		||||
 | 
			
		||||
   Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
   you may not use this file except in compliance with the License.
 | 
			
		||||
   You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
     http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
   Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
   distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
   See the License for the specific language governing permissions and
 | 
			
		||||
   limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
void ZConfig::switchTo()
 | 
			
		||||
{
 | 
			
		||||
  currMode=&configMode;
 | 
			
		||||
  serial.setFlowControlType(commandMode.serial.getFlowControlType());
 | 
			
		||||
  serial.setPetsciiMode(commandMode.serial.isPetsciiMode());
 | 
			
		||||
  savedEcho=commandMode.doEcho;
 | 
			
		||||
  newListen=commandMode.preserveListeners;
 | 
			
		||||
  commandMode.doEcho=true;
 | 
			
		||||
  serverSpec.port=6502;
 | 
			
		||||
  serverSpec.flagsBitmap=commandMode.getConfigFlagBitmap() & (~FLAG_ECHO);
 | 
			
		||||
  if(servs)
 | 
			
		||||
    serverSpec = *servs;
 | 
			
		||||
  serial.setXON(true);
 | 
			
		||||
  showMenu=true;
 | 
			
		||||
  EOLN=commandMode.EOLN;
 | 
			
		||||
  EOLNC=EOLN.c_str();
 | 
			
		||||
  currState = ZCFGMENU_MAIN;
 | 
			
		||||
  lastNumber=0;
 | 
			
		||||
  lastAddress="";
 | 
			
		||||
  lastOptions="";
 | 
			
		||||
  settingsChanged=false;
 | 
			
		||||
  lastNumNetworks=0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ZConfig::serialIncoming()
 | 
			
		||||
{
 | 
			
		||||
  bool crReceived=commandMode.readSerialStream();
 | 
			
		||||
  commandMode.clearPlusProgress(); // re-check the plus-escape mode
 | 
			
		||||
  if(crReceived)
 | 
			
		||||
  {
 | 
			
		||||
    doModeCommand();
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ZConfig::switchBackToCommandMode()
 | 
			
		||||
{
 | 
			
		||||
  commandMode.doEcho=savedEcho;
 | 
			
		||||
  currMode = &commandMode;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ZConfig::doModeCommand()
 | 
			
		||||
{
 | 
			
		||||
  String cmd = commandMode.getNextSerialCommand();
 | 
			
		||||
  char c='?';
 | 
			
		||||
  char sc='?';
 | 
			
		||||
  for(int i=0;i<cmd.length();i++)
 | 
			
		||||
  {
 | 
			
		||||
    if(cmd[i]>32)
 | 
			
		||||
    {
 | 
			
		||||
      c=lc(cmd[i]);
 | 
			
		||||
      if((i<cmd.length()-1)
 | 
			
		||||
      &&(cmd[i+1]>32))
 | 
			
		||||
        sc=lc(cmd[i+1]);
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  switch(currState)
 | 
			
		||||
  {
 | 
			
		||||
    case ZCFGMENU_MAIN:
 | 
			
		||||
    {
 | 
			
		||||
      if((c=='q')||(cmd.length()==0))
 | 
			
		||||
      {
 | 
			
		||||
        if(settingsChanged)
 | 
			
		||||
        {
 | 
			
		||||
          currState=ZCFGMENU_WICONFIRM;
 | 
			
		||||
          showMenu=true;
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
          commandMode.showInitMessage();
 | 
			
		||||
          switchBackToCommandMode();
 | 
			
		||||
          return;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      else
 | 
			
		||||
      if(c=='a') // add to phonebook
 | 
			
		||||
      {
 | 
			
		||||
        currState=ZCFGMENU_NUM;
 | 
			
		||||
        showMenu=true;
 | 
			
		||||
      }
 | 
			
		||||
      else
 | 
			
		||||
      if(c=='w') // wifi
 | 
			
		||||
      {
 | 
			
		||||
        currState=ZCFGMENU_WIMENU;
 | 
			
		||||
        showMenu=true;
 | 
			
		||||
      }
 | 
			
		||||
      else
 | 
			
		||||
      if(c=='h') // host
 | 
			
		||||
      {
 | 
			
		||||
        currState=ZCFGMENU_NEWHOST;
 | 
			
		||||
        showMenu=true;
 | 
			
		||||
      }
 | 
			
		||||
      else
 | 
			
		||||
      if(c=='f') // flow control
 | 
			
		||||
      {
 | 
			
		||||
        currState=ZCFGMENU_FLOW;
 | 
			
		||||
        showMenu=true;
 | 
			
		||||
      }
 | 
			
		||||
      else
 | 
			
		||||
      if((c=='p')&&(sc=='e')) // petscii translation toggle
 | 
			
		||||
      {
 | 
			
		||||
        commandMode.serial.setPetsciiMode(!commandMode.serial.isPetsciiMode());
 | 
			
		||||
        serial.setPetsciiMode(commandMode.serial.isPetsciiMode());
 | 
			
		||||
        settingsChanged=true;
 | 
			
		||||
        showMenu=true;
 | 
			
		||||
      }
 | 
			
		||||
      else
 | 
			
		||||
      if((c=='p')&&(sc=='r')) // print spec
 | 
			
		||||
      {
 | 
			
		||||
        currState=ZCFGMENU_NEWPRINT;
 | 
			
		||||
        showMenu=true;
 | 
			
		||||
      }
 | 
			
		||||
      else
 | 
			
		||||
      if(c=='e') // echo
 | 
			
		||||
      {
 | 
			
		||||
        savedEcho = !savedEcho;
 | 
			
		||||
        settingsChanged=true;
 | 
			
		||||
        showMenu=true;
 | 
			
		||||
      }
 | 
			
		||||
      else
 | 
			
		||||
      if(c=='b') // bbs
 | 
			
		||||
      {
 | 
			
		||||
        currState=ZCFGMENU_BBSMENU;
 | 
			
		||||
        showMenu=true;
 | 
			
		||||
      }
 | 
			
		||||
      else
 | 
			
		||||
      if(c>47 && c<58) // its a phonebook entry!
 | 
			
		||||
      {
 | 
			
		||||
        PhoneBookEntry *pb=PhoneBookEntry::findPhonebookEntry(cmd);
 | 
			
		||||
        if(pb == null)
 | 
			
		||||
        {
 | 
			
		||||
          serial.printf("%s%sPhone number not found: '%s'.%s%s",EOLNC,EOLNC,cmd.c_str(),EOLNC,EOLNC);
 | 
			
		||||
          currState=ZCFGMENU_MAIN;
 | 
			
		||||
          showMenu=true;
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
          lastNumber = pb->number;
 | 
			
		||||
          lastAddress = pb->address;
 | 
			
		||||
          lastOptions = pb->modifiers;
 | 
			
		||||
          lastNotes = pb->notes;
 | 
			
		||||
          currState=ZCFGMENU_ADDRESS;
 | 
			
		||||
          showMenu=true;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      else
 | 
			
		||||
      {
 | 
			
		||||
        showMenu=true; // re-show the menu
 | 
			
		||||
      }
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    case ZCFGMENU_WICONFIRM:
 | 
			
		||||
    {
 | 
			
		||||
      if((cmd.length()==0)||(c=='n'))
 | 
			
		||||
      {
 | 
			
		||||
        commandMode.showInitMessage();
 | 
			
		||||
        switchBackToCommandMode();
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
      else
 | 
			
		||||
      if(c=='y')
 | 
			
		||||
      {
 | 
			
		||||
        if(newListen != commandMode.preserveListeners)
 | 
			
		||||
        {
 | 
			
		||||
          commandMode.preserveListeners=newListen;
 | 
			
		||||
          if(!newListen)
 | 
			
		||||
          {
 | 
			
		||||
            SPIFFS.remove("/zlisteners.txt");
 | 
			
		||||
            WiFiServerNode::DestroyAllServers();
 | 
			
		||||
          }
 | 
			
		||||
          else
 | 
			
		||||
          {
 | 
			
		||||
            commandMode.ringCounter=1;
 | 
			
		||||
            commandMode.autoStreamMode=true;
 | 
			
		||||
            WiFiServerNode *s=WiFiServerNode::FindServer(serverSpec.port);
 | 
			
		||||
            if(s != null)
 | 
			
		||||
              delete s;
 | 
			
		||||
            s = new WiFiServerNode(serverSpec.port,serverSpec.flagsBitmap);
 | 
			
		||||
            WiFiServerNode::SaveWiFiServers();
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        if(commandMode.preserveListeners)
 | 
			
		||||
        {
 | 
			
		||||
          WiFiServerNode *s = WiFiServerNode::FindServer(serverSpec.port);
 | 
			
		||||
          if( s != null)
 | 
			
		||||
          {
 | 
			
		||||
            if(s->flagsBitmap != serverSpec.flagsBitmap)
 | 
			
		||||
            {
 | 
			
		||||
              s->flagsBitmap = serverSpec.flagsBitmap;
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
          else
 | 
			
		||||
          {
 | 
			
		||||
            WiFiServerNode::DestroyAllServers();
 | 
			
		||||
            s = new WiFiServerNode(serverSpec.port,serverSpec.flagsBitmap);
 | 
			
		||||
            WiFiServerNode::SaveWiFiServers();
 | 
			
		||||
            commandMode.updateAutoAnswer();
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
        commandMode.reSaveConfig();
 | 
			
		||||
        serial.printf("%sSettings saved.%s",EOLNC,EOLNC);
 | 
			
		||||
        commandMode.showInitMessage();
 | 
			
		||||
        WiFiServerNode::SaveWiFiServers();
 | 
			
		||||
        switchBackToCommandMode();
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
      else
 | 
			
		||||
        showMenu=true;
 | 
			
		||||
    }
 | 
			
		||||
    case ZCFGMENU_NUM:
 | 
			
		||||
    {
 | 
			
		||||
      PhoneBookEntry *pb=PhoneBookEntry::findPhonebookEntry(cmd);
 | 
			
		||||
      if(pb != null)
 | 
			
		||||
      {
 | 
			
		||||
        serial.printf("%s%sNumber already exists '%s'.%s%s",EOLNC,EOLNC,cmd.c_str(),EOLNC,EOLNC);
 | 
			
		||||
        currState=ZCFGMENU_MAIN;
 | 
			
		||||
        showMenu=true;
 | 
			
		||||
      }
 | 
			
		||||
      else
 | 
			
		||||
      if(cmd.length()==0)
 | 
			
		||||
      {
 | 
			
		||||
        currState=ZCFGMENU_MAIN;
 | 
			
		||||
        showMenu=true;
 | 
			
		||||
      }
 | 
			
		||||
      else
 | 
			
		||||
      {
 | 
			
		||||
        lastNumber = atol((char *)cmd.c_str());
 | 
			
		||||
        lastAddress = "";
 | 
			
		||||
        ConnSettings flags(commandMode.getConfigFlagBitmap());
 | 
			
		||||
        lastOptions = flags.getFlagString();
 | 
			
		||||
        lastNotes = "";
 | 
			
		||||
        currState=ZCFGMENU_ADDRESS;
 | 
			
		||||
        showMenu=true;
 | 
			
		||||
      }
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    case ZCFGMENU_NEWPORT:
 | 
			
		||||
    {
 | 
			
		||||
      if(cmd.length()>0)
 | 
			
		||||
      {
 | 
			
		||||
        serverSpec.port = atoi((char *)cmd.c_str());
 | 
			
		||||
        settingsChanged=true;
 | 
			
		||||
      }
 | 
			
		||||
      currState=ZCFGMENU_BBSMENU;
 | 
			
		||||
      showMenu=true;
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    case ZCFGMENU_ADDRESS:
 | 
			
		||||
    {
 | 
			
		||||
      PhoneBookEntry *entry = PhoneBookEntry::findPhonebookEntry(lastNumber);
 | 
			
		||||
      if(cmd.equalsIgnoreCase("delete") && (entry != null))
 | 
			
		||||
      {
 | 
			
		||||
        delete entry;
 | 
			
		||||
        currState=ZCFGMENU_MAIN;
 | 
			
		||||
        serial.printf("%sPhonebook entry deleted.%s%s",EOLNC,EOLNC,EOLNC);
 | 
			
		||||
      }
 | 
			
		||||
      else
 | 
			
		||||
      if((cmd.length()==0) && (entry != null))
 | 
			
		||||
          currState=ZCFGMENU_NOTES; // just keep old values
 | 
			
		||||
      else
 | 
			
		||||
      {
 | 
			
		||||
        if(!validateHostInfo((uint8_t *)cmd.c_str()))
 | 
			
		||||
          serial.printf("%sInvalid address format (hostname:port) or (user:pass@hostname:port) for '%s'.%s%s",EOLNC,cmd.c_str(),EOLNC,EOLNC);
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
          lastAddress = cmd;
 | 
			
		||||
          currState=ZCFGMENU_NOTES;
 | 
			
		||||
          if(lastAddress.indexOf("@")>0)
 | 
			
		||||
          {
 | 
			
		||||
            int x = lastOptions.indexOf("S"); 
 | 
			
		||||
            if(x<0)
 | 
			
		||||
              lastOptions += "S";
 | 
			
		||||
            else
 | 
			
		||||
              lastOptions = lastOptions.substring(0,x) + lastOptions.substring(x+1);
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      showMenu=true; // re-show the menu
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    case ZCFGMENU_BBSMENU:
 | 
			
		||||
    {
 | 
			
		||||
      if(cmd.length()==0)
 | 
			
		||||
        currState=ZCFGMENU_MAIN;
 | 
			
		||||
      else
 | 
			
		||||
      {
 | 
			
		||||
        ConnSettings flags(serverSpec.flagsBitmap);
 | 
			
		||||
        switch(c)
 | 
			
		||||
        {
 | 
			
		||||
        case 'h':
 | 
			
		||||
          currState=ZCFGMENU_NEWPORT;
 | 
			
		||||
          break;
 | 
			
		||||
        case 'd':
 | 
			
		||||
          newListen=false;
 | 
			
		||||
          settingsChanged=true;
 | 
			
		||||
          break;
 | 
			
		||||
        case 'p': 
 | 
			
		||||
          if(newListen)
 | 
			
		||||
          {
 | 
			
		||||
            flags.petscii=!flags.petscii;
 | 
			
		||||
            settingsChanged=true;
 | 
			
		||||
          }
 | 
			
		||||
          break;
 | 
			
		||||
        case 't': 
 | 
			
		||||
          if(newListen)
 | 
			
		||||
          {
 | 
			
		||||
            flags.telnet=!flags.telnet;
 | 
			
		||||
            settingsChanged=true;
 | 
			
		||||
          }
 | 
			
		||||
          break;
 | 
			
		||||
        case 'e':
 | 
			
		||||
          if(newListen)
 | 
			
		||||
            flags.echo=!flags.echo;
 | 
			
		||||
          else
 | 
			
		||||
            newListen=true;
 | 
			
		||||
          settingsChanged=true;
 | 
			
		||||
          break;
 | 
			
		||||
        case 'f':
 | 
			
		||||
          if(newListen)
 | 
			
		||||
          {
 | 
			
		||||
            if(flags.xonxoff)
 | 
			
		||||
            {
 | 
			
		||||
              flags.xonxoff=false;
 | 
			
		||||
              flags.rtscts=true; 
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            if(flags.rtscts)
 | 
			
		||||
              flags.rtscts=false;
 | 
			
		||||
            else
 | 
			
		||||
              flags.xonxoff=true;
 | 
			
		||||
            settingsChanged=true;
 | 
			
		||||
          }
 | 
			
		||||
          break;
 | 
			
		||||
        case 's': 
 | 
			
		||||
          if(newListen)
 | 
			
		||||
          {
 | 
			
		||||
            flags.secure=!flags.secure;
 | 
			
		||||
            settingsChanged=true;
 | 
			
		||||
          }
 | 
			
		||||
          break;
 | 
			
		||||
         
 | 
			
		||||
        default:
 | 
			
		||||
          serial.printf("%sInvalid option '%s'.%s%s",EOLNC,cmd.c_str(),EOLNC,EOLNC);
 | 
			
		||||
          break;
 | 
			
		||||
        }
 | 
			
		||||
        settingsChanged=true;
 | 
			
		||||
        serverSpec.flagsBitmap = flags.getBitmap();
 | 
			
		||||
      }
 | 
			
		||||
      showMenu=true;
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    case ZCFGMENU_SUBNET:
 | 
			
		||||
    {
 | 
			
		||||
      if(cmd.length()==0)
 | 
			
		||||
        currState=ZCFGMENU_NETMENU;
 | 
			
		||||
      else
 | 
			
		||||
      {
 | 
			
		||||
        IPAddress *newaddr = ConnSettings::parseIP(cmd.c_str());
 | 
			
		||||
        if(newaddr==null)
 | 
			
		||||
          serial.printf("%sBad address (%s).%s",EOLNC,cmd.c_str(),EOLNC);
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
          currState=ZCFGMENU_NETMENU;
 | 
			
		||||
          switch(netOpt)
 | 
			
		||||
          {
 | 
			
		||||
          case 'i': lastIP = *newaddr; break;
 | 
			
		||||
          case 'd': lastDNS = *newaddr; break;
 | 
			
		||||
          case 'g': lastGW = *newaddr; break;
 | 
			
		||||
          case 's': lastSN = *newaddr; break;
 | 
			
		||||
          }
 | 
			
		||||
          free(newaddr);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      showMenu=true;
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    case ZCFGMENU_NETMENU:
 | 
			
		||||
    {
 | 
			
		||||
      if(cmd.length()==0)
 | 
			
		||||
      {
 | 
			
		||||
        currState=ZCFGMENU_MAIN;
 | 
			
		||||
        if((staticIP==null)&&(useDHCP))
 | 
			
		||||
        {}
 | 
			
		||||
        else
 | 
			
		||||
        if(useDHCP)
 | 
			
		||||
        {
 | 
			
		||||
          setNewStaticIPs(null,null,null,null);
 | 
			
		||||
          if(!connectWifi(wifiSSI.c_str(),wifiPW.c_str(),staticIP,staticDNS,staticGW,staticSN))
 | 
			
		||||
            serial.printf("%sUnable to connect to %s. :(%s",EOLNC,wifiSSI.c_str(),EOLNC);
 | 
			
		||||
          settingsChanged=true;
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        if((staticIP==null)
 | 
			
		||||
        ||(*staticIP != lastIP)
 | 
			
		||||
        ||(*staticDNS != lastDNS)
 | 
			
		||||
        ||(*staticGW != lastGW)
 | 
			
		||||
        ||(*staticSN != lastSN))
 | 
			
		||||
        {
 | 
			
		||||
          IPAddress *ip=new IPAddress();
 | 
			
		||||
          *ip = lastIP;
 | 
			
		||||
          IPAddress *dns=new IPAddress();
 | 
			
		||||
          *dns = lastDNS;
 | 
			
		||||
          IPAddress *gw=new IPAddress();
 | 
			
		||||
          *gw = lastGW;
 | 
			
		||||
          IPAddress *sn=new IPAddress();
 | 
			
		||||
          *sn = lastSN;
 | 
			
		||||
          setNewStaticIPs(ip,dns,gw,sn);
 | 
			
		||||
          if(!connectWifi(wifiSSI.c_str(),wifiPW.c_str(),staticIP,staticDNS,staticGW,staticSN))
 | 
			
		||||
            serial.printf("%sUnable to connect to %s. :(%s",EOLNC,wifiSSI.c_str(),EOLNC);
 | 
			
		||||
          settingsChanged=true;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      else
 | 
			
		||||
      if(useDHCP)
 | 
			
		||||
      {
 | 
			
		||||
        if(c=='d')
 | 
			
		||||
          useDHCP=false;
 | 
			
		||||
      }
 | 
			
		||||
      else
 | 
			
		||||
      {
 | 
			
		||||
        switch(c)
 | 
			
		||||
        {
 | 
			
		||||
        case 'e':
 | 
			
		||||
          useDHCP=true;
 | 
			
		||||
          break;
 | 
			
		||||
        case 'i':
 | 
			
		||||
        case 'd': 
 | 
			
		||||
        case 'g':
 | 
			
		||||
        case 's':
 | 
			
		||||
          netOpt=c;
 | 
			
		||||
          currState=ZCFGMENU_SUBNET;
 | 
			
		||||
          break;
 | 
			
		||||
        default:
 | 
			
		||||
          serial.printf("%sInvalid option '%s'.%s%s",EOLNC,cmd.c_str(),EOLNC,EOLNC);
 | 
			
		||||
          break;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      showMenu=true;
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    case ZCFGMENU_NOTES:
 | 
			
		||||
    {
 | 
			
		||||
      if(cmd.length()>0)
 | 
			
		||||
        lastNotes=cmd;
 | 
			
		||||
      currState=ZCFGMENU_OPTIONS;
 | 
			
		||||
      showMenu=true; // re-show the menu
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    case ZCFGMENU_OPTIONS:
 | 
			
		||||
    {
 | 
			
		||||
      if(cmd.length()==0)
 | 
			
		||||
      {
 | 
			
		||||
        PhoneBookEntry *entry = PhoneBookEntry::findPhonebookEntry(lastNumber);
 | 
			
		||||
        if(entry != null)
 | 
			
		||||
        {
 | 
			
		||||
          serial.printf("%sPhonebook entry updated.%s%s",EOLNC,EOLNC,EOLNC);
 | 
			
		||||
          delete entry;
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
          serial.printf("%sPhonebook entry added.%s%s",EOLNC,EOLNC,EOLNC);
 | 
			
		||||
        entry = new PhoneBookEntry(lastNumber,lastAddress.c_str(),lastOptions.c_str(),lastNotes.c_str());
 | 
			
		||||
        PhoneBookEntry::savePhonebook();
 | 
			
		||||
        currState=ZCFGMENU_MAIN;
 | 
			
		||||
      }
 | 
			
		||||
      else
 | 
			
		||||
      {
 | 
			
		||||
        ConnSettings flags(lastOptions.c_str());
 | 
			
		||||
        switch(c)
 | 
			
		||||
        {
 | 
			
		||||
          case 'p': 
 | 
			
		||||
            flags.petscii=!flags.petscii;
 | 
			
		||||
            break;
 | 
			
		||||
          case 't': 
 | 
			
		||||
            flags.telnet=!flags.telnet;
 | 
			
		||||
            break;
 | 
			
		||||
          case 'e': 
 | 
			
		||||
            flags.echo=!flags.echo;
 | 
			
		||||
            break;
 | 
			
		||||
          case 'f':
 | 
			
		||||
            if(flags.xonxoff)
 | 
			
		||||
            {
 | 
			
		||||
              flags.xonxoff=false;
 | 
			
		||||
              flags.rtscts=true; 
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            if(flags.rtscts)
 | 
			
		||||
              flags.rtscts=false;
 | 
			
		||||
            else
 | 
			
		||||
              flags.xonxoff=true;
 | 
			
		||||
            break;
 | 
			
		||||
          case 's': 
 | 
			
		||||
            flags.secure=!flags.secure;
 | 
			
		||||
            break;
 | 
			
		||||
          default:
 | 
			
		||||
            serial.printf("%sInvalid toggle option '%s'.%s%s",EOLNC,cmd.c_str(),EOLNC,EOLNC);
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        lastOptions = flags.getFlagString();
 | 
			
		||||
      }
 | 
			
		||||
      showMenu=true; // re-show the menu
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    case ZCFGMENU_WIMENU:
 | 
			
		||||
    {
 | 
			
		||||
      if(cmd.length()==0)
 | 
			
		||||
      {
 | 
			
		||||
        currState=ZCFGMENU_MAIN;
 | 
			
		||||
        showMenu=true;
 | 
			
		||||
      }
 | 
			
		||||
      else
 | 
			
		||||
      {
 | 
			
		||||
        int num=atoi(cmd.c_str());
 | 
			
		||||
        if((num<=0)||(num>lastNumNetworks))
 | 
			
		||||
            serial.printf("%sInvalid number.  Try again.%s",EOLNC,EOLNC);
 | 
			
		||||
        else
 | 
			
		||||
        if(WiFi.encryptionType(num-1) == ENC_TYPE_NONE)
 | 
			
		||||
        {
 | 
			
		||||
          if(!connectWifi(WiFi.SSID(num-1).c_str(),"",null,null,null,null))
 | 
			
		||||
          {
 | 
			
		||||
            serial.printf("%sUnable to connect to %s. :(%s",EOLNC,WiFi.SSID(num-1).c_str(),EOLNC);
 | 
			
		||||
          }
 | 
			
		||||
          else
 | 
			
		||||
          {
 | 
			
		||||
            wifiSSI=WiFi.SSID(num-1);
 | 
			
		||||
            wifiPW="";
 | 
			
		||||
            settingsChanged=true;
 | 
			
		||||
            serial.printf("%sConnected!%s",EOLNC,EOLNC);
 | 
			
		||||
            currState=ZCFGMENU_NETMENU;
 | 
			
		||||
          }
 | 
			
		||||
          showMenu=true;
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
          lastNumber=num-1;
 | 
			
		||||
          currState=ZCFGMENU_WIFIPW;
 | 
			
		||||
          showMenu=true;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    case ZCFGMENU_NEWHOST:
 | 
			
		||||
      if(cmd.length()==0)
 | 
			
		||||
        currState=ZCFGMENU_WIMENU;
 | 
			
		||||
      else
 | 
			
		||||
      {
 | 
			
		||||
        hostname=cmd;
 | 
			
		||||
        hostname.replace(',','.');
 | 
			
		||||
        if((wifiSSI.length() > 0) && (WiFi.status()==WL_CONNECTED))
 | 
			
		||||
        {
 | 
			
		||||
            if(!connectWifi(wifiSSI.c_str(),wifiPW.c_str(),staticIP,staticDNS,staticGW,staticSN))
 | 
			
		||||
              serial.printf("%sUnable to connect to %s. :(%s",EOLNC,wifiSSI.c_str(),EOLNC);
 | 
			
		||||
            settingsChanged=true;
 | 
			
		||||
        }
 | 
			
		||||
        currState=ZCFGMENU_MAIN;
 | 
			
		||||
        showMenu=true;
 | 
			
		||||
      }
 | 
			
		||||
      break;
 | 
			
		||||
    case ZCFGMENU_NEWPRINT:
 | 
			
		||||
      if(cmd.length()>0)
 | 
			
		||||
      {
 | 
			
		||||
        if(!printMode.testPrinterSpec(cmd.c_str(),cmd.length(),commandMode.serial.isPetsciiMode()))
 | 
			
		||||
        {
 | 
			
		||||
          serial.printf("%sBad format. Try ?:<host>:<port>/<path>.%s",EOLNC,EOLNC);
 | 
			
		||||
          serial.printf("? = A)scii P)etscii or R)aw.%s",EOLNC);
 | 
			
		||||
          serial.printf("Example: R:192.168.1.71:631/ipp/printer%s",EOLNC);
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
          printMode.setLastPrinterSpec(cmd.c_str());
 | 
			
		||||
          settingsChanged=true;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      currState=ZCFGMENU_MAIN;
 | 
			
		||||
      showMenu=true;
 | 
			
		||||
      break;
 | 
			
		||||
    case ZCFGMENU_WIFIPW:
 | 
			
		||||
      if(cmd.length()==0)
 | 
			
		||||
      {
 | 
			
		||||
        currState=ZCFGMENU_WIMENU;
 | 
			
		||||
        showMenu=true;
 | 
			
		||||
      }
 | 
			
		||||
      else
 | 
			
		||||
      {
 | 
			
		||||
          for(int i=0;i<500;i++)
 | 
			
		||||
          {
 | 
			
		||||
            if(serial.isSerialOut())
 | 
			
		||||
              serialOutDeque();
 | 
			
		||||
            delay(1);
 | 
			
		||||
          }
 | 
			
		||||
          if(!connectWifi(WiFi.SSID(lastNumber).c_str(),cmd.c_str(),null,null,null,null))
 | 
			
		||||
            serial.printf("%sUnable to connect to %s.%s",EOLNC,WiFi.SSID(lastNumber).c_str(),EOLNC);
 | 
			
		||||
          else
 | 
			
		||||
          {
 | 
			
		||||
            //setNewStaticIPs(null,null,null,null);
 | 
			
		||||
            useDHCP=(staticIP==null);
 | 
			
		||||
            lastIP=(staticIP != null)?*staticIP:WiFi.localIP();
 | 
			
		||||
            lastDNS=(staticDNS != null)?*staticDNS:IPAddress(192,168,0,1);
 | 
			
		||||
            lastGW=(staticGW != null)?*staticGW:IPAddress(192,168,0,1);
 | 
			
		||||
            lastSN=(staticSN != null)?*staticSN:IPAddress(255,255,255,0);
 | 
			
		||||
            wifiSSI=WiFi.SSID(lastNumber);
 | 
			
		||||
            wifiPW=cmd;
 | 
			
		||||
            settingsChanged=true;
 | 
			
		||||
            currState=ZCFGMENU_NETMENU;
 | 
			
		||||
          }
 | 
			
		||||
          showMenu=true;
 | 
			
		||||
      }
 | 
			
		||||
      break;
 | 
			
		||||
    case ZCFGMENU_FLOW:
 | 
			
		||||
      if(cmd.length()==0)
 | 
			
		||||
      {
 | 
			
		||||
        currState=ZCFGMENU_WIMENU;
 | 
			
		||||
        showMenu=true;
 | 
			
		||||
      }
 | 
			
		||||
      else
 | 
			
		||||
      {
 | 
			
		||||
        currState=ZCFGMENU_MAIN;
 | 
			
		||||
        showMenu=true;
 | 
			
		||||
        if(c=='x')
 | 
			
		||||
          commandMode.serial.setFlowControlType(FCT_NORMAL);
 | 
			
		||||
        else
 | 
			
		||||
        if(c=='r')
 | 
			
		||||
          commandMode.serial.setFlowControlType(FCT_RTSCTS);
 | 
			
		||||
        else
 | 
			
		||||
        if(c=='d')
 | 
			
		||||
          commandMode.serial.setFlowControlType(FCT_DISABLED);
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
          serial.printf("%sUnknown flow control type '%s'.  Try again.%s",EOLNC,cmd.c_str(),EOLNC);
 | 
			
		||||
          currState=ZCFGMENU_FLOW;
 | 
			
		||||
        }
 | 
			
		||||
        settingsChanged = settingsChanged || (currState ==ZCFGMENU_MAIN);
 | 
			
		||||
        serial.setFlowControlType(commandMode.serial.getFlowControlType());
 | 
			
		||||
        serial.setXON(true);
 | 
			
		||||
      }
 | 
			
		||||
      break;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ZConfig::loop()
 | 
			
		||||
{
 | 
			
		||||
  if(showMenu)
 | 
			
		||||
  {
 | 
			
		||||
    showMenu=false;
 | 
			
		||||
    switch(currState)
 | 
			
		||||
    {
 | 
			
		||||
      case ZCFGMENU_MAIN:
 | 
			
		||||
      {
 | 
			
		||||
        serial.printf("%sMain Menu%s",EOLNC,EOLNC);
 | 
			
		||||
        serial.printf("[HOST] name: %s%s",hostname.c_str(),EOLNC);
 | 
			
		||||
        serial.printf("[WIFI] connection: %s%s",(WiFi.status() == WL_CONNECTED)?wifiSSI.c_str():"Not connected",EOLNC);
 | 
			
		||||
        String flowName;
 | 
			
		||||
        switch(commandMode.serial.getFlowControlType())
 | 
			
		||||
        {
 | 
			
		||||
          case FCT_NORMAL:
 | 
			
		||||
            flowName = "XON/XOFF";
 | 
			
		||||
            break;
 | 
			
		||||
          case FCT_RTSCTS:
 | 
			
		||||
            flowName = "RTS/CTS";
 | 
			
		||||
            break;
 | 
			
		||||
          case FCT_DISABLED:
 | 
			
		||||
            flowName = "DISABLED";
 | 
			
		||||
            break;
 | 
			
		||||
          default:
 | 
			
		||||
            flowName = "OTHER";
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        String bbsMode = "DISABLED";
 | 
			
		||||
        if(newListen)
 | 
			
		||||
        {
 | 
			
		||||
          bbsMode = "Port ";
 | 
			
		||||
          bbsMode += serverSpec.port;
 | 
			
		||||
        }
 | 
			
		||||
        serial.printf("[FLOW] control: %s%s",flowName.c_str(),EOLNC);
 | 
			
		||||
        serial.printf("[ECHO] keystrokes: %s%s",savedEcho?"ON":"OFF",EOLNC);
 | 
			
		||||
        serial.printf("[BBS] host: %s%s",bbsMode.c_str(),EOLNC);
 | 
			
		||||
        serial.printf("[PRINT] spec: %s%s",printMode.getLastPrinterSpec(),EOLNC);
 | 
			
		||||
        serial.printf("[PETSCII] translation: %s%s",commandMode.serial.isPetsciiMode()?"ON":"OFF",EOLNC);
 | 
			
		||||
        serial.printf("[ADD] new phonebook entry%s",EOLNC);
 | 
			
		||||
        PhoneBookEntry *p = phonebook;
 | 
			
		||||
        if(p != null)
 | 
			
		||||
        {
 | 
			
		||||
          serial.printf("Phonebook entries:%s",EOLNC);
 | 
			
		||||
          while(p != null)
 | 
			
		||||
          {
 | 
			
		||||
            if(strlen(p->notes)>0)
 | 
			
		||||
              serial.printf("  [%lu] %s (%s)%s",p->number, p->address, p->notes, EOLNC);
 | 
			
		||||
            else
 | 
			
		||||
              serial.printf("  [%lu] %s%s",p->number, p->address, EOLNC);
 | 
			
		||||
            p=p->next;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
        serial.printf("%sEnter command or entry or ENTER to exit: ",EOLNC,EOLNC);
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
      case ZCFGMENU_NUM:
 | 
			
		||||
        serial.printf("%sEnter a new fake phone number (digits ONLY)%s: ",EOLNC,EOLNC);
 | 
			
		||||
        break;
 | 
			
		||||
      case ZCFGMENU_NEWPORT:
 | 
			
		||||
        serial.printf("%sEnter a port number to listen on%s: ",EOLNC,EOLNC);
 | 
			
		||||
        break;
 | 
			
		||||
      case ZCFGMENU_ADDRESS:
 | 
			
		||||
      {
 | 
			
		||||
        PhoneBookEntry *lastEntry = PhoneBookEntry::findPhonebookEntry(lastNumber);
 | 
			
		||||
        if(lastEntry == null)
 | 
			
		||||
          serial.printf("%sEnter hostname:port, or user:pass@hostname:port for SSH%s: ",EOLNC,EOLNC);
 | 
			
		||||
        else
 | 
			
		||||
          serial.printf("%sModify address, or enter DELETE (%s)%s: ",EOLNC,lastAddress.c_str(),EOLNC);
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
      case ZCFGMENU_OPTIONS:
 | 
			
		||||
      {
 | 
			
		||||
        ConnSettings flags(lastOptions.c_str());
 | 
			
		||||
        serial.printf("%sConnection Options:%s",EOLNC,EOLNC);
 | 
			
		||||
        serial.printf("[PETSCII] Translation: %s%s",flags.petscii?"ON":"OFF",EOLNC);
 | 
			
		||||
        serial.printf("[TELNET] Translation: %s%s",flags.telnet?"ON":"OFF",EOLNC);
 | 
			
		||||
        serial.printf("[ECHO]: %s%s",flags.echo?"ON":"OFF",EOLNC);
 | 
			
		||||
        serial.printf("[FLOW] Control: %s%s",flags.xonxoff?"XON/XOFF":flags.rtscts?"RTS/CTS":"DISABLED",EOLNC);
 | 
			
		||||
        serial.printf("[SSH/SSL] Security: %s%s",flags.secure?"ON":"OFF",EOLNC);
 | 
			
		||||
        serial.printf("%sEnter option to toggle or ENTER to exit%s: ",EOLNC,EOLNC);
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
      case ZCFGMENU_NOTES:
 | 
			
		||||
      {
 | 
			
		||||
        serial.printf("%sEnter some notes for this entry (%s)%s: ",EOLNC,lastNotes.c_str(),EOLNC);
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
      case ZCFGMENU_BBSMENU:
 | 
			
		||||
      {
 | 
			
		||||
        serial.printf("%sBBS host settings:%s",EOLNC,EOLNC);
 | 
			
		||||
        if(newListen)
 | 
			
		||||
        {
 | 
			
		||||
          ConnSettings flags(serverSpec.flagsBitmap);
 | 
			
		||||
          serial.printf("%s[HOST] Listener Port: %d%s",EOLNC,serverSpec.port,EOLNC);
 | 
			
		||||
          serial.printf("[PETSCII] Translation: %s%s",flags.petscii?"ON":"OFF",EOLNC);
 | 
			
		||||
          serial.printf("[TELNET] Translation: %s%s",flags.telnet?"ON":"OFF",EOLNC);
 | 
			
		||||
          serial.printf("[ECHO]: %s%s",flags.echo?"ON":"OFF",EOLNC);
 | 
			
		||||
          serial.printf("[FLOW] Control: %s%s",flags.xonxoff?"XON/XOFF":flags.rtscts?"RTS/CTS":"DISABLED",EOLNC);
 | 
			
		||||
          serial.printf("[DISABLE] BBS host listener%s",EOLNC);
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
          serial.printf("%s[ENABLE] BBS host listener%s",EOLNC,EOLNC);
 | 
			
		||||
        serial.printf("%sEnter option to toggle or ENTER to exit%s: ",EOLNC,EOLNC);
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
      case ZCFGMENU_SUBNET:
 | 
			
		||||
      {
 | 
			
		||||
        String str;
 | 
			
		||||
        switch(netOpt)
 | 
			
		||||
        {
 | 
			
		||||
        case 'i':
 | 
			
		||||
        {
 | 
			
		||||
          ConnSettings::IPtoStr(&lastIP,str);
 | 
			
		||||
          serial.printf("%sIP Address (%s)%s: %s",EOLNC,str.c_str(),EOLNC,EOLNC);
 | 
			
		||||
          break;
 | 
			
		||||
        }
 | 
			
		||||
        case 'g':
 | 
			
		||||
        {
 | 
			
		||||
          ConnSettings::IPtoStr(&lastGW,str);
 | 
			
		||||
          serial.printf("%sGateway Address (%s)%s: %s",EOLNC,str.c_str(),EOLNC,EOLNC);
 | 
			
		||||
          break;
 | 
			
		||||
        }
 | 
			
		||||
        case 's':
 | 
			
		||||
        {
 | 
			
		||||
          ConnSettings::IPtoStr(&lastSN,str);
 | 
			
		||||
          serial.printf("%sSubnet Mask Address (%s)%s: %s",EOLNC,str.c_str(),EOLNC,EOLNC);
 | 
			
		||||
          break;
 | 
			
		||||
        }
 | 
			
		||||
        case 'd':
 | 
			
		||||
        {
 | 
			
		||||
          ConnSettings::IPtoStr(&lastDNS,str);
 | 
			
		||||
          serial.printf("%sDNS Address (%s)%s: %s",EOLNC,str.c_str(),EOLNC,EOLNC);
 | 
			
		||||
          break;
 | 
			
		||||
        }
 | 
			
		||||
        }
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
      case ZCFGMENU_NETMENU:
 | 
			
		||||
      {
 | 
			
		||||
        serial.printf("%sNetwork settings:%s",EOLNC,EOLNC);
 | 
			
		||||
        if(!useDHCP)
 | 
			
		||||
        {
 | 
			
		||||
          String str;
 | 
			
		||||
          ConnSettings::IPtoStr(&lastIP,str);
 | 
			
		||||
          serial.printf("%s[IP]: %s%s",EOLNC,str.c_str(),EOLNC);
 | 
			
		||||
          ConnSettings::IPtoStr(&lastSN,str);
 | 
			
		||||
          serial.printf("[SUBNET]: %s%s",str.c_str(),EOLNC);
 | 
			
		||||
          ConnSettings::IPtoStr(&lastGW,str);
 | 
			
		||||
          serial.printf("[GATEWAY]: %s%s",str.c_str(),EOLNC);
 | 
			
		||||
          ConnSettings::IPtoStr(&lastDNS,str);
 | 
			
		||||
          serial.printf("[DNS]: %s%s",str.c_str(),EOLNC);
 | 
			
		||||
          serial.printf("[ENABLE] Enable DHCP%s",EOLNC);
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
          serial.printf("%s[DISABLE] DHCP%s",EOLNC,EOLNC);
 | 
			
		||||
        serial.printf("%sEnter option to toggle or ENTER to exit%s: ",EOLNC,EOLNC);
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
      case ZCFGMENU_WIMENU:
 | 
			
		||||
      {
 | 
			
		||||
        int n = WiFi.scanNetworks();
 | 
			
		||||
        if(n>20)
 | 
			
		||||
          n=20;
 | 
			
		||||
        serial.printf("%sWiFi Networks:%s",EOLNC,EOLNC);
 | 
			
		||||
        lastNumNetworks=n;
 | 
			
		||||
        for (int i = 0; i < n; ++i)
 | 
			
		||||
        {
 | 
			
		||||
          serial.printf("[%d] ",(i+1));
 | 
			
		||||
          serial.prints(WiFi.SSID(i).c_str());
 | 
			
		||||
          serial.prints(" (");
 | 
			
		||||
          serial.printi(WiFi.RSSI(i));
 | 
			
		||||
          serial.prints(")");
 | 
			
		||||
          serial.prints((WiFi.encryptionType(i) == ENC_TYPE_NONE)?" ":"*");
 | 
			
		||||
          serial.prints(EOLN.c_str());
 | 
			
		||||
          serial.flush();
 | 
			
		||||
          delay(10);
 | 
			
		||||
        }
 | 
			
		||||
        serial.printf("%sEnter number to connect, or ENTER: ",EOLNC);
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
      case ZCFGMENU_NEWHOST:
 | 
			
		||||
      {
 | 
			
		||||
        serial.printf("%sEnter a new hostname: ",EOLNC);
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
      case ZCFGMENU_NEWPRINT:
 | 
			
		||||
      {
 | 
			
		||||
        serial.printf("%sEnter ipp printer spec (?:<host>:<port>/path)%s: ",EOLNC,EOLNC);
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
      case ZCFGMENU_WIFIPW:
 | 
			
		||||
      {
 | 
			
		||||
        serial.printf("%sEnter your WiFi Password: ",EOLNC);
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
      case ZCFGMENU_FLOW:
 | 
			
		||||
      {
 | 
			
		||||
        serial.printf("%sEnter RTS/CTS, XON/XOFF, or DISABLE flow control%s: ",EOLNC,EOLNC);
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
      case ZCFGMENU_WICONFIRM:
 | 
			
		||||
      {
 | 
			
		||||
        serial.printf("%sYour setting changed. Save (y/N)?",EOLNC);
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  if(commandMode.checkPlusEscape())
 | 
			
		||||
  {
 | 
			
		||||
    switchBackToCommandMode();
 | 
			
		||||
  }
 | 
			
		||||
  else
 | 
			
		||||
  if(serial.isSerialOut())
 | 
			
		||||
  {
 | 
			
		||||
    serialOutDeque();
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,48 @@
 | 
			
		|||
#include <Arduino.h>
 | 
			
		||||
/*
 | 
			
		||||
   Copyright 2016-2019 Bo Zimmerman
 | 
			
		||||
 | 
			
		||||
   Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
   you may not use this file except in compliance with the License.
 | 
			
		||||
   You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
     http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
   Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
   distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
   See the License for the specific language governing permissions and
 | 
			
		||||
   limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
#ifdef INCLUDE_SD_SHELL
 | 
			
		||||
#ifdef INCLUDE_HOSTCM
 | 
			
		||||
void ZHostCMMode::switchBackToCommandMode()
 | 
			
		||||
{
 | 
			
		||||
  if(proto != 0)
 | 
			
		||||
    delete proto;
 | 
			
		||||
  proto = 0;
 | 
			
		||||
  currMode = &commandMode;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ZHostCMMode::switchTo()
 | 
			
		||||
{
 | 
			
		||||
  currMode=&hostcmMode;
 | 
			
		||||
  if(proto == 0)
 | 
			
		||||
    proto = new HostCM(&SD);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ZHostCMMode::serialIncoming()
 | 
			
		||||
{
 | 
			
		||||
  if(proto != 0)
 | 
			
		||||
    proto->receiveLoop();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ZHostCMMode::loop()
 | 
			
		||||
{
 | 
			
		||||
  serialOutDeque();
 | 
			
		||||
  if((proto != 0) && (proto->isAborted()))
 | 
			
		||||
    switchBackToCommandMode();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,560 @@
 | 
			
		|||
#include <Arduino.h>
 | 
			
		||||
/*
 | 
			
		||||
   Copyright 2016-2019 Bo Zimmerman
 | 
			
		||||
 | 
			
		||||
   Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
   you may not use this file except in compliance with the License.
 | 
			
		||||
   You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
     http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
   Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
   distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
   See the License for the specific language governing permissions and
 | 
			
		||||
   limitations under the License. 
 | 
			
		||||
*/
 | 
			
		||||
//#define TCP_SND_BUF                     4 * TCP_MSS
 | 
			
		||||
#define ZIMODEM_VERSION "4.0.0"
 | 
			
		||||
const char compile_date[] = __DATE__ " " __TIME__;
 | 
			
		||||
#define DEFAULT_NO_DELAY true
 | 
			
		||||
#define null 0
 | 
			
		||||
#define INCLUDE_IRCC true
 | 
			
		||||
//# define USE_DEVUPDATER true // only enable this if your name is Bo
 | 
			
		||||
 | 
			
		||||
#ifdef ARDUINO_ESP32_DEV
 | 
			
		||||
# define ZIMODEM_ESP32
 | 
			
		||||
#elif defined(ESP32)
 | 
			
		||||
# define ZIMODEM_ESP32
 | 
			
		||||
#elif defined(ARDUINO_ESP320)
 | 
			
		||||
# define ZIMODEM_ESP32
 | 
			
		||||
#elif defined(ARDUINO_NANO32)
 | 
			
		||||
# define ZIMODEM_ESP32
 | 
			
		||||
#elif defined(ARDUINO_LoLin32)
 | 
			
		||||
# define ZIMODEM_ESP32
 | 
			
		||||
#elif defined(ARDUINO_ESPea32)
 | 
			
		||||
# define ZIMODEM_ESP32
 | 
			
		||||
#elif defined(ARDUINO_QUANTUM)
 | 
			
		||||
# define ZIMODEM_ESP32
 | 
			
		||||
#else
 | 
			
		||||
# define ZIMODEM_ESP8266
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef SUPPORT_LED_PINS
 | 
			
		||||
# ifdef GPIO_NUM_0
 | 
			
		||||
#   define DEFAULT_PIN_AA GPIO_NUM_16
 | 
			
		||||
#   define DEFAULT_PIN_HS GPIO_NUM_15
 | 
			
		||||
#   define DEFAULT_PIN_WIFI GPIO_NUM_0
 | 
			
		||||
# else
 | 
			
		||||
#   define DEFAULT_PIN_AA 16
 | 
			
		||||
#   define DEFAULT_PIN_HS 15
 | 
			
		||||
#   define DEFAULT_PIN_WIFI 0
 | 
			
		||||
# endif
 | 
			
		||||
# define DEFAULT_HS_BAUD 38400
 | 
			
		||||
# define DEFAULT_AA_ACTIVE LOW
 | 
			
		||||
# define DEFAULT_AA_INACTIVE HIGH
 | 
			
		||||
# define DEFAULT_HS_ACTIVE LOW
 | 
			
		||||
# define DEFAULT_HS_INACTIVE HIGH
 | 
			
		||||
# define DEFAULT_WIFI_ACTIVE LOW
 | 
			
		||||
# define DEFAULT_WIFI_INACTIVE HIGH
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef ZIMODEM_ESP32
 | 
			
		||||
# define PIN_FACTORY_RESET GPIO_NUM_0
 | 
			
		||||
# define DEFAULT_PIN_DCD GPIO_NUM_14
 | 
			
		||||
# define DEFAULT_PIN_CTS GPIO_NUM_13
 | 
			
		||||
# define DEFAULT_PIN_RTS GPIO_NUM_15 // unused
 | 
			
		||||
# define DEFAULT_PIN_RI GPIO_NUM_32
 | 
			
		||||
# define DEFAULT_PIN_DSR GPIO_NUM_12
 | 
			
		||||
# define DEFAULT_PIN_SND GPIO_NUM_25
 | 
			
		||||
# define DEFAULT_PIN_OTH GPIO_NUM_4
 | 
			
		||||
# define DEFAULT_PIN_DTR GPIO_NUM_27
 | 
			
		||||
# define debugPrintf Serial.printf
 | 
			
		||||
# define INCLUDE_SD_SHELL true
 | 
			
		||||
# define DEFAULT_FCT FCT_DISABLED
 | 
			
		||||
# define SerialConfig uint32_t
 | 
			
		||||
# define UART_CONFIG_MASK 0x8000000
 | 
			
		||||
# define UART_NB_BIT_MASK      0B00001100 | UART_CONFIG_MASK
 | 
			
		||||
# define UART_NB_BIT_5         0B00000000 | UART_CONFIG_MASK
 | 
			
		||||
# define UART_NB_BIT_6         0B00000100 | UART_CONFIG_MASK
 | 
			
		||||
# define UART_NB_BIT_7         0B00001000 | UART_CONFIG_MASK
 | 
			
		||||
# define UART_NB_BIT_8         0B00001100 | UART_CONFIG_MASK
 | 
			
		||||
# define UART_PARITY_MASK      0B00000011
 | 
			
		||||
# define UART_PARITY_NONE      0B00000000
 | 
			
		||||
# define UART_NB_STOP_BIT_MASK 0B00110000
 | 
			
		||||
# define UART_NB_STOP_BIT_0    0B00000000
 | 
			
		||||
# define UART_NB_STOP_BIT_1    0B00010000
 | 
			
		||||
# define UART_NB_STOP_BIT_15   0B00100000
 | 
			
		||||
# define UART_NB_STOP_BIT_2    0B00110000
 | 
			
		||||
# define preEOLN serial.prints
 | 
			
		||||
# define echoEOLN serial.write
 | 
			
		||||
//# define HARD_DCD_HIGH 1
 | 
			
		||||
//# define HARD_DCD_LOW 1
 | 
			
		||||
# define INCLUDE_HOSTCM true // safe to remove if you need space
 | 
			
		||||
# define INCLUDE_PING true
 | 
			
		||||
# define INCLUDE_SSH true
 | 
			
		||||
#else  // ESP-8266, e.g. ESP-01, ESP-12E, inverted for C64Net WiFi Modem
 | 
			
		||||
# define DEFAULT_PIN_DSR 13
 | 
			
		||||
# define DEFAULT_PIN_DTR 12
 | 
			
		||||
# define DEFAULT_PIN_RI 14
 | 
			
		||||
# define DEFAULT_PIN_RTS 4
 | 
			
		||||
# define DEFAULT_PIN_CTS 5 // is 0 for ESP-01, see getDefaultCtsPin() below.
 | 
			
		||||
# define DEFAULT_PIN_DCD 2
 | 
			
		||||
# define DEFAULT_FCT FCT_DISABLED
 | 
			
		||||
# define RS232_INVERTED 1
 | 
			
		||||
# define debugPrintf doNothing
 | 
			
		||||
# define preEOLN(...)
 | 
			
		||||
# define echoEOLN(...) serial.prints(EOLN)
 | 
			
		||||
#endif
 | 
			
		||||
#define INCLUDE_SLIP true
 | 
			
		||||
 | 
			
		||||
#ifdef RS232_INVERTED
 | 
			
		||||
# define DEFAULT_DCD_HIGH  HIGH
 | 
			
		||||
# define DEFAULT_DCD_LOW  LOW
 | 
			
		||||
# define DEFAULT_CTS_HIGH  HIGH
 | 
			
		||||
# define DEFAULT_CTS_LOW  LOW
 | 
			
		||||
# define DEFAULT_RTS_HIGH  HIGH
 | 
			
		||||
# define DEFAULT_RTS_LOW  LOW
 | 
			
		||||
# define DEFAULT_RI_HIGH  HIGH
 | 
			
		||||
# define DEFAULT_RI_LOW  LOW
 | 
			
		||||
# define DEFAULT_DSR_HIGH  HIGH
 | 
			
		||||
# define DEFAULT_DSR_LOW  LOW
 | 
			
		||||
# define DEFAULT_DTR_HIGH  HIGH
 | 
			
		||||
# define DEFAULT_DTR_LOW  LOW
 | 
			
		||||
#else
 | 
			
		||||
# define DEFAULT_DCD_HIGH  LOW
 | 
			
		||||
# define DEFAULT_DCD_LOW  HIGH
 | 
			
		||||
# define DEFAULT_CTS_HIGH  LOW
 | 
			
		||||
# define DEFAULT_CTS_LOW  HIGH
 | 
			
		||||
# define DEFAULT_RTS_HIGH  LOW
 | 
			
		||||
# define DEFAULT_RTS_LOW  HIGH
 | 
			
		||||
# define DEFAULT_RI_HIGH  LOW
 | 
			
		||||
# define DEFAULT_RI_LOW  HIGH
 | 
			
		||||
# define DEFAULT_DSR_HIGH  LOW
 | 
			
		||||
# define DEFAULT_DSR_LOW  HIGH
 | 
			
		||||
# define DEFAULT_DTR_HIGH  LOW
 | 
			
		||||
# define DEFAULT_DTR_LOW  HIGH
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define DEFAULT_BAUD_RATE 1200
 | 
			
		||||
#define DEFAULT_SERIAL_CONFIG SERIAL_8N1
 | 
			
		||||
#define MAX_PIN_NO 50
 | 
			
		||||
#define INTERNAL_FLOW_CONTROL_DIV 380
 | 
			
		||||
#define DEFAULT_RECONNECT_DELAY 60000
 | 
			
		||||
#define MAX_RECONNECT_DELAY 1800000
 | 
			
		||||
 | 
			
		||||
class ZMode
 | 
			
		||||
{
 | 
			
		||||
  public:
 | 
			
		||||
    virtual void serialIncoming();
 | 
			
		||||
    virtual void loop();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#include "pet2asc.h"
 | 
			
		||||
#include "rt_clock.h"
 | 
			
		||||
#include "filelog.h"
 | 
			
		||||
#include "serout.h"
 | 
			
		||||
#include "connSettings.h"
 | 
			
		||||
#include "wificlientnode.h"
 | 
			
		||||
#include "stringstream.h"
 | 
			
		||||
#include "phonebook.h"
 | 
			
		||||
#include "wifiservernode.h"
 | 
			
		||||
#include "zstream.h"
 | 
			
		||||
#include "proto_http.h"
 | 
			
		||||
#include "proto_ftp.h"
 | 
			
		||||
#include "zconfigmode.h"
 | 
			
		||||
#include "zcommand.h"
 | 
			
		||||
#include "zprint.h"
 | 
			
		||||
 | 
			
		||||
#ifdef INCLUDE_SD_SHELL
 | 
			
		||||
#  ifdef INCLUDE_HOSTCM
 | 
			
		||||
#    include "zhostcmmode.h"
 | 
			
		||||
#  endif
 | 
			
		||||
#  include "proto_xmodem.h"
 | 
			
		||||
#  include "proto_zmodem.h"
 | 
			
		||||
#  include "proto_kermit.h"
 | 
			
		||||
#  include "zbrowser.h"
 | 
			
		||||
#endif
 | 
			
		||||
#ifdef INCLUDE_SLIP
 | 
			
		||||
#  include "zslipmode.h"
 | 
			
		||||
#endif
 | 
			
		||||
#ifdef INCLUDE_IRCC
 | 
			
		||||
#  include "zircmode.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static WiFiClientNode *conns = null;
 | 
			
		||||
static WiFiServerNode *servs = null;
 | 
			
		||||
static PhoneBookEntry *phonebook = null;
 | 
			
		||||
static bool pinSupport[MAX_PIN_NO];
 | 
			
		||||
static String termType = DEFAULT_TERMTYPE;
 | 
			
		||||
static String busyMsg = DEFAULT_BUSYMSG;
 | 
			
		||||
 | 
			
		||||
static ZMode *currMode = null;
 | 
			
		||||
static ZStream streamMode;
 | 
			
		||||
//static ZSlip slipMode; // not yet implemented
 | 
			
		||||
static ZCommand commandMode;
 | 
			
		||||
static ZPrint printMode;
 | 
			
		||||
static ZConfig configMode;
 | 
			
		||||
static RealTimeClock zclock(0);
 | 
			
		||||
#ifdef INCLUDE_SD_SHELL
 | 
			
		||||
#  ifdef INCLUDE_HOSTCM
 | 
			
		||||
     static ZHostCMMode hostcmMode;
 | 
			
		||||
#  endif
 | 
			
		||||
   static ZBrowser browseMode;
 | 
			
		||||
#endif
 | 
			
		||||
#ifdef INCLUDE_SLIP
 | 
			
		||||
   static ZSLIPMode slipMode;
 | 
			
		||||
#endif
 | 
			
		||||
#ifdef INCLUDE_IRCC
 | 
			
		||||
   static ZIRCMode ircMode;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
enum BaudState
 | 
			
		||||
{
 | 
			
		||||
  BS_NORMAL,
 | 
			
		||||
  BS_SWITCH_TEMP_NEXT,
 | 
			
		||||
  BS_SWITCHED_TEMP,
 | 
			
		||||
  BS_SWITCH_NORMAL_NEXT
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static String wifiSSI;
 | 
			
		||||
static String wifiPW;
 | 
			
		||||
static String hostname;
 | 
			
		||||
static IPAddress *staticIP = null;
 | 
			
		||||
static IPAddress *staticDNS = null;
 | 
			
		||||
static IPAddress *staticGW = null;
 | 
			
		||||
static IPAddress *staticSN = null;
 | 
			
		||||
static unsigned long lastConnectAttempt = 0;
 | 
			
		||||
static unsigned long nextReconnectDelay = 0; // zero means don't attempt reconnects
 | 
			
		||||
static SerialConfig serialConfig = DEFAULT_SERIAL_CONFIG;
 | 
			
		||||
static int baudRate=DEFAULT_BAUD_RATE;
 | 
			
		||||
static int dequeSize=1+(DEFAULT_BAUD_RATE/INTERNAL_FLOW_CONTROL_DIV);
 | 
			
		||||
static BaudState baudState = BS_NORMAL; 
 | 
			
		||||
static unsigned long resetPushTimer=0;
 | 
			
		||||
static int tempBaud = -1; // -1 do nothing
 | 
			
		||||
static int dcdStatus = DEFAULT_DCD_LOW;
 | 
			
		||||
static int pinDCD = DEFAULT_PIN_DCD;
 | 
			
		||||
static int pinCTS = DEFAULT_PIN_CTS;
 | 
			
		||||
static int pinRTS = DEFAULT_PIN_RTS;
 | 
			
		||||
static int pinDSR = DEFAULT_PIN_DSR;
 | 
			
		||||
static int pinDTR = DEFAULT_PIN_DTR;
 | 
			
		||||
static int pinRI = DEFAULT_PIN_RI;
 | 
			
		||||
static int dcdActive = DEFAULT_DCD_HIGH;
 | 
			
		||||
static int dcdInactive = DEFAULT_DCD_LOW;
 | 
			
		||||
static int ctsActive = DEFAULT_CTS_HIGH;
 | 
			
		||||
static int ctsInactive = DEFAULT_CTS_LOW;
 | 
			
		||||
static int rtsActive = DEFAULT_RTS_HIGH;
 | 
			
		||||
static int rtsInactive = DEFAULT_RTS_LOW;
 | 
			
		||||
static int riActive = DEFAULT_RI_HIGH;
 | 
			
		||||
static int riInactive = DEFAULT_RI_LOW;
 | 
			
		||||
static int dtrActive = DEFAULT_DTR_HIGH;
 | 
			
		||||
static int dtrInactive = DEFAULT_DTR_LOW;
 | 
			
		||||
static int dsrActive = DEFAULT_DSR_HIGH;
 | 
			
		||||
static int dsrInactive = DEFAULT_DSR_LOW;
 | 
			
		||||
 | 
			
		||||
static int getDefaultCtsPin()
 | 
			
		||||
{
 | 
			
		||||
#ifdef ZIMODEM_ESP32
 | 
			
		||||
  return DEFAULT_PIN_CTS;
 | 
			
		||||
#else
 | 
			
		||||
  if((ESP.getFlashChipRealSize()/1024)>=4096) // assume this is a striketerm/esp12e
 | 
			
		||||
    return DEFAULT_PIN_CTS;
 | 
			
		||||
  else
 | 
			
		||||
    return 0;
 | 
			
		||||
#endif 
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void doNothing(const char* format, ...) 
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void s_pinWrite(uint8_t pinNo, uint8_t value)
 | 
			
		||||
{
 | 
			
		||||
  if(pinSupport[pinNo])
 | 
			
		||||
  {
 | 
			
		||||
    digitalWrite(pinNo, value);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void setHostName(const char *hname)
 | 
			
		||||
{
 | 
			
		||||
#ifdef ZIMODEM_ESP32
 | 
			
		||||
      tcpip_adapter_set_hostname(TCPIP_ADAPTER_IF_STA, hname);
 | 
			
		||||
#else
 | 
			
		||||
      WiFi.hostname(hname);
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void setNewStaticIPs(IPAddress *ip, IPAddress *dns, IPAddress *gateWay, IPAddress *subNet)
 | 
			
		||||
{
 | 
			
		||||
  if(staticIP != null)
 | 
			
		||||
    free(staticIP);
 | 
			
		||||
  staticIP = ip;
 | 
			
		||||
  if(staticDNS != null)
 | 
			
		||||
    free(staticDNS);
 | 
			
		||||
  staticDNS = dns;
 | 
			
		||||
  if(staticGW != null)
 | 
			
		||||
    free(staticGW);
 | 
			
		||||
  staticGW = gateWay;
 | 
			
		||||
  if(staticSN != null)
 | 
			
		||||
    free(staticSN);
 | 
			
		||||
  staticSN = subNet;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool connectWifi(const char* ssid, const char* password, IPAddress *ip, IPAddress *dns, IPAddress *gateWay, IPAddress *subNet)
 | 
			
		||||
{
 | 
			
		||||
  while(WiFi.status() == WL_CONNECTED)
 | 
			
		||||
  {
 | 
			
		||||
    WiFi.disconnect();
 | 
			
		||||
    delay(100);
 | 
			
		||||
    yield();
 | 
			
		||||
  }
 | 
			
		||||
#ifndef ZIMODEM_ESP32
 | 
			
		||||
  if(hostname.length() > 0)
 | 
			
		||||
    setHostName(hostname.c_str());
 | 
			
		||||
#endif
 | 
			
		||||
  WiFi.mode(WIFI_STA);
 | 
			
		||||
  if((ip != null)&&(gateWay != null)&&(dns != null)&&(subNet!=null))
 | 
			
		||||
  {
 | 
			
		||||
    if(!WiFi.config(*ip,*gateWay,*subNet,*dns))
 | 
			
		||||
      return false;
 | 
			
		||||
  }
 | 
			
		||||
  WiFi.begin(ssid, password);
 | 
			
		||||
  if(hostname.length() > 0)
 | 
			
		||||
    setHostName(hostname.c_str());
 | 
			
		||||
  bool amConnected = (WiFi.status() == WL_CONNECTED) && (strcmp(WiFi.localIP().toString().c_str(), "0.0.0.0")!=0);
 | 
			
		||||
  int WiFiCounter = 0;
 | 
			
		||||
  while ((!amConnected) && (WiFiCounter < 20))
 | 
			
		||||
  {
 | 
			
		||||
    WiFiCounter++;
 | 
			
		||||
    if(!amConnected)
 | 
			
		||||
      delay(500);
 | 
			
		||||
    amConnected = (WiFi.status() == WL_CONNECTED) && (strcmp(WiFi.localIP().toString().c_str(), "0.0.0.0")!=0);
 | 
			
		||||
  }
 | 
			
		||||
  lastConnectAttempt = millis();
 | 
			
		||||
  if(lastConnectAttempt == 0)  // it IS possible for millis() to be 0, but we need to ignore it.
 | 
			
		||||
    lastConnectAttempt = 1; // 0 is a special case, so skip it
 | 
			
		||||
 | 
			
		||||
  if(!amConnected)
 | 
			
		||||
  {
 | 
			
		||||
    nextReconnectDelay = 0; // assume no retry is desired.. let the caller set it up, as it could be bad PW
 | 
			
		||||
    WiFi.disconnect();
 | 
			
		||||
  }
 | 
			
		||||
  else
 | 
			
		||||
    nextReconnectDelay = DEFAULT_RECONNECT_DELAY; // if connected, we always want to try reconns in the future
 | 
			
		||||
 | 
			
		||||
#ifdef SUPPORT_LED_PINS
 | 
			
		||||
  s_pinWrite(DEFAULT_PIN_WIFI,(WiFi.status() == WL_CONNECTED)?DEFAULT_WIFI_ACTIVE:DEFAULT_WIFI_INACTIVE);
 | 
			
		||||
#endif
 | 
			
		||||
  return (WiFi.status() == WL_CONNECTED);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void checkBaudChange()
 | 
			
		||||
{
 | 
			
		||||
  switch(baudState)
 | 
			
		||||
  {
 | 
			
		||||
    case BS_SWITCH_TEMP_NEXT:
 | 
			
		||||
      changeBaudRate(tempBaud);
 | 
			
		||||
      baudState = BS_SWITCHED_TEMP;
 | 
			
		||||
      break;
 | 
			
		||||
    case BS_SWITCH_NORMAL_NEXT:
 | 
			
		||||
      changeBaudRate(baudRate);
 | 
			
		||||
      baudState = BS_NORMAL;
 | 
			
		||||
      break;
 | 
			
		||||
    default:
 | 
			
		||||
      break;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void changeBaudRate(int baudRate)
 | 
			
		||||
{
 | 
			
		||||
  flushSerial(); // blocking, but very very necessary
 | 
			
		||||
  delay(500); // give the client half a sec to catch up
 | 
			
		||||
  logPrintfln("Baud change to %d.\n",baudRate);
 | 
			
		||||
  debugPrintf("Baud change to %d.\n",baudRate);
 | 
			
		||||
  dequeSize=1+(baudRate/INTERNAL_FLOW_CONTROL_DIV);
 | 
			
		||||
  debugPrintf("Deque constant now: %d\n",dequeSize);
 | 
			
		||||
#ifdef ZIMODEM_ESP32
 | 
			
		||||
  HWSerial.updateBaudRate(baudRate);
 | 
			
		||||
#else
 | 
			
		||||
  HWSerial.begin(baudRate, serialConfig);  //Change baud rate
 | 
			
		||||
#endif
 | 
			
		||||
#ifdef SUPPORT_LED_PINS
 | 
			
		||||
  s_pinWrite(DEFAULT_PIN_HS,(baudRate>=DEFAULT_HS_BAUD)?DEFAULT_HS_ACTIVE:DEFAULT_HS_INACTIVE);
 | 
			
		||||
#endif  
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void changeSerialConfig(SerialConfig conf)
 | 
			
		||||
{
 | 
			
		||||
  flushSerial(); // blocking, but very very necessary
 | 
			
		||||
  delay(500); // give the client half a sec to catch up
 | 
			
		||||
  debugPrintf("Config changing to %d.\n",(int)conf);
 | 
			
		||||
  dequeSize=1+(baudRate/INTERNAL_FLOW_CONTROL_DIV);
 | 
			
		||||
  debugPrintf("Deque constant now: %d\n",dequeSize);
 | 
			
		||||
  HWSerial.begin(baudRate, conf);  //Change baud rate
 | 
			
		||||
  debugPrintf("Config changed.\n");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int checkOpenConnections()
 | 
			
		||||
{
 | 
			
		||||
  int num=WiFiClientNode::getNumOpenWiFiConnections();
 | 
			
		||||
  if(num == 0)
 | 
			
		||||
  {
 | 
			
		||||
    if((dcdStatus == dcdActive)
 | 
			
		||||
    &&(dcdStatus != dcdInactive))
 | 
			
		||||
    {
 | 
			
		||||
      logPrintfln("DCD going inactive.\n");
 | 
			
		||||
      dcdStatus = dcdInactive;
 | 
			
		||||
      s_pinWrite(pinDCD,dcdStatus);
 | 
			
		||||
      if(baudState == BS_SWITCHED_TEMP)
 | 
			
		||||
        baudState = BS_SWITCH_NORMAL_NEXT;
 | 
			
		||||
      if(currMode == &commandMode)
 | 
			
		||||
        clearSerialOutBuffer();
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  else
 | 
			
		||||
  {
 | 
			
		||||
    if((dcdStatus == dcdInactive)
 | 
			
		||||
    &&(dcdStatus != dcdActive))
 | 
			
		||||
    {
 | 
			
		||||
      logPrintfln("DCD going active.\n");
 | 
			
		||||
      dcdStatus = dcdActive;
 | 
			
		||||
      s_pinWrite(pinDCD,dcdStatus);
 | 
			
		||||
      if((tempBaud > 0) && (baudState == BS_NORMAL))
 | 
			
		||||
        baudState = BS_SWITCH_TEMP_NEXT;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  return num;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void setup() 
 | 
			
		||||
{
 | 
			
		||||
  for(int i=0;i<MAX_PIN_NO;i++)
 | 
			
		||||
    pinSupport[i]=false;
 | 
			
		||||
#ifdef ZIMODEM_ESP32
 | 
			
		||||
  Serial.begin(115200); //the debug port
 | 
			
		||||
  Serial.setDebugOutput(true);
 | 
			
		||||
  debugPrintf("Debug port open and ready.\n");
 | 
			
		||||
  pinSupport[4]=true;
 | 
			
		||||
  pinSupport[5]=true;
 | 
			
		||||
  for(int i=12;i<=23;i++)
 | 
			
		||||
    pinSupport[i]=true;
 | 
			
		||||
  for(int i=25;i<=27;i++)
 | 
			
		||||
    pinSupport[i]=true;
 | 
			
		||||
  for(int i=32;i<=33;i++)
 | 
			
		||||
    pinSupport[i]=true;
 | 
			
		||||
#else
 | 
			
		||||
  pinSupport[0]=true;
 | 
			
		||||
  pinSupport[2]=true;
 | 
			
		||||
  if((ESP.getFlashChipRealSize()/1024)>=4096) // assume this is a strykelink/esp12e
 | 
			
		||||
  {
 | 
			
		||||
    pinSupport[4]=true;
 | 
			
		||||
    pinSupport[5]=true;
 | 
			
		||||
    for(int i=9;i<=16;i++)
 | 
			
		||||
      pinSupport[i]=true;
 | 
			
		||||
    pinSupport[11]=false;
 | 
			
		||||
  }
 | 
			
		||||
#endif    
 | 
			
		||||
  initSDShell();
 | 
			
		||||
  currMode = &commandMode;
 | 
			
		||||
  if(!SPIFFS.begin())
 | 
			
		||||
  {
 | 
			
		||||
    SPIFFS.format();
 | 
			
		||||
    SPIFFS.begin();
 | 
			
		||||
    debugPrintf("SPIFFS Formatted.");
 | 
			
		||||
  }
 | 
			
		||||
  HWSerial.begin(DEFAULT_BAUD_RATE, DEFAULT_SERIAL_CONFIG);  //Start Serial
 | 
			
		||||
#ifdef ZIMODEM_ESP8266
 | 
			
		||||
  HWSerial.setRxBufferSize(1024);
 | 
			
		||||
#endif
 | 
			
		||||
  commandMode.loadConfig();
 | 
			
		||||
  PhoneBookEntry::loadPhonebook();
 | 
			
		||||
  dcdStatus = dcdInactive;
 | 
			
		||||
  s_pinWrite(pinDCD,dcdStatus);
 | 
			
		||||
  flushSerial();
 | 
			
		||||
#ifdef SUPPORT_LED_PINS
 | 
			
		||||
  s_pinWrite(DEFAULT_PIN_WIFI,(WiFi.status() == WL_CONNECTED)?DEFAULT_WIFI_ACTIVE:DEFAULT_WIFI_INACTIVE);
 | 
			
		||||
  s_pinWrite(DEFAULT_PIN_HS,(baudRate>=DEFAULT_HS_BAUD)?DEFAULT_HS_ACTIVE:DEFAULT_HS_INACTIVE);
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void checkReconnect()
 | 
			
		||||
{
 | 
			
		||||
  if((WiFi.status() != WL_CONNECTED)
 | 
			
		||||
  &&(nextReconnectDelay>0)
 | 
			
		||||
  &&(lastConnectAttempt>0)
 | 
			
		||||
  &&(wifiSSI.length()>0))
 | 
			
		||||
  {
 | 
			
		||||
     unsigned long now=millis();
 | 
			
		||||
     if(lastConnectAttempt > now)
 | 
			
		||||
       lastConnectAttempt=1;
 | 
			
		||||
     if(now > lastConnectAttempt + nextReconnectDelay)
 | 
			
		||||
     {
 | 
			
		||||
        debugPrintf("Attempting Reconnect to %s\n",wifiSSI.c_str());
 | 
			
		||||
        unsigned long oldReconnectDelay = nextReconnectDelay;
 | 
			
		||||
        if(!connectWifi(wifiSSI.c_str(),wifiPW.c_str(),staticIP,staticDNS,staticGW,staticSN))
 | 
			
		||||
          debugPrintf("%sUnable to reconnect to %s.\n",wifiSSI.c_str());
 | 
			
		||||
        nextReconnectDelay = oldReconnectDelay * 2;
 | 
			
		||||
        if(nextReconnectDelay > MAX_RECONNECT_DELAY)
 | 
			
		||||
          nextReconnectDelay = DEFAULT_RECONNECT_DELAY;
 | 
			
		||||
     }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void checkFactoryReset()
 | 
			
		||||
{
 | 
			
		||||
#ifdef ZIMODEM_ESP32
 | 
			
		||||
    if(!digitalRead(PIN_FACTORY_RESET))
 | 
			
		||||
    {
 | 
			
		||||
      if(resetPushTimer != 1)
 | 
			
		||||
      {
 | 
			
		||||
        if(resetPushTimer==0)
 | 
			
		||||
        {
 | 
			
		||||
          resetPushTimer=millis();
 | 
			
		||||
          if(resetPushTimer==1)
 | 
			
		||||
            resetPushTimer++;
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        if((millis() - resetPushTimer) > 5000)
 | 
			
		||||
        {
 | 
			
		||||
          SPIFFS.remove(CONFIG_FILE);
 | 
			
		||||
          SPIFFS.remove(CONFIG_FILE_OLD);
 | 
			
		||||
          SPIFFS.remove("/zphonebook.txt");
 | 
			
		||||
          SPIFFS.remove("/zlisteners.txt");
 | 
			
		||||
          PhoneBookEntry::clearPhonebook();
 | 
			
		||||
          SPIFFS.end();
 | 
			
		||||
          SPIFFS.format();
 | 
			
		||||
          SPIFFS.begin();
 | 
			
		||||
          PhoneBookEntry::clearPhonebook();
 | 
			
		||||
          if(WiFi.status() == WL_CONNECTED)
 | 
			
		||||
            WiFi.disconnect();
 | 
			
		||||
          baudRate = DEFAULT_BAUD_RATE;
 | 
			
		||||
          commandMode.loadConfig();
 | 
			
		||||
          PhoneBookEntry::loadPhonebook();
 | 
			
		||||
          dcdStatus = dcdInactive;
 | 
			
		||||
          s_pinWrite(pinDCD,dcdStatus);
 | 
			
		||||
          wifiSSI="";
 | 
			
		||||
          delay(500);
 | 
			
		||||
          zclock.reset();
 | 
			
		||||
          commandMode.reset();
 | 
			
		||||
          resetPushTimer=1;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    if(resetPushTimer != 0)
 | 
			
		||||
      resetPushTimer=0;
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void loop() 
 | 
			
		||||
{
 | 
			
		||||
  checkFactoryReset();
 | 
			
		||||
  checkReconnect();
 | 
			
		||||
  if(HWSerial.available())
 | 
			
		||||
  {
 | 
			
		||||
    currMode->serialIncoming();
 | 
			
		||||
  }
 | 
			
		||||
  currMode->loop();
 | 
			
		||||
  zclock.tick();
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,539 @@
 | 
			
		|||
#include <Arduino.h>
 | 
			
		||||
/*
 | 
			
		||||
 * zircmode.ino
 | 
			
		||||
 *
 | 
			
		||||
 *  Created on: May 18, 2022
 | 
			
		||||
 *      Author: Bo Zimmerman
 | 
			
		||||
 */
 | 
			
		||||
#ifdef INCLUDE_IRCC
 | 
			
		||||
//https://github.com/bl4de/irc-client/blob/master/irc_client.py
 | 
			
		||||
void ZIRCMode::switchBackToCommandMode()
 | 
			
		||||
{
 | 
			
		||||
  serial.println("Back in command mode.");
 | 
			
		||||
  if(current != null)
 | 
			
		||||
  {
 | 
			
		||||
    delete current;
 | 
			
		||||
    current = null;
 | 
			
		||||
  }
 | 
			
		||||
  currMode = &commandMode;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ZIRCMode::switchTo()
 | 
			
		||||
{
 | 
			
		||||
  currMode=&ircMode;
 | 
			
		||||
  savedEcho=commandMode.doEcho;
 | 
			
		||||
  commandMode.doEcho=true;
 | 
			
		||||
  serial.setFlowControlType(commandMode.serial.getFlowControlType());
 | 
			
		||||
  serial.setPetsciiMode(commandMode.serial.isPetsciiMode());
 | 
			
		||||
  showMenu=true;
 | 
			
		||||
  EOLN=commandMode.EOLN;
 | 
			
		||||
  EOLNC=EOLN.c_str();
 | 
			
		||||
  currState=ZIRCMENU_MAIN;
 | 
			
		||||
  lastNumber=0;
 | 
			
		||||
  lastAddress="";
 | 
			
		||||
  lastOptions="";
 | 
			
		||||
  channelName="";
 | 
			
		||||
  joinReceived=false;
 | 
			
		||||
  if(nick.length()==0)
 | 
			
		||||
  {
 | 
			
		||||
    randomSeed(millis());
 | 
			
		||||
    char tempNick[50];
 | 
			
		||||
    sprintf(tempNick,"ChangeMe#%ld",random(1,999));
 | 
			
		||||
    nick = tempNick;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ZIRCMode::doIRCCommand()
 | 
			
		||||
{
 | 
			
		||||
  String cmd = commandMode.getNextSerialCommand();
 | 
			
		||||
  char c='?';
 | 
			
		||||
  while((cmd.length()>0)
 | 
			
		||||
  &&(cmd[0]==32)||(cmd[0]==7))
 | 
			
		||||
    cmd = cmd.substring(1);
 | 
			
		||||
  if(cmd.length()>0)
 | 
			
		||||
    c=lc(cmd[0]);
 | 
			
		||||
  switch(currState)
 | 
			
		||||
  {
 | 
			
		||||
    case ZIRCMENU_MAIN:
 | 
			
		||||
    {
 | 
			
		||||
      if((c=='q')||(cmd.length()==0))
 | 
			
		||||
      {
 | 
			
		||||
        commandMode.showInitMessage();
 | 
			
		||||
        switchBackToCommandMode();
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
      else
 | 
			
		||||
      if(c=='a') // add to phonebook
 | 
			
		||||
      {
 | 
			
		||||
        currState=ZIRCMENU_NUM;
 | 
			
		||||
        showMenu=true;
 | 
			
		||||
      }
 | 
			
		||||
      else
 | 
			
		||||
      if(c=='n') // change nick
 | 
			
		||||
      {
 | 
			
		||||
        currState=ZIRCMENU_NICK;
 | 
			
		||||
        showMenu=true;
 | 
			
		||||
      }
 | 
			
		||||
      else
 | 
			
		||||
      if(c>47 && c<58) // its a phonebook entry!
 | 
			
		||||
      {
 | 
			
		||||
        PhoneBookEntry *pb=PhoneBookEntry::findPhonebookEntry(cmd);
 | 
			
		||||
        if(pb == null)
 | 
			
		||||
        {
 | 
			
		||||
          serial.printf("%s%sPhone number not found: '%s'.%s%s",EOLNC,EOLNC,cmd.c_str(),EOLNC,EOLNC);
 | 
			
		||||
          currState=ZIRCMENU_MAIN;
 | 
			
		||||
          showMenu=true;
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
          serial.printf("%s%sConnecting to %s...%s%s",EOLNC,EOLNC,pb->address,EOLNC,EOLNC);
 | 
			
		||||
          String address = pb->address;
 | 
			
		||||
          char vbuf[address.length()+1];
 | 
			
		||||
          strcpy(vbuf,pb->address);
 | 
			
		||||
          char *colon=strstr((char *)vbuf,":");
 | 
			
		||||
          int port=6666;
 | 
			
		||||
          if(colon != null)
 | 
			
		||||
          {
 | 
			
		||||
            (*colon)=0;
 | 
			
		||||
            port=atoi((char *)(++colon));
 | 
			
		||||
          }
 | 
			
		||||
          int flagsBitmap=0;
 | 
			
		||||
          {
 | 
			
		||||
            ConnSettings flags("");
 | 
			
		||||
            flagsBitmap = flags.getBitmap(serial.getFlowControlType());
 | 
			
		||||
          }
 | 
			
		||||
          logPrintfln("Connnecting: %s %d %d",(char *)vbuf,port,flagsBitmap);
 | 
			
		||||
          WiFiClientNode *c = new WiFiClientNode((char *)vbuf,port,flagsBitmap);
 | 
			
		||||
          if(!c->isConnected())
 | 
			
		||||
          {
 | 
			
		||||
            logPrintln("Connnect: FAIL");
 | 
			
		||||
            serial.prints("Connection failed.\n\r"); //TODO: maybe get rid of?
 | 
			
		||||
            currState=ZIRCMENU_MAIN;
 | 
			
		||||
            showMenu=true;
 | 
			
		||||
          }
 | 
			
		||||
          else
 | 
			
		||||
          {
 | 
			
		||||
            logPrintfln("Connnect: SUCCESS: %d",c->id);
 | 
			
		||||
            serial.prints("Connected.\n\r"); //TODO: maybe get rid of?
 | 
			
		||||
            current=c;
 | 
			
		||||
            buf = "";
 | 
			
		||||
            currState=ZIRCMENU_COMMAND;
 | 
			
		||||
            ircState=ZIRCSTATE_WAIT;
 | 
			
		||||
            timeout=millis()+6000;
 | 
			
		||||
            showMenu=true; // only wait to get it to act
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      else
 | 
			
		||||
      {
 | 
			
		||||
        showMenu=true; // re-show the menu
 | 
			
		||||
      }
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    case ZIRCMENU_NUM:
 | 
			
		||||
    {
 | 
			
		||||
      PhoneBookEntry *pb=PhoneBookEntry::findPhonebookEntry(cmd);
 | 
			
		||||
      if(pb != null)
 | 
			
		||||
      {
 | 
			
		||||
        serial.printf("%s%sNumber already exists '%s'.%s%s",EOLNC,EOLNC,cmd.c_str(),EOLNC,EOLNC);
 | 
			
		||||
        currState=ZIRCMENU_MAIN;
 | 
			
		||||
        showMenu=true;
 | 
			
		||||
      }
 | 
			
		||||
      else
 | 
			
		||||
      if(cmd.length()==0)
 | 
			
		||||
      {
 | 
			
		||||
        currState=ZIRCMENU_MAIN;
 | 
			
		||||
        showMenu=true;
 | 
			
		||||
      }
 | 
			
		||||
      else
 | 
			
		||||
      {
 | 
			
		||||
        lastNumber = atol((char *)cmd.c_str());
 | 
			
		||||
        lastAddress = "";
 | 
			
		||||
        ConnSettings flags(commandMode.getConfigFlagBitmap());
 | 
			
		||||
        lastOptions = flags.getFlagString();
 | 
			
		||||
        lastNotes = "";
 | 
			
		||||
        currState=ZIRCMENU_ADDRESS;
 | 
			
		||||
        showMenu=true;
 | 
			
		||||
      }
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    case ZIRCMENU_ADDRESS:
 | 
			
		||||
    {
 | 
			
		||||
      PhoneBookEntry *entry = PhoneBookEntry::findPhonebookEntry(lastNumber);
 | 
			
		||||
      if(cmd.equalsIgnoreCase("delete") && (entry != null))
 | 
			
		||||
      {
 | 
			
		||||
        delete entry;
 | 
			
		||||
        currState=ZIRCMENU_MAIN;
 | 
			
		||||
        serial.printf("%sPhonebook entry deleted.%s%s",EOLNC,EOLNC,EOLNC);
 | 
			
		||||
      }
 | 
			
		||||
      else
 | 
			
		||||
      if((cmd.length()==0) && (entry != null))
 | 
			
		||||
          currState=ZIRCMENU_NOTES; // just keep old values
 | 
			
		||||
      else
 | 
			
		||||
      {
 | 
			
		||||
        boolean fail = cmd.indexOf(',') >= 0;
 | 
			
		||||
        int colonDex=cmd.indexOf(':');
 | 
			
		||||
        fail = fail || (colonDex <= 0) || (colonDex == cmd.length()-1);
 | 
			
		||||
        fail = fail || (colonDex != cmd.lastIndexOf(':'));
 | 
			
		||||
        if(!fail)
 | 
			
		||||
        {
 | 
			
		||||
          for(int i=colonDex+1;i<cmd.length();i++)
 | 
			
		||||
            if(strchr("0123456789",cmd[i])<0)
 | 
			
		||||
              fail=true;
 | 
			
		||||
        }
 | 
			
		||||
        if(fail)
 | 
			
		||||
        {
 | 
			
		||||
          serial.printf("%sInvalid address format (hostname:port) for '%s'.%s%s",EOLNC,cmd.c_str(),EOLNC,EOLNC);
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
          lastAddress = cmd;
 | 
			
		||||
          currState=ZIRCMENU_NOTES;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      showMenu=true; // re-show the menu
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    case ZIRCMENU_NOTES:
 | 
			
		||||
    {
 | 
			
		||||
      if(cmd.length()>0)
 | 
			
		||||
        lastNotes=cmd;
 | 
			
		||||
      currState=ZIRCMENU_OPTIONS;
 | 
			
		||||
      showMenu=true; // re-show the menu
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    case ZIRCMENU_NICK:
 | 
			
		||||
    {
 | 
			
		||||
      if(cmd.length()>0)
 | 
			
		||||
        nick=cmd;
 | 
			
		||||
      currState=ZIRCMENU_MAIN;
 | 
			
		||||
      showMenu=true; // re-show the menu
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    case ZIRCMENU_OPTIONS:
 | 
			
		||||
    {
 | 
			
		||||
      if(cmd.length()==0)
 | 
			
		||||
      {
 | 
			
		||||
        serial.printf("%sPhonebook entry added.%s%s",EOLNC,EOLNC,EOLNC);
 | 
			
		||||
        PhoneBookEntry *entry = new PhoneBookEntry(lastNumber,lastAddress.c_str(),lastOptions.c_str(),lastNotes.c_str());
 | 
			
		||||
        PhoneBookEntry::savePhonebook();
 | 
			
		||||
        currState=ZIRCMENU_MAIN;
 | 
			
		||||
      }
 | 
			
		||||
      else
 | 
			
		||||
      {
 | 
			
		||||
        ConnSettings flags(lastOptions.c_str());
 | 
			
		||||
        switch(c)
 | 
			
		||||
        {
 | 
			
		||||
          case 'p':
 | 
			
		||||
            flags.petscii=!flags.petscii;
 | 
			
		||||
            break;
 | 
			
		||||
          case 't':
 | 
			
		||||
            flags.telnet=!flags.telnet;
 | 
			
		||||
            break;
 | 
			
		||||
          case 'e':
 | 
			
		||||
            flags.echo=!flags.echo;
 | 
			
		||||
            break;
 | 
			
		||||
          case 'f':
 | 
			
		||||
            if(flags.xonxoff)
 | 
			
		||||
            {
 | 
			
		||||
              flags.xonxoff=false;
 | 
			
		||||
              flags.rtscts=true;
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            if(flags.rtscts)
 | 
			
		||||
              flags.rtscts=false;
 | 
			
		||||
            else
 | 
			
		||||
              flags.xonxoff=true;
 | 
			
		||||
            break;
 | 
			
		||||
          case 's':
 | 
			
		||||
            flags.secure=!flags.secure;
 | 
			
		||||
            break;
 | 
			
		||||
          default:
 | 
			
		||||
            serial.printf("%sInvalid toggle option '%s'.%s%s",EOLNC,cmd.c_str(),EOLNC,EOLNC);
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        lastOptions = flags.getFlagString();
 | 
			
		||||
      }
 | 
			
		||||
      showMenu=true; // re-show the menu
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    case ZIRCMENU_COMMAND:
 | 
			
		||||
    {
 | 
			
		||||
      if(c=='/')
 | 
			
		||||
      {
 | 
			
		||||
        String lccmd = cmd;
 | 
			
		||||
        lccmd.toLowerCase();
 | 
			
		||||
        if(lccmd.startsWith("/join "))
 | 
			
		||||
        {
 | 
			
		||||
          int cs=5;
 | 
			
		||||
          while((cmd.length()>cs)
 | 
			
		||||
          &&((cmd[cs]==' ')||(cmd[cs]==7)))
 | 
			
		||||
            cs++;
 | 
			
		||||
          if(cs < cmd.length())
 | 
			
		||||
          {
 | 
			
		||||
            if(channelName.length()>0 && joinReceived)
 | 
			
		||||
            {
 | 
			
		||||
              serial.println("* Already in "+channelName+": Not Yet Implemented");
 | 
			
		||||
              // we are already joined somewhere
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
              channelName = cmd.substring(cs);
 | 
			
		||||
              if(current != null)
 | 
			
		||||
                current->print("JOIN :"+channelName+"\r\n");
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
          else
 | 
			
		||||
            serial.println("* A channel name is required *");
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        if(lccmd.startsWith("/quit"))
 | 
			
		||||
        {
 | 
			
		||||
          if(current != null)
 | 
			
		||||
          {
 | 
			
		||||
            current->print("QUIT Good bye!\r\n");
 | 
			
		||||
            current->flush();
 | 
			
		||||
            delay(1000);
 | 
			
		||||
            current->markForDisconnect();
 | 
			
		||||
            delete current;
 | 
			
		||||
            current = null;
 | 
			
		||||
          }
 | 
			
		||||
          switchBackToCommandMode();
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
          serial.println("* Unknown command: "+lccmd);
 | 
			
		||||
          serial.println("* Try /?");
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      else
 | 
			
		||||
      if((current != null)
 | 
			
		||||
      &&(joinReceived))
 | 
			
		||||
        current->printf("PRIVMSG %s :%s\r\n",channelName.c_str(),cmd.c_str());
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ZIRCMode::loopMenuMode()
 | 
			
		||||
{
 | 
			
		||||
  if(showMenu)
 | 
			
		||||
  {
 | 
			
		||||
    showMenu=false;
 | 
			
		||||
    switch(currState)
 | 
			
		||||
    {
 | 
			
		||||
      case ZIRCMENU_MAIN:
 | 
			
		||||
      {
 | 
			
		||||
        if(nick.length()==0)
 | 
			
		||||
          nick = hostname;
 | 
			
		||||
        serial.printf("%sInternet Relay Chat (IRC) Main Menu%s",EOLNC,EOLNC);
 | 
			
		||||
        serial.printf("[NICK] name: %s%s",nick.c_str(),EOLNC);
 | 
			
		||||
        serial.printf("[ADD] new phonebook entry%s",EOLNC);
 | 
			
		||||
        PhoneBookEntry *p = phonebook;
 | 
			
		||||
        if(p != null)
 | 
			
		||||
        {
 | 
			
		||||
          serial.printf("Phonebook entries:%s",EOLNC);
 | 
			
		||||
          while(p != null)
 | 
			
		||||
          {
 | 
			
		||||
            if(strlen(p->notes)>0)
 | 
			
		||||
              serial.printf("  [%lu] %s (%s)%s",p->number, p->address, p->notes, EOLNC);
 | 
			
		||||
            else
 | 
			
		||||
              serial.printf("  [%lu] %s%s",p->number, p->address, EOLNC);
 | 
			
		||||
            p=p->next;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
        serial.printf("%sEnter command, number to connect to, or ENTER to exit: ",EOLNC,EOLNC);
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
      case ZIRCMENU_NUM:
 | 
			
		||||
        serial.printf("%sEnter a new fake phone number (digits ONLY)%s: ",EOLNC,EOLNC);
 | 
			
		||||
        break;
 | 
			
		||||
      case ZIRCMENU_ADDRESS:
 | 
			
		||||
      {
 | 
			
		||||
        serial.printf("%sEnter a new hostname:port%s: ",EOLNC,EOLNC);
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
      case ZIRCMENU_NICK:
 | 
			
		||||
      {
 | 
			
		||||
        serial.printf("%sEnter a new nick-name%s: ",EOLNC,EOLNC);
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
      case ZIRCMENU_OPTIONS:
 | 
			
		||||
      {
 | 
			
		||||
        ConnSettings flags(lastOptions.c_str());
 | 
			
		||||
        serial.printf("%sConnection Options:%s",EOLNC,EOLNC);
 | 
			
		||||
        serial.printf("[PETSCII] Translation: %s%s",flags.petscii?"ON":"OFF",EOLNC);
 | 
			
		||||
        serial.printf("[TELNET] Translation: %s%s",flags.telnet?"ON":"OFF",EOLNC);
 | 
			
		||||
        serial.printf("[ECHO]: %s%s",flags.echo?"ON":"OFF",EOLNC);
 | 
			
		||||
        serial.printf("[FLOW] Control: %s%s",flags.xonxoff?"XON/XOFF":flags.rtscts?"RTS/CTS":"DISABLED",EOLNC);
 | 
			
		||||
        serial.printf("%sEnter option to toggle or ENTER to exit%s: ",EOLNC,EOLNC);
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
      case ZIRCMENU_NOTES:
 | 
			
		||||
      {
 | 
			
		||||
        serial.printf("%sEnter some notes for this entry (%s)%s: ",EOLNC,lastNotes.c_str(),EOLNC);
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
      case ZIRCMENU_COMMAND:
 | 
			
		||||
      {
 | 
			
		||||
        showMenu=true; // keep coming back here, over and over and over
 | 
			
		||||
        if((current==null)||(!current->isConnected()))
 | 
			
		||||
          switchBackToCommandMode();
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            String cmd;
 | 
			
		||||
            while((current->available()>0) && (current->isConnected()))
 | 
			
		||||
            {
 | 
			
		||||
              uint8_t c = current->read();
 | 
			
		||||
              if((c == '\r')||(c == '\n')||(buf.length()>510))
 | 
			
		||||
              {
 | 
			
		||||
                  if((c=='\r')||(c=='\n'))
 | 
			
		||||
                  {
 | 
			
		||||
                    cmd=buf;
 | 
			
		||||
                    buf="";
 | 
			
		||||
                    break;
 | 
			
		||||
                  }
 | 
			
		||||
                  buf="";
 | 
			
		||||
              }
 | 
			
		||||
              else
 | 
			
		||||
                  buf += (char)c;
 | 
			
		||||
            }
 | 
			
		||||
            if(cmd.length()>0)
 | 
			
		||||
            {
 | 
			
		||||
              if(cmd.indexOf("PING :")==0)
 | 
			
		||||
              {
 | 
			
		||||
                  int x = cmd.indexOf(':');
 | 
			
		||||
                  if(x>0)
 | 
			
		||||
                    current->print("PONG "+cmd.substring(x+1)+"\r\n");
 | 
			
		||||
              }
 | 
			
		||||
              else
 | 
			
		||||
              switch(ircState)
 | 
			
		||||
              {
 | 
			
		||||
                case ZIRCSTATE_WAIT:
 | 
			
		||||
                {
 | 
			
		||||
                  if(cmd.indexOf("376")>=0)
 | 
			
		||||
                  {
 | 
			
		||||
                      ircState = ZIRCSTATE_COMMAND;
 | 
			
		||||
                      //TODO: say something?
 | 
			
		||||
                  }
 | 
			
		||||
                  else
 | 
			
		||||
                  if(cmd.indexOf("No Ident response")>=0)
 | 
			
		||||
                  {
 | 
			
		||||
                      current->print("NICK "+nick+"\r\n");
 | 
			
		||||
                      current->print("USER guest 0 * :"+nick+"\r\n");
 | 
			
		||||
                  }
 | 
			
		||||
                  else
 | 
			
		||||
                  if(cmd.indexOf("433")>=0)
 | 
			
		||||
                  {
 | 
			
		||||
                      if(nick.indexOf("_____")==0)
 | 
			
		||||
                      {
 | 
			
		||||
                          ircState = ZIRCSTATE_WAIT;
 | 
			
		||||
                          delete current;
 | 
			
		||||
                          current = null;
 | 
			
		||||
                          currState = ZIRCMENU_MAIN;
 | 
			
		||||
                      }
 | 
			
		||||
                      else
 | 
			
		||||
                      {
 | 
			
		||||
                        nick = "_" + nick;
 | 
			
		||||
                        current->print("NICK "+nick+"\r\n");
 | 
			
		||||
                        current->print("USER guest 0 * :"+nick+"\r\n");
 | 
			
		||||
                        // above was user nick * * : nick
 | 
			
		||||
                      }
 | 
			
		||||
                  }
 | 
			
		||||
                  else
 | 
			
		||||
                  if(cmd.indexOf(":")==0)
 | 
			
		||||
                  {
 | 
			
		||||
                    int x = cmd.indexOf(":",1);
 | 
			
		||||
                    if(x>1)
 | 
			
		||||
                    {
 | 
			
		||||
                      serial.prints(cmd.substring(x+1));
 | 
			
		||||
                      serial.prints(EOLNC);
 | 
			
		||||
                    }
 | 
			
		||||
                  }
 | 
			
		||||
                  break;
 | 
			
		||||
                }
 | 
			
		||||
                case ZIRCSTATE_COMMAND:
 | 
			
		||||
                {
 | 
			
		||||
                  if((!joinReceived) 
 | 
			
		||||
                  && (channelName.length()>0) 
 | 
			
		||||
                  && (cmd.indexOf("366")>=0))
 | 
			
		||||
                  {
 | 
			
		||||
                    joinReceived=true;
 | 
			
		||||
                    serial.prints("Channel joined.  Enter a message to send, or /quit.");
 | 
			
		||||
                    serial.prints(EOLNC);
 | 
			
		||||
                  }
 | 
			
		||||
                  int x0 = cmd.indexOf(":");
 | 
			
		||||
                  int x1 = (x0>=0)?cmd.indexOf(" PRIVMSG ", x0+1):-1;
 | 
			
		||||
                  x1 = (x1>0)?cmd.indexOf(":", x1+1):(x0>=0)?cmd.indexOf(":", x0+1):-1;
 | 
			
		||||
                  if(x1>0)
 | 
			
		||||
                  {
 | 
			
		||||
                    String msg2=cmd.substring(x1+1);
 | 
			
		||||
                    msg2.trim();
 | 
			
		||||
                    String msg1=cmd.substring(x0+1,x1);
 | 
			
		||||
                    msg1.trim();
 | 
			
		||||
                    int x2=msg1.indexOf("!");
 | 
			
		||||
                    if(x2>=0)
 | 
			
		||||
                      serial.print("< "+msg1.substring(0,x2)+"> "+msg2);
 | 
			
		||||
                    else
 | 
			
		||||
                      serial.prints(msg2);
 | 
			
		||||
                    serial.prints(EOLNC);
 | 
			
		||||
                  }
 | 
			
		||||
                  break;
 | 
			
		||||
                }
 | 
			
		||||
                default:
 | 
			
		||||
                  serial.prints("unknown state\n\r");
 | 
			
		||||
                  switchBackToCommandMode();
 | 
			
		||||
                  break;
 | 
			
		||||
              }
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            if(ircState == ZIRCSTATE_WAIT)
 | 
			
		||||
            {
 | 
			
		||||
              if(millis()>timeout)
 | 
			
		||||
              {
 | 
			
		||||
                timeout = millis()+60000;
 | 
			
		||||
                current->print("NICK "+nick+"\r\n");
 | 
			
		||||
                current->print("USER guest 0 * :"+nick+"\r\n");
 | 
			
		||||
              }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  if(commandMode.checkPlusEscape())
 | 
			
		||||
  {
 | 
			
		||||
    switchBackToCommandMode();
 | 
			
		||||
  }
 | 
			
		||||
  else
 | 
			
		||||
  if(serial.isSerialOut())
 | 
			
		||||
  {
 | 
			
		||||
    serialOutDeque();
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ZIRCMode::serialIncoming()
 | 
			
		||||
{
 | 
			
		||||
  bool crReceived=commandMode.readSerialStream();
 | 
			
		||||
  commandMode.clearPlusProgress(); // re-check the plus-escape mode
 | 
			
		||||
  if(crReceived)
 | 
			
		||||
  {
 | 
			
		||||
    doIRCCommand();
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ZIRCMode::loop()
 | 
			
		||||
{
 | 
			
		||||
  loopMenuMode();
 | 
			
		||||
  if(commandMode.checkPlusEscape())
 | 
			
		||||
  {
 | 
			
		||||
    switchBackToCommandMode();
 | 
			
		||||
  }
 | 
			
		||||
  else
 | 
			
		||||
  if(serial.isSerialOut())
 | 
			
		||||
  {
 | 
			
		||||
    serialOutDeque();
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif /* INCLUDE_IRCC */
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,417 @@
 | 
			
		|||
#include <Arduino.h>
 | 
			
		||||
/*
 | 
			
		||||
   Copyright 2020-2020 Bo Zimmerman
 | 
			
		||||
 | 
			
		||||
   Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
   you may not use this file except in compliance with the License.
 | 
			
		||||
   You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
     http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
   Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
   distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
   See the License for the specific language governing permissions and
 | 
			
		||||
   limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
size_t ZPrint::writeStr(char *s)
 | 
			
		||||
{
 | 
			
		||||
  if(outStream != null)
 | 
			
		||||
  {
 | 
			
		||||
    int len=strlen(s);
 | 
			
		||||
    outStream->write((uint8_t *)s,len);
 | 
			
		||||
    if(logFileOpen)
 | 
			
		||||
    {
 | 
			
		||||
      for(int i=0;i<len;i++)
 | 
			
		||||
        logSocketOut(s[i]);
 | 
			
		||||
    }
 | 
			
		||||
    return len;
 | 
			
		||||
  }
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
char *ZPrint::getLastPrinterSpec()
 | 
			
		||||
{
 | 
			
		||||
  if(lastPrinterSpec==0)
 | 
			
		||||
    return "";
 | 
			
		||||
  return lastPrinterSpec;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ZPrint::setLastPrinterSpec(const char *spec)
 | 
			
		||||
{
 | 
			
		||||
  if(lastPrinterSpec != 0)
 | 
			
		||||
    free(lastPrinterSpec);
 | 
			
		||||
  lastPrinterSpec = 0;
 | 
			
		||||
  if((spec != 0) && (*spec != 0))
 | 
			
		||||
  {
 | 
			
		||||
    int newLen = strlen(spec);
 | 
			
		||||
    lastPrinterSpec = (char *)malloc(newLen + 1);
 | 
			
		||||
    strcpy(lastPrinterSpec,spec);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
int ZPrint::getTimeoutDelayMs()
 | 
			
		||||
{
 | 
			
		||||
  return timeoutDelayMs;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ZPrint::setTimeoutDelayMs(int ms)
 | 
			
		||||
{
 | 
			
		||||
  if(ms > 50)
 | 
			
		||||
    timeoutDelayMs = ms;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
size_t ZPrint::writeChunk(char *s, int len)
 | 
			
		||||
{
 | 
			
		||||
  char buf[25];
 | 
			
		||||
  sprintf(buf,"%x\r\n",len);
 | 
			
		||||
  writeStr(buf);
 | 
			
		||||
  outStream->write((uint8_t *)s,len);
 | 
			
		||||
  if(logFileOpen)
 | 
			
		||||
  {
 | 
			
		||||
    for(int i=0;i<len;i++)
 | 
			
		||||
      logSocketOut(s[i]);
 | 
			
		||||
  }
 | 
			
		||||
  writeStr("\r\n");
 | 
			
		||||
  return len+strlen(buf)+4;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ZPrint::announcePrintJob(const char *hostIp, const int port, const char *req)
 | 
			
		||||
{
 | 
			
		||||
  logPrintfln("Print Request to host=%s, port=%d",hostIp,port);
 | 
			
		||||
  debugPrintf("Print Request to host=%s, port=%d\n",hostIp,port);
 | 
			
		||||
  logPrintfln("Print Request is /%s",req);
 | 
			
		||||
  debugPrintf("Print Request is /%s\n",req);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ZResult ZPrint::switchToPostScript(char *prefix)
 | 
			
		||||
{
 | 
			
		||||
  if((lastPrinterSpec==0)
 | 
			
		||||
  ||(strlen(lastPrinterSpec)<=5)
 | 
			
		||||
  ||(lastPrinterSpec[1]!=':'))
 | 
			
		||||
    return ZERROR;
 | 
			
		||||
  char *workBuf = (char *)malloc(strlen(lastPrinterSpec) +1);
 | 
			
		||||
  strcpy(workBuf, lastPrinterSpec);
 | 
			
		||||
  char *hostIp;
 | 
			
		||||
  char *req;
 | 
			
		||||
  int port;
 | 
			
		||||
  bool doSSL;
 | 
			
		||||
  if(!parseWebUrl((uint8_t *)workBuf+2,&hostIp,&req,&port,&doSSL))
 | 
			
		||||
  {
 | 
			
		||||
    free(workBuf);
 | 
			
		||||
    return ZERROR;
 | 
			
		||||
  }
 | 
			
		||||
  payloadType = RAW;
 | 
			
		||||
  announcePrintJob(hostIp,port,req);
 | 
			
		||||
  ZResult result;
 | 
			
		||||
  if(pinSupport[pinRTS])
 | 
			
		||||
    s_pinWrite(pinRTS, rtsInactive);
 | 
			
		||||
  yield();
 | 
			
		||||
  wifiSock = new WiFiClientNode(hostIp,port,doSSL?FLAG_SECURE:0);
 | 
			
		||||
  wifiSock->setNoDelay(false); // we want a delay in this case
 | 
			
		||||
  outStream = wifiSock;
 | 
			
		||||
  result = finishSwitchTo(hostIp, req, port, doSSL);
 | 
			
		||||
  if(result == ZERROR)
 | 
			
		||||
  {
 | 
			
		||||
    outStream = null;
 | 
			
		||||
    delete wifiSock;
 | 
			
		||||
    wifiSock = null;
 | 
			
		||||
  }
 | 
			
		||||
  yield();
 | 
			
		||||
  if(pinSupport[pinRTS])
 | 
			
		||||
    s_pinWrite(pinRTS, rtsActive);
 | 
			
		||||
  if((result != ZERROR)
 | 
			
		||||
  &&(prefix != 0)
 | 
			
		||||
  &&(strlen(prefix)>0))
 | 
			
		||||
  {
 | 
			
		||||
    writeChunk(prefix,strlen(prefix));
 | 
			
		||||
    serialIncoming();
 | 
			
		||||
  }
 | 
			
		||||
  free(workBuf);
 | 
			
		||||
  return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool ZPrint::testPrinterSpec(const char *vbuf, int vlen, bool petscii)
 | 
			
		||||
{
 | 
			
		||||
  char *workBuf = (char *)malloc(vlen+1);
 | 
			
		||||
  strcpy(workBuf, vbuf);
 | 
			
		||||
  if(petscii)
 | 
			
		||||
  {
 | 
			
		||||
    for(int i=0;i<vlen;i++)
 | 
			
		||||
      workBuf[i] = petToAsc(workBuf[i]);
 | 
			
		||||
  }
 | 
			
		||||
  if((vlen <= 2)||(workBuf[1]!=':'))
 | 
			
		||||
  {
 | 
			
		||||
    free(workBuf);
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  switch(workBuf[0])
 | 
			
		||||
  {
 | 
			
		||||
  case 'P': case 'p': 
 | 
			
		||||
  case 'A': case 'a': 
 | 
			
		||||
  case 'R': case 'r': 
 | 
			
		||||
    //yay
 | 
			
		||||
    break;
 | 
			
		||||
  default:
 | 
			
		||||
    free(workBuf);
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
  char *hostIp;
 | 
			
		||||
  char *req;
 | 
			
		||||
  int port;
 | 
			
		||||
  bool doSSL;
 | 
			
		||||
  if(!parseWebUrl((uint8_t *)workBuf+2,&hostIp,&req,&port,&doSSL))
 | 
			
		||||
  {
 | 
			
		||||
    free(workBuf);
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
  free(workBuf);
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ZResult ZPrint::switchTo(char *vbuf, int vlen, bool petscii)
 | 
			
		||||
{
 | 
			
		||||
  char *workBuf = (char *)malloc(vlen+1);
 | 
			
		||||
  strcpy(workBuf, vbuf);
 | 
			
		||||
  if(petscii)
 | 
			
		||||
  {
 | 
			
		||||
    for(int i=0;i<vlen;i++)
 | 
			
		||||
      workBuf[i] = petToAsc(workBuf[i]);
 | 
			
		||||
  }
 | 
			
		||||
  bool newUrl = true;
 | 
			
		||||
  if((vlen <= 2)||(workBuf[1]!=':'))
 | 
			
		||||
  {
 | 
			
		||||
    if((lastPrinterSpec==0)
 | 
			
		||||
    ||(strlen(lastPrinterSpec)<=5)
 | 
			
		||||
    ||(lastPrinterSpec[1]!=':'))
 | 
			
		||||
    {
 | 
			
		||||
      free(workBuf);
 | 
			
		||||
      return ZERROR;
 | 
			
		||||
    }
 | 
			
		||||
    if((vlen == 1)
 | 
			
		||||
    &&(strchr("parPAR",workBuf[0])!=0))
 | 
			
		||||
      lastPrinterSpec[0]=workBuf[0];
 | 
			
		||||
    free(workBuf);
 | 
			
		||||
    workBuf = (char *)malloc(strlen(lastPrinterSpec) +1);
 | 
			
		||||
    strcpy(workBuf, lastPrinterSpec);
 | 
			
		||||
    vlen=strlen(workBuf);
 | 
			
		||||
    newUrl = false;
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  switch(workBuf[0])
 | 
			
		||||
  {
 | 
			
		||||
  case 'P': case 'p': 
 | 
			
		||||
    payloadType = PETSCII;
 | 
			
		||||
    break;
 | 
			
		||||
  case 'A': case 'a': 
 | 
			
		||||
    payloadType = ASCII;
 | 
			
		||||
    break;
 | 
			
		||||
  case 'R': case 'r': 
 | 
			
		||||
    payloadType = RAW;
 | 
			
		||||
    break;
 | 
			
		||||
  default:
 | 
			
		||||
    free(workBuf);
 | 
			
		||||
    return ZERROR;
 | 
			
		||||
  }
 | 
			
		||||
  char *hostIp;
 | 
			
		||||
  char *req;
 | 
			
		||||
  int port;
 | 
			
		||||
  bool doSSL;
 | 
			
		||||
  if(!parseWebUrl((uint8_t *)workBuf+2,&hostIp,&req,&port,&doSSL))
 | 
			
		||||
  {
 | 
			
		||||
    free(workBuf);
 | 
			
		||||
    return ZERROR;
 | 
			
		||||
  }
 | 
			
		||||
  if(newUrl)
 | 
			
		||||
    setLastPrinterSpec(vbuf);
 | 
			
		||||
 | 
			
		||||
  wifiSock = new WiFiClientNode(hostIp,port,doSSL?FLAG_SECURE:0);
 | 
			
		||||
  wifiSock->setNoDelay(false); // we want a delay in this case
 | 
			
		||||
  outStream = wifiSock;
 | 
			
		||||
  announcePrintJob(hostIp,port,req);
 | 
			
		||||
  ZResult result = finishSwitchTo(hostIp, req, port, doSSL);
 | 
			
		||||
  free(workBuf);
 | 
			
		||||
  if(result == ZERROR)
 | 
			
		||||
    delete wifiSock;
 | 
			
		||||
  return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ZResult ZPrint::finishSwitchTo(char *hostIp, char *req, int port, bool doSSL)
 | 
			
		||||
{
 | 
			
		||||
  if((wifiSock != null) && (!wifiSock->isConnected()))
 | 
			
		||||
    return ZERROR;
 | 
			
		||||
  char portStr[10];
 | 
			
		||||
  sprintf(portStr,"%d",port);
 | 
			
		||||
  // send the request and http headers:
 | 
			
		||||
  sprintf(pbuf,"POST /%s HTTP/1.1\r\n",req);
 | 
			
		||||
  writeStr(pbuf);
 | 
			
		||||
  writeStr("Transfer-Encoding: chunked\r\n");
 | 
			
		||||
  writeStr("Content-Type: application/ipp\r\n");
 | 
			
		||||
  sprintf(pbuf,"Host: %s:%d\r\n",hostIp,port);
 | 
			
		||||
  writeStr(pbuf);
 | 
			
		||||
  writeStr("Connection: Keep-Alive\r\n");
 | 
			
		||||
  writeStr("User-Agent: Zimodem\r\n");
 | 
			
		||||
  writeStr("Accept-Encoding: gzip,deflate\r\n");
 | 
			
		||||
  writeStr("\r\n");
 | 
			
		||||
  outStream->flush();
 | 
			
		||||
  // send the ipp header
 | 
			
		||||
  if((wifiSock != null)&&(!wifiSock->isConnected()))
 | 
			
		||||
    return ZERROR;
 | 
			
		||||
  
 | 
			
		||||
  char jobChar1 = '0' + (jobNum / 10);
 | 
			
		||||
  char jobChar2 = '0' + (jobNum % 10);
 | 
			
		||||
  if(++jobNum>94)
 | 
			
		||||
    jobNum=0;
 | 
			
		||||
  //                                version  operatid  reqid------------------ attribtabid
 | 
			
		||||
  sprintf(pbuf,"%c%c%c%c%c%c%c%c%c",0x01,0x01,0x00,0x02,0x00,0x00,0x00,jobNum+1,0x01);
 | 
			
		||||
  writeChunk(pbuf,9);
 | 
			
		||||
  sprintf(pbuf,"%c%c%cattributes-charset%c%cutf-8",0x47,0x00,0x12,0x00,0x05);
 | 
			
		||||
  writeChunk(pbuf,28);
 | 
			
		||||
  sprintf(pbuf,"%c%c%cattributes-natural-language%c%cen-us",0x48,0x00,0x1b,0x00,0x05);
 | 
			
		||||
  writeChunk(pbuf,37);
 | 
			
		||||
  
 | 
			
		||||
  int urllen = strlen(hostIp) + strlen(req)+ strlen(portStr)+9;
 | 
			
		||||
  sprintf(pbuf,"%c%c%cprinter-uri%c%chttp://%s:%s/%s",0x45,0x00,0x0b,0x00,urllen,hostIp,portStr,req);
 | 
			
		||||
  writeChunk(pbuf,urllen+16);
 | 
			
		||||
  sprintf(pbuf,"%c%c%crequesting-user-name%c%czimodem",0x42,0x00,0x14,0x00,0x07);
 | 
			
		||||
  writeChunk(pbuf,32);
 | 
			
		||||
  sprintf(pbuf,"%c%c%cjob-name%c%czimodem-j%c%c",0x42,0x00,0x08,0x00,0x0b,jobChar1,jobChar2);
 | 
			
		||||
  writeChunk(pbuf,24);
 | 
			
		||||
  sprintf(pbuf,"%c%c%c%ccopies%c%c%c%c%c%c",0x02,0x21,0x00,0x06,0x00,0x04,0x00,0x00,0x00,0x01);
 | 
			
		||||
  writeChunk(pbuf,16);
 | 
			
		||||
  sprintf(pbuf,"%c%c%corientation-requested%c%c%c%c%c%c",0x23,0x00,0x15,0x00,0x04,0x00,0x00,0x00,0x03);
 | 
			
		||||
  writeChunk(pbuf,30);
 | 
			
		||||
  sprintf(pbuf,"%c%c%coutput-mode%c%cmonochrome%c",0x44,0x00,0x0b,0x00,0x0a,     0x03);
 | 
			
		||||
  writeChunk(pbuf,27);
 | 
			
		||||
  outStream->flush();
 | 
			
		||||
  if((wifiSock != null)&&(!wifiSock->isConnected()))
 | 
			
		||||
    return ZERROR;
 | 
			
		||||
  checkOpenConnections();
 | 
			
		||||
  checkBaudChange();
 | 
			
		||||
  pdex=0;
 | 
			
		||||
  coldex=0;
 | 
			
		||||
  lastNonPlusTimeMs = 0;
 | 
			
		||||
  plussesInARow=0;
 | 
			
		||||
  currentExpiresTimeMs = millis()+5000;
 | 
			
		||||
  currMode=&printMode;
 | 
			
		||||
  return ZIGNORE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ZPrint::serialIncoming()
 | 
			
		||||
{
 | 
			
		||||
  if(HWSerial.available() > 0)
 | 
			
		||||
  {
 | 
			
		||||
    while(HWSerial.available() > 0)
 | 
			
		||||
    {
 | 
			
		||||
      uint8_t c=HWSerial.read();
 | 
			
		||||
      logSerialIn(c);
 | 
			
		||||
      if((c==commandMode.EC)
 | 
			
		||||
      &&(plussesInARow<3)
 | 
			
		||||
      &&((plussesInARow>0)||((millis()-lastNonPlusTimeMs)>900)))
 | 
			
		||||
      {
 | 
			
		||||
        plussesInARow++;
 | 
			
		||||
        continue;
 | 
			
		||||
      }
 | 
			
		||||
      else
 | 
			
		||||
      {
 | 
			
		||||
        if(plussesInARow > 0)
 | 
			
		||||
        {
 | 
			
		||||
          for(int i=0;i<plussesInARow;i++)
 | 
			
		||||
            pbuf[pdex++]=commandMode.EC;
 | 
			
		||||
          plussesInARow=0;
 | 
			
		||||
        }
 | 
			
		||||
        lastNonPlusTimeMs=millis();
 | 
			
		||||
      }
 | 
			
		||||
      
 | 
			
		||||
      if(payloadType == PETSCII)
 | 
			
		||||
        c=petToAsc(c);
 | 
			
		||||
      if(payloadType != RAW)
 | 
			
		||||
      {
 | 
			
		||||
        if(c==0)
 | 
			
		||||
          continue;
 | 
			
		||||
        else
 | 
			
		||||
        if(c<32)
 | 
			
		||||
        {
 | 
			
		||||
          if((c=='\r')||(c=='\n'))
 | 
			
		||||
          {
 | 
			
		||||
            coldex=0;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
          coldex++;
 | 
			
		||||
          if(coldex > 80)
 | 
			
		||||
          {
 | 
			
		||||
            pbuf[pdex++]='\n';
 | 
			
		||||
            pbuf[pdex++]='\r';
 | 
			
		||||
            coldex=1;
 | 
			
		||||
          }
 | 
			
		||||
          else
 | 
			
		||||
          if((lastC == '\n')&&(lastLastC!='\r'))
 | 
			
		||||
              pbuf[pdex++]='\r';
 | 
			
		||||
          else
 | 
			
		||||
          if((lastC == '\r')&&(lastLastC!='\n'))
 | 
			
		||||
              pbuf[pdex++]='\n';
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      pbuf[pdex++]=(char)c;
 | 
			
		||||
      lastLastC=lastC;
 | 
			
		||||
      lastC=c;
 | 
			
		||||
      if(pdex>=250)
 | 
			
		||||
      {
 | 
			
		||||
        if(((wifiSock!=null)&&(wifiSock->isConnected()))
 | 
			
		||||
        ||((wifiSock==null)&&(outStream!=null)))
 | 
			
		||||
        {
 | 
			
		||||
          writeChunk(pbuf,pdex);
 | 
			
		||||
          //wifiSock->flush();
 | 
			
		||||
        }
 | 
			
		||||
        pdex=0;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    if(plussesInARow == 3)
 | 
			
		||||
      currentExpiresTimeMs = millis()+900;
 | 
			
		||||
    else
 | 
			
		||||
      currentExpiresTimeMs = millis()+timeoutDelayMs;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ZPrint::switchBackToCommandMode(bool error)
 | 
			
		||||
{
 | 
			
		||||
  if((wifiSock != null)||(outStream!=null))
 | 
			
		||||
  {
 | 
			
		||||
    if(error)
 | 
			
		||||
      commandMode.sendOfficialResponse(ZERROR);
 | 
			
		||||
    else
 | 
			
		||||
      commandMode.sendOfficialResponse(ZOK);
 | 
			
		||||
    if(wifiSock != null)
 | 
			
		||||
      delete wifiSock;
 | 
			
		||||
  }
 | 
			
		||||
  wifiSock = null;
 | 
			
		||||
  outStream = null;
 | 
			
		||||
  currMode = &commandMode;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ZPrint::loop()
 | 
			
		||||
{
 | 
			
		||||
  if(((wifiSock==null)&&(outStream==null))
 | 
			
		||||
  || ((wifiSock!=null)&&(!wifiSock->isConnected())))
 | 
			
		||||
  {
 | 
			
		||||
    debugPrintf("No printer connection\n");
 | 
			
		||||
    switchBackToCommandMode(true);
 | 
			
		||||
  }
 | 
			
		||||
  else
 | 
			
		||||
  if(millis()>currentExpiresTimeMs)
 | 
			
		||||
  {
 | 
			
		||||
    debugPrintf("Time-out in printing\n");
 | 
			
		||||
    if(pdex > 0)
 | 
			
		||||
      writeChunk(pbuf,pdex);
 | 
			
		||||
    writeStr("0\r\n\r\n");
 | 
			
		||||
    outStream->flush();
 | 
			
		||||
    switchBackToCommandMode(false);
 | 
			
		||||
  }
 | 
			
		||||
  checkBaudChange();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,176 @@
 | 
			
		|||
#include <Arduino.h>
 | 
			
		||||
/*
 | 
			
		||||
 * zslipmode.ino
 | 
			
		||||
 *
 | 
			
		||||
 *  Created on: May 17, 2022
 | 
			
		||||
 *      Author: Bo Zimmerman
 | 
			
		||||
 */
 | 
			
		||||
#ifdef INCLUDE_SLIP
 | 
			
		||||
 | 
			
		||||
void ZSLIPMode::switchBackToCommandMode()
 | 
			
		||||
{
 | 
			
		||||
  currMode = &commandMode;
 | 
			
		||||
  //TODO: UNDO THIS:   raw_recv(_pcb, &_raw_recv, (void *) _pcb);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ZSLIPMode::switchTo()
 | 
			
		||||
{
 | 
			
		||||
  uint8_t num_slip1 = 0;
 | 
			
		||||
  struct netif slipif1;
 | 
			
		||||
  ip4_addr_t ipaddr_slip1, netmask_slip1, gw_slip1;
 | 
			
		||||
  //LWIP_PORT_INIT_SLIP1_IPADDR(&ipaddr_slip1);
 | 
			
		||||
  //LWIP_PORT_INIT_SLIP1_GW(&gw_slip1);
 | 
			
		||||
  //LWIP_PORT_INIT_SLIP1_NETMASK(&netmask_slip1);
 | 
			
		||||
  //printf("Starting lwIP slipif, local interface IP is %s\n", ip4addr_ntoa(&ipaddr_slip1));
 | 
			
		||||
 | 
			
		||||
  netif_add(&slipif1, &ipaddr_slip1, &netmask_slip1, &gw_slip1, &num_slip1, slipif_init, ip_input);
 | 
			
		||||
 | 
			
		||||
  sserial.setFlowControlType(FCT_DISABLED);
 | 
			
		||||
  if(commandMode.getFlowControlType()==FCT_RTSCTS)
 | 
			
		||||
    sserial.setFlowControlType(FCT_RTSCTS);
 | 
			
		||||
  sserial.setPetsciiMode(false);
 | 
			
		||||
  sserial.setXON(true);
 | 
			
		||||
 | 
			
		||||
  inPacket="";
 | 
			
		||||
  started=false;
 | 
			
		||||
  escaped=false;
 | 
			
		||||
  if(_pcb == 0)
 | 
			
		||||
  {
 | 
			
		||||
    _pcb = raw_new(IP_PROTO_TCP);
 | 
			
		||||
    if(!_pcb){
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  //_lock = xSemaphoreCreateMutex();
 | 
			
		||||
  raw_recv(_pcb, &_raw_recv, (void *) _pcb);
 | 
			
		||||
  currMode=&slipMode;
 | 
			
		||||
  debugPrintf("Switched to SLIP mode\n\r");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static String encodeSLIP(uint8_t *ipPacket, int ipLen)
 | 
			
		||||
{
 | 
			
		||||
  String slip;
 | 
			
		||||
  slip += ZSLIPMode::SLIP_END;
 | 
			
		||||
  for(int i=0;i<ipLen;i++)
 | 
			
		||||
  {
 | 
			
		||||
    if(ipPacket[i] == ZSLIPMode::SLIP_END)
 | 
			
		||||
        slip += ZSLIPMode::SLIP_ESC + ZSLIPMode::SLIP_ESC_END;
 | 
			
		||||
    else
 | 
			
		||||
    if(ipPacket[i] == ZSLIPMode::SLIP_ESC)
 | 
			
		||||
        slip += ZSLIPMode::SLIP_ESC + ZSLIPMode::SLIP_ESC_ESC;
 | 
			
		||||
    else
 | 
			
		||||
      slip += ipPacket[i];
 | 
			
		||||
  }
 | 
			
		||||
  slip += ZSLIPMode::SLIP_END;
 | 
			
		||||
  return slip;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static uint8_t _raw_recv(void *arg, raw_pcb *pcb, pbuf *pb, const ip_addr_t *addr)
 | 
			
		||||
{
 | 
			
		||||
  while(pb != NULL)
 | 
			
		||||
  {
 | 
			
		||||
    pbuf * this_pb = pb;
 | 
			
		||||
    pb = pb->next;
 | 
			
		||||
    this_pb->next = NULL;
 | 
			
		||||
    for(int i=0;i<this_pb->len;i+=4)
 | 
			
		||||
    {
 | 
			
		||||
      String pkt = encodeSLIP((uint8_t *)this_pb->payload, this_pb->len);
 | 
			
		||||
      int plen = pkt.length();
 | 
			
		||||
      if(plen > 0)
 | 
			
		||||
      {
 | 
			
		||||
        if(logFileOpen)
 | 
			
		||||
          logPrintln("SLIP-in packet:");
 | 
			
		||||
        uint8_t *buf = (uint8_t *)pkt.c_str();
 | 
			
		||||
        for(int p=0;p<plen;p++)
 | 
			
		||||
        {
 | 
			
		||||
          if(logFileOpen)
 | 
			
		||||
            logSocketIn(buf[p]);
 | 
			
		||||
          sserial.printb(buf[p]);
 | 
			
		||||
          if(sserial.isSerialOut())
 | 
			
		||||
            serialOutDeque();
 | 
			
		||||
        }
 | 
			
		||||
        if(sserial.isSerialOut())
 | 
			
		||||
          serialOutDeque();
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    //pbuf_free(this_pb); // at this point, there are no refs, so errs out.
 | 
			
		||||
  }
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ZSLIPMode::serialIncoming()
 | 
			
		||||
{
 | 
			
		||||
  while(HWSerial.available()>0)
 | 
			
		||||
  {
 | 
			
		||||
    uint8_t c = HWSerial.read();
 | 
			
		||||
    if(logFileOpen)
 | 
			
		||||
      logSerialIn(c);
 | 
			
		||||
    if (c == SLIP_END)
 | 
			
		||||
    {
 | 
			
		||||
      if(started)
 | 
			
		||||
      {
 | 
			
		||||
        if(inPacket.length()>0)
 | 
			
		||||
        {
 | 
			
		||||
          if(logFileOpen)
 | 
			
		||||
            logPrintln("SLIP-out packet.");
 | 
			
		||||
          struct pbuf p = { 0 };
 | 
			
		||||
          p.next = NULL;
 | 
			
		||||
          p.payload = (void *)inPacket.c_str();
 | 
			
		||||
          p.len = inPacket.length();
 | 
			
		||||
          p.tot_len = inPacket.length();
 | 
			
		||||
          raw_send(_pcb, &p);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      else
 | 
			
		||||
        started=true;
 | 
			
		||||
      inPacket="";
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    if(c == SLIP_ESC)
 | 
			
		||||
      escaped=true;
 | 
			
		||||
    else
 | 
			
		||||
    if(c == SLIP_ESC_END)
 | 
			
		||||
    {
 | 
			
		||||
      if(escaped)
 | 
			
		||||
      {
 | 
			
		||||
        inPacket += SLIP_END;
 | 
			
		||||
        escaped = false;
 | 
			
		||||
      }
 | 
			
		||||
      else
 | 
			
		||||
        inPacket += c;
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    if(c == SLIP_ESC_ESC)
 | 
			
		||||
    {
 | 
			
		||||
      if(escaped)
 | 
			
		||||
      {
 | 
			
		||||
        inPacket += SLIP_ESC;
 | 
			
		||||
        escaped=false;
 | 
			
		||||
      }
 | 
			
		||||
      else
 | 
			
		||||
        inPacket += c;
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    if(escaped)
 | 
			
		||||
    {
 | 
			
		||||
      debugPrintf("SLIP Protocol Error\n");
 | 
			
		||||
      if(logFileOpen)
 | 
			
		||||
        logPrintln("SLIP error.");
 | 
			
		||||
      inPacket="";
 | 
			
		||||
      escaped=false;
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
      inPacket += c;
 | 
			
		||||
      started=true;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ZSLIPMode::loop()
 | 
			
		||||
{
 | 
			
		||||
  if(sserial.isSerialOut())
 | 
			
		||||
    serialOutDeque();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif /* INCLUDE_SLIP_ */
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,316 @@
 | 
			
		|||
/*
 | 
			
		||||
   Copyright 2016-2019 Bo Zimmerman
 | 
			
		||||
 | 
			
		||||
   Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
   you may not use this file except in compliance with the License.
 | 
			
		||||
   You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
	   http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
   Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
   distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
   See the License for the specific language governing permissions and
 | 
			
		||||
   limitations under the License.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
void ZStream::switchTo(WiFiClientNode *conn)
 | 
			
		||||
{
 | 
			
		||||
  current = conn;
 | 
			
		||||
  currentExpiresTimeMs = 0;
 | 
			
		||||
  lastNonPlusTimeMs = 0;
 | 
			
		||||
  plussesInARow=0;
 | 
			
		||||
  serial.setXON(true);
 | 
			
		||||
  serial.setPetsciiMode(isPETSCII());
 | 
			
		||||
  serial.setFlowControlType(getFlowControl());
 | 
			
		||||
  currMode=&streamMode;
 | 
			
		||||
  checkBaudChange();
 | 
			
		||||
  if(pinSupport[pinDTR])
 | 
			
		||||
    lastDTR = digitalRead(pinDTR);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool ZStream::isPETSCII()
 | 
			
		||||
{
 | 
			
		||||
  return (current != null) && (current->isPETSCII());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool ZStream::isEcho()
 | 
			
		||||
{
 | 
			
		||||
  return (current != null) && (current->isEcho());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
FlowControlType ZStream::getFlowControl()
 | 
			
		||||
{
 | 
			
		||||
  return (current != null) ? (current->getFlowControl()) : FCT_DISABLED;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool ZStream::isTelnet()
 | 
			
		||||
{
 | 
			
		||||
  return (current != null) && (current->isTelnet());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool ZStream::isDisconnectedOnStreamExit()
 | 
			
		||||
{
 | 
			
		||||
  return (current != null) && (current->isDisconnectedOnStreamExit());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ZStream::baudDelay()
 | 
			
		||||
{
 | 
			
		||||
  if(baudRate<1200)
 | 
			
		||||
    delay(5);
 | 
			
		||||
  else
 | 
			
		||||
  if(baudRate==1200)
 | 
			
		||||
    delay(3);
 | 
			
		||||
  else
 | 
			
		||||
    delay(1);
 | 
			
		||||
  yield();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ZStream::serialIncoming()
 | 
			
		||||
{
 | 
			
		||||
  int bytesAvailable = HWSerial.available();
 | 
			
		||||
  if(bytesAvailable == 0)
 | 
			
		||||
    return;
 | 
			
		||||
  uint8_t escBufDex = 0;
 | 
			
		||||
  while(--bytesAvailable >= 0)
 | 
			
		||||
  {
 | 
			
		||||
    uint8_t c=HWSerial.read();
 | 
			
		||||
    if(((c==27)||(escBufDex>0))
 | 
			
		||||
    &&(!isPETSCII()))
 | 
			
		||||
    {
 | 
			
		||||
      escBuf[escBufDex++] = c;
 | 
			
		||||
      if(((c>='a')&&(c<='z'))
 | 
			
		||||
      ||((c>='A')&&(c<='Z'))
 | 
			
		||||
      ||(escBufDex>=ZSTREAM_ESC_BUF_MAX)
 | 
			
		||||
      ||((escBufDex==2)&&(c!='[')))
 | 
			
		||||
      {
 | 
			
		||||
        logSerialIn(c);
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
      if(bytesAvailable==0)
 | 
			
		||||
      {
 | 
			
		||||
        baudDelay();
 | 
			
		||||
        bytesAvailable=HWSerial.available();
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    logSerialIn(c);
 | 
			
		||||
    if((c==commandMode.EC)
 | 
			
		||||
    &&((plussesInARow>0)||((millis()-lastNonPlusTimeMs)>800)))
 | 
			
		||||
      plussesInARow++;
 | 
			
		||||
    else
 | 
			
		||||
    if(c!=commandMode.EC)
 | 
			
		||||
    {
 | 
			
		||||
      plussesInARow=0;
 | 
			
		||||
      lastNonPlusTimeMs=millis();
 | 
			
		||||
    }
 | 
			
		||||
    if((c==19)&&(getFlowControl()==FCT_NORMAL))
 | 
			
		||||
      serial.setXON(false);
 | 
			
		||||
    else
 | 
			
		||||
    if((c==17)&&(getFlowControl()==FCT_NORMAL))
 | 
			
		||||
      serial.setXON(true);
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
      if(isEcho())
 | 
			
		||||
        serial.printb(c);
 | 
			
		||||
      if(isPETSCII())
 | 
			
		||||
        c = petToAsc(c);
 | 
			
		||||
      if(escBufDex==0)
 | 
			
		||||
        socketWrite(c);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if(escBufDex>0)
 | 
			
		||||
    socketWrite(escBuf,escBufDex);
 | 
			
		||||
  currentExpiresTimeMs = 0;
 | 
			
		||||
  if(plussesInARow==3)
 | 
			
		||||
    currentExpiresTimeMs=millis()+800;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ZStream::switchBackToCommandMode(bool logout)
 | 
			
		||||
{
 | 
			
		||||
  if(logout && (current != null) && isDisconnectedOnStreamExit())
 | 
			
		||||
  {
 | 
			
		||||
    if(!commandMode.suppressResponses)
 | 
			
		||||
    {
 | 
			
		||||
      if(commandMode.numericResponses)
 | 
			
		||||
      {
 | 
			
		||||
        preEOLN(commandMode.EOLN);
 | 
			
		||||
        serial.prints("3");
 | 
			
		||||
        serial.prints(commandMode.EOLN);
 | 
			
		||||
      }
 | 
			
		||||
      else
 | 
			
		||||
      if(current->isAnswered())
 | 
			
		||||
      {
 | 
			
		||||
        preEOLN(commandMode.EOLN);
 | 
			
		||||
        serial.prints("NO CARRIER");
 | 
			
		||||
        serial.prints(commandMode.EOLN);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    delete current;
 | 
			
		||||
  }
 | 
			
		||||
  current = null;
 | 
			
		||||
  currMode = &commandMode;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ZStream::socketWrite(uint8_t *buf, uint8_t len)
 | 
			
		||||
{
 | 
			
		||||
  if(current->isConnected())
 | 
			
		||||
  {
 | 
			
		||||
    uint8_t escapedBuf[len*2];
 | 
			
		||||
    if(isTelnet())
 | 
			
		||||
    {
 | 
			
		||||
      int eDex=0;
 | 
			
		||||
      for(int i=0;i<len;i++)
 | 
			
		||||
      {
 | 
			
		||||
          escapedBuf[eDex++] = buf[i];
 | 
			
		||||
          if(buf[i]==0xff)
 | 
			
		||||
            escapedBuf[eDex++] = buf[i];
 | 
			
		||||
      }
 | 
			
		||||
      buf=escapedBuf;
 | 
			
		||||
      len=eDex;
 | 
			
		||||
    }
 | 
			
		||||
    for(int i=0;i<len;i++)
 | 
			
		||||
      logSocketOut(buf[i]);
 | 
			
		||||
    current->write(buf,len);
 | 
			
		||||
    nextFlushMs=millis()+250;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ZStream::socketWrite(uint8_t c)
 | 
			
		||||
{
 | 
			
		||||
  if(current->isConnected())
 | 
			
		||||
  {
 | 
			
		||||
    if(c == 0xFF && isTelnet()) 
 | 
			
		||||
      current->write(c);
 | 
			
		||||
    current->write(c);
 | 
			
		||||
    logSocketOut(c);
 | 
			
		||||
    nextFlushMs=millis()+250;
 | 
			
		||||
    //current->flush(); // rendered safe by available check
 | 
			
		||||
    //delay(0);
 | 
			
		||||
    //yield();
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ZStream::loop()
 | 
			
		||||
{
 | 
			
		||||
  WiFiServerNode *serv = servs;
 | 
			
		||||
  while(serv != null)
 | 
			
		||||
  {
 | 
			
		||||
    if(serv->hasClient())
 | 
			
		||||
    {
 | 
			
		||||
      WiFiClient newClient = serv->server->available();
 | 
			
		||||
      if(newClient.connected())
 | 
			
		||||
      {
 | 
			
		||||
        int port=newClient.localPort();
 | 
			
		||||
        String remoteIPStr = newClient.remoteIP().toString();
 | 
			
		||||
        const char *remoteIP=remoteIPStr.c_str();
 | 
			
		||||
        bool found=false;
 | 
			
		||||
        WiFiClientNode *c=conns;
 | 
			
		||||
        while(c!=null)
 | 
			
		||||
        {
 | 
			
		||||
          if((c->isConnected())
 | 
			
		||||
          &&(c->port==port)
 | 
			
		||||
          &&(strcmp(remoteIP,c->host)==0))
 | 
			
		||||
            found=true;
 | 
			
		||||
          c=c->next;
 | 
			
		||||
        }
 | 
			
		||||
        if(!found)
 | 
			
		||||
          new WiFiClientNode(newClient, serv->flagsBitmap, 5); // constructing is enough
 | 
			
		||||
        // else // auto disconnect when from same 
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    serv=serv->next;
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  WiFiClientNode *conn = conns;
 | 
			
		||||
  unsigned long now=millis();
 | 
			
		||||
  while(conn != null)
 | 
			
		||||
  {
 | 
			
		||||
    WiFiClientNode *nextConn = conn->next;
 | 
			
		||||
    if((!conn->isAnswered())
 | 
			
		||||
    &&(conn->isConnected())
 | 
			
		||||
    &&(conn!=current)
 | 
			
		||||
    &&(!conn->isMarkedForDisconnect()))
 | 
			
		||||
    {
 | 
			
		||||
      conn->write((uint8_t *)busyMsg.c_str(), busyMsg.length());
 | 
			
		||||
      conn->flushAlways();
 | 
			
		||||
      conn->markForDisconnect();
 | 
			
		||||
    }
 | 
			
		||||
    conn = nextConn;
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  WiFiClientNode::checkForAutoDisconnections();
 | 
			
		||||
  
 | 
			
		||||
  if(pinSupport[pinDTR])
 | 
			
		||||
  {
 | 
			
		||||
    if(lastDTR==dtrActive)
 | 
			
		||||
    {
 | 
			
		||||
      lastDTR = digitalRead(pinDTR);
 | 
			
		||||
      if((lastDTR==dtrInactive)
 | 
			
		||||
      &&(dtrInactive != dtrActive))
 | 
			
		||||
      {
 | 
			
		||||
        if(current != null)
 | 
			
		||||
          current->setDisconnectOnStreamExit(true);
 | 
			
		||||
        switchBackToCommandMode(true);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    lastDTR = digitalRead(pinDTR);
 | 
			
		||||
  }
 | 
			
		||||
  if((current==null)||(!current->isConnected()))
 | 
			
		||||
  {
 | 
			
		||||
    switchBackToCommandMode(true);
 | 
			
		||||
  }
 | 
			
		||||
  else
 | 
			
		||||
  if((currentExpiresTimeMs > 0) && (millis() > currentExpiresTimeMs))
 | 
			
		||||
  {
 | 
			
		||||
    currentExpiresTimeMs = 0;
 | 
			
		||||
    if(plussesInARow == 3)
 | 
			
		||||
    {
 | 
			
		||||
      plussesInARow=0;
 | 
			
		||||
      if(current != 0)
 | 
			
		||||
      {
 | 
			
		||||
        commandMode.sendOfficialResponse(ZOK);
 | 
			
		||||
        switchBackToCommandMode(false);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  else
 | 
			
		||||
  if(serial.isSerialOut())
 | 
			
		||||
  {
 | 
			
		||||
    if(current->available()>0)
 | 
			
		||||
    //&&(current->isConnected()) // not a requirement to have available bytes to read
 | 
			
		||||
    {
 | 
			
		||||
      int bufferRemaining=serialOutBufferBytesRemaining();
 | 
			
		||||
      if(bufferRemaining > 0)
 | 
			
		||||
      {
 | 
			
		||||
        int bytesAvailable = current->available();
 | 
			
		||||
        if(bytesAvailable > bufferRemaining)
 | 
			
		||||
          bytesAvailable = bufferRemaining;
 | 
			
		||||
        if(bytesAvailable>0)
 | 
			
		||||
        {
 | 
			
		||||
          for(int i=0;(i<bytesAvailable) && (current->available()>0);i++)
 | 
			
		||||
          {
 | 
			
		||||
            if(serial.isSerialCancelled())
 | 
			
		||||
              break;
 | 
			
		||||
            uint8_t c=current->read();
 | 
			
		||||
            logSocketIn(c);
 | 
			
		||||
            if((!isTelnet() || handleAsciiIAC((char *)&c,current))
 | 
			
		||||
            && (!isPETSCII() || ascToPet((char *)&c,current)))
 | 
			
		||||
              serial.printb(c);
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    if(serial.isSerialOut())
 | 
			
		||||
    {
 | 
			
		||||
      if((nextFlushMs > 0) && (millis() > nextFlushMs))
 | 
			
		||||
      {
 | 
			
		||||
        nextFlushMs = 0;
 | 
			
		||||
        serial.flush();
 | 
			
		||||
      }
 | 
			
		||||
      serialOutDeque();
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  checkBaudChange();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,11 @@
 | 
			
		|||
 | 
			
		||||
This directory is intended for PlatformIO Test Runner and project tests.
 | 
			
		||||
 | 
			
		||||
Unit Testing is a software testing method by which individual units of
 | 
			
		||||
source code, sets of one or more MCU program modules together with associated
 | 
			
		||||
control data, usage procedures, and operating procedures, are tested to
 | 
			
		||||
determine whether they are fit for use. Unit testing finds problems early
 | 
			
		||||
in the development cycle.
 | 
			
		||||
 | 
			
		||||
More information about PlatformIO Unit Testing:
 | 
			
		||||
- https://docs.platformio.org/en/latest/advanced/unit-testing/index.html
 | 
			
		||||
		Loading…
	
		Reference in New Issue