echo.h   echo.h 
skipping to change at line 30 skipping to change at line 30
public: public:
echobuf (sockinetbuf& si): protocol::protocolbuf (si) {} echobuf (sockinetbuf& si): protocol::protocolbuf (si) {}
echobuf (protocol::p_name pname) : protocol::protocolbuf (pname) {} echobuf (protocol::p_name pname) : protocol::protocolbuf (pname) {}
virtual void serve_clients (int portno = -1); virtual void serve_clients (int portno = -1);
virtual const char* rfc_name () const { return "echo"; } virtual const char* rfc_name () const { return "echo"; }
virtual const char* rfc_doc () const { return "rfc862"; } virtual const char* rfc_doc () const { return "rfc862"; }
}; };
protected: protected:
echo (): ios(0) {} echo (): std::ios(0) {}
public: public:
echo (protocol::p_name pname) echo (protocol::p_name pname)
: ios (0) : std::ios (0)
{ {
ios::init (new echobuf (pname)); std::ios::init (new echobuf (pname));
} }
~echo () { delete ios::rdbuf (); ios::init (0); } ~echo () { delete std::ios::rdbuf (); std::ios::init (0); }
echobuf* rdbuf () { return (echobuf*) protocol::rdbuf (); } echobuf* rdbuf () { return (echobuf*) protocol::rdbuf (); }
echobuf* operator -> () { return rdbuf (); } echobuf* operator -> () { return rdbuf (); }
}; };
#endif // !ECHO_H #endif // !ECHO_H
 End of changes. 4 change blocks. 
4 lines changed or deleted 4 lines changed or added


 ftp.h   ftp.h 
skipping to change at line 77 skipping to change at line 77
char* password; char* password;
char* account; char* account;
char cwd [MAXPATHLEN]; char cwd [MAXPATHLEN];
char parentdir [MAXPATHLEN]; char parentdir [MAXPATHLEN];
filestru fs; filestru fs;
transmode tm; transmode tm;
sockinetaddr udata; // user will listen at this addr for data conn. sockinetaddr udata; // user will listen at this addr for data conn.
int serverportno; int serverportno;
char replycode [5]; char replycode [5];
ostream* o; std::ostream* o;
replycodea send_cmd (const char* cmd, const char* arg=0); replycodea send_cmd (const char* cmd, const char* arg=0);
replycodea ftpdata (int portno, istream* i, ostream* out, replycodea ftpdata (int portno, std::istream* i, std::ostream* out,
const char* cmd, const char* arg=0); const char* cmd, const char* arg=0);
ftpbuf (ftpbuf&); ftpbuf (ftpbuf&);
ftpbuf& operator = (ftpbuf&); ftpbuf& operator = (ftpbuf&);
public: public:
ftpbuf (ostream* out = 0); ftpbuf (std::ostream* out = 0);
replycodea get_response (); replycodea get_response ();
const char* reply_code () const { return replycode; } const char* reply_code () const { return replycode; }
replycodea help () { return send_cmd ("HELP"); } replycodea help () { return send_cmd ("HELP"); }
replycodea noop () { return send_cmd ("NOOP"); } replycodea noop () { return send_cmd ("NOOP"); }
replycodea quit () { return send_cmd ("QUIT"); } replycodea quit () { return send_cmd ("QUIT"); }
replycodea abort () { return send_cmd ("ABOR"); } replycodea abort () { return send_cmd ("ABOR"); }
replycodea user (const char* name) {return send_cmd ("USER", name);} replycodea user (const char* name) {return send_cmd ("USER", name);}
replycodea passwd (const char* pw) {return send_cmd ("PASS", pw); } replycodea passwd (const char* pw) {return send_cmd ("PASS", pw); }
skipping to change at line 128 skipping to change at line 128
replycodea pwd () { return send_cmd ("PWD"); } replycodea pwd () { return send_cmd ("PWD"); }
replycodea system () { return send_cmd ("SYST"); } replycodea system () { return send_cmd ("SYST"); }
replycodea status () { return send_cmd ("STAT"); } replycodea status () { return send_cmd ("STAT"); }
virtual void serve_clients (int portno = -1); virtual void serve_clients (int portno = -1);
virtual const char* rfc_name () const { return "ftp"; } virtual const char* rfc_name () const { return "ftp"; }
virtual const char* rfc_doc () const { return "rfc959"; } virtual const char* rfc_doc () const { return "rfc959"; }
}; };
protected: protected:
ftp (): ios (0) {} ftp (): std::ios (0) {}
public: public:
ftp (ostream* out); ftp (std::ostream* out);
~ftp () { delete ios::rdbuf (); ios::init (0); } ~ftp () { delete std::ios::rdbuf (); std::ios::init (0); }
ftpbuf* rdbuf () { return (ftpbuf*) protocol::rdbuf (); } ftpbuf* rdbuf () { return (ftpbuf*) protocol::rdbuf (); }
ftpbuf* operator -> () { return rdbuf (); } ftpbuf* operator -> () { return rdbuf (); }
}; };
#endif // !FTP_H #endif // !FTP_H
 End of changes. 5 change blocks. 
6 lines changed or deleted 6 lines changed or added


 pipestream.h   pipestream.h 
skipping to change at line 18 skipping to change at line 18
// //
// Version: 12Jan97 1.11 // Version: 12Jan97 1.11
#ifndef _PIPESTREAM_H #ifndef _PIPESTREAM_H
#define _PIPESTREAM_H #define _PIPESTREAM_H
#include <socket++/sockstream.h> #include <socket++/sockstream.h>
class ipipestream: public isockstream { class ipipestream: public isockstream {
protected: protected:
// ipipestream (): ios (0) {} // ipipestream (): std::ios (0) {}
public: public:
ipipestream (const char* cmd); ipipestream (const char* cmd);
~ipipestream () { delete ios::rdbuf (); } ~ipipestream () { delete std::ios::rdbuf (); }
}; };
class opipestream: public osockstream { class opipestream: public osockstream {
protected: protected:
// opipestream (): ios(0) {} // opipestream (): std::ios(0) {}
public: public:
opipestream (const char* cmd); opipestream (const char* cmd);
~opipestream () { delete ios::rdbuf (); } ~opipestream () { delete std::ios::rdbuf (); }
}; };
class iopipestream: public iosockstream { class iopipestream: public iosockstream {
private: private:
iopipestream(const iopipestream& sp); // no defintion provided iopipestream(const iopipestream& sp); // no defintion provided
iopipestream& operator = (iopipestream&); // no definition provide d iopipestream& operator = (iopipestream&); // no definition provide d
protected: protected:
int sp[2]; // socket pair int sp[2]; // socket pair
skipping to change at line 53 skipping to change at line 53
// cpid is 0 if this is child // cpid is 0 if this is child
pid_t cpid; pid_t cpid;
iopipestream* next; // next in the chain. Used only by iopipestream* next; // next in the chain. Used only by
// iopipstream (sockbuf::type, int) // iopipstream (sockbuf::type, int)
static iopipestream* head; // list to take care of by fork() static iopipestream* head; // list to take care of by fork()
public: public:
iopipestream(sockbuf::type ty=sockbuf::sock_stream, int proto=0); iopipestream(sockbuf::type ty=sockbuf::sock_stream, int proto=0);
iopipestream(const char* cmd); iopipestream(const char* cmd);
~iopipestream () { delete ios::rdbuf (); } ~iopipestream () { delete std::ios::rdbuf (); }
pid_t pid () const { return cpid; } // returns cpid pid_t pid () const { return cpid; } // returns cpid
static pid_t fork(); // sets cpid of all iopipestream* in the head static pid_t fork(); // sets cpid of all iopipestream* in the head
}; };
#endif // _PIPESTREAM_H #endif // _PIPESTREAM_H
 End of changes. 5 change blocks. 
5 lines changed or deleted 5 lines changed or added


 protocol.h   protocol.h 
skipping to change at line 49 skipping to change at line 49
void connect (const char* host); void connect (const char* host);
void connect (const char* host, int portno); void connect (const char* host, int portno);
const char* protocol_name () const; const char* protocol_name () const;
virtual void serve_clients (int portno = -1) = 0; virtual void serve_clients (int portno = -1) = 0;
virtual const char* rfc_name () const = 0; virtual const char* rfc_name () const = 0;
virtual const char* rfc_doc () const = 0; virtual const char* rfc_doc () const = 0;
}; };
protocol (): ios (0), iosockstream(NULL) {} // NULL seems like a very ba d idea protocol (): std::ios (0), iosockstream(NULL) {} // NULL seems like a ve ry bad idea
}; };
#endif // PROTOCOL_H #endif // PROTOCOL_H
 End of changes. 1 change blocks. 
1 lines changed or deleted 1 lines changed or added


 smtp.h   smtp.h 
skipping to change at line 19 skipping to change at line 19
// Version: 12Jan97 1.11 // Version: 12Jan97 1.11
#ifndef SMTP_H #ifndef SMTP_H
#define SMTP_H #define SMTP_H
#include <socket++/protocol.h> #include <socket++/protocol.h>
class smtp: public protocol { class smtp: public protocol {
public: public:
class smtpbuf : public protocol::protocolbuf { class smtpbuf : public protocol::protocolbuf {
ostream* o; // send all the responses to o std::ostream* o; // send all the responses to o
void send_cmd (const char* cmd, const char* s = 0, void send_cmd (const char* cmd, const char* s = 0,
const char* p = 0); const char* p = 0);
void get_response (); void get_response ();
smtpbuf (smtpbuf&); smtpbuf (smtpbuf&);
smtpbuf& operator = (smtpbuf&); smtpbuf& operator = (smtpbuf&);
public: public:
smtpbuf (ostream* out = 0) smtpbuf (std::ostream* out = 0)
: protocol::protocolbuf (protocol::tcp), o (out) {} : protocol::protocolbuf (protocol::tcp), o (out) {}
void send_buf (const char* buf, int buflen); void send_buf (const char* buf, int buflen);
void helo (); void helo ();
void quit () { send_cmd ("QUIT"); } void quit () { send_cmd ("QUIT"); }
void turn () { send_cmd ("TURN"); } void turn () { send_cmd ("TURN"); }
void rset () { send_cmd ("RSET"); } void rset () { send_cmd ("RSET"); }
void noop () { send_cmd ("NOOP"); } void noop () { send_cmd ("NOOP"); }
void vrfy (const char* s) { send_cmd ("VRFY ", s); } void vrfy (const char* s) { send_cmd ("VRFY ", s); }
skipping to change at line 55 skipping to change at line 55
void mail (const char* reverse_path); void mail (const char* reverse_path);
void rcpt (const char* forward_path); void rcpt (const char* forward_path);
void help (const char* s = 0); void help (const char* s = 0);
virtual void serve_clients (int portno = -1); virtual void serve_clients (int portno = -1);
virtual const char* rfc_name () const { return "smtp"; } virtual const char* rfc_name () const { return "smtp"; }
virtual const char* rfc_doc () const { return "rfc821"; } virtual const char* rfc_doc () const { return "rfc821"; }
}; };
protected: protected:
smtp(): ios (0) {} smtp(): std::ios (0) {}
public: public:
smtp (ostream* out): ios (0) { ios::init (new smtpbuf (out)); } smtp (std::ostream* out): std::ios (0) { std::ios::init (new smtpbuf (out
~smtp () { delete ios::rdbuf (); ios::init (0); } )); }
~smtp () { delete std::ios::rdbuf (); std::ios::init (0); }
int get_response (char* buf, int len); int get_response (char* buf, int len);
smtpbuf* rdbuf () { return (smtpbuf*) protocol::rdbuf (); } smtpbuf* rdbuf () { return (smtpbuf*) protocol::rdbuf (); }
smtpbuf* operator -> () { return rdbuf (); } smtpbuf* operator -> () { return rdbuf (); }
}; };
extern ostream& operator << (ostream& o, smtp& s); extern std::ostream& operator << (std::ostream& o, smtp& s);
#endif // SMTP_H #endif // SMTP_H
 End of changes. 5 change blocks. 
6 lines changed or deleted 7 lines changed or added


 sockinet.h   sockinet.h 
skipping to change at line 108 skipping to change at line 108
class isockinet: public isockstream class isockinet: public isockstream
{ {
public: public:
isockinet (const sockbuf::sockdesc& sd); isockinet (const sockbuf::sockdesc& sd);
isockinet (const sockinetbuf& sb); isockinet (const sockinetbuf& sb);
isockinet (sockbuf::type ty=sockbuf::sock_stream, isockinet (sockbuf::type ty=sockbuf::sock_stream,
int proto=0); int proto=0);
~isockinet (); ~isockinet ();
sockinetbuf* rdbuf () { return (sockinetbuf*)ios::rdbuf (); } sockinetbuf* rdbuf () { return (sockinetbuf*)std::ios::rdbuf (); }
sockinetbuf* operator -> () { return rdbuf (); } sockinetbuf* operator -> () { return rdbuf (); }
}; };
class osockinet: public osockstream class osockinet: public osockstream
{ {
public: public:
osockinet (const sockbuf::sockdesc& sd); osockinet (const sockbuf::sockdesc& sd);
osockinet (const sockinetbuf& sb); osockinet (const sockinetbuf& sb);
osockinet (sockbuf::type ty=sockbuf::sock_stream, osockinet (sockbuf::type ty=sockbuf::sock_stream,
int proto=0); int proto=0);
~osockinet (); ~osockinet ();
sockinetbuf* rdbuf () { return (sockinetbuf*)ios::rdbuf (); } sockinetbuf* rdbuf () { return (sockinetbuf*)std::ios::rdbuf (); }
sockinetbuf* operator -> () { return rdbuf (); } sockinetbuf* operator -> () { return rdbuf (); }
}; };
class iosockinet: public iosockstream class iosockinet: public iosockstream
{ {
public: public:
iosockinet (const sockbuf::sockdesc& sd); iosockinet (const sockbuf::sockdesc& sd);
iosockinet (const sockinetbuf& sb); iosockinet (const sockinetbuf& sb);
iosockinet (sockbuf::type ty=sockbuf::sock_stream, iosockinet (sockbuf::type ty=sockbuf::sock_stream,
int proto=0); int proto=0);
~iosockinet (); ~iosockinet ();
sockinetbuf* rdbuf () { return (sockinetbuf*)ios::rdbuf (); } sockinetbuf* rdbuf () { return (sockinetbuf*)std::ios::rdbuf (); }
sockinetbuf* operator -> () { return rdbuf (); } sockinetbuf* operator -> () { return rdbuf (); }
}; };
#endif // _SOCKINET_H #endif // _SOCKINET_H
 End of changes. 3 change blocks. 
3 lines changed or deleted 3 lines changed or added


 sockstream.h   sockstream.h 
skipping to change at line 54 skipping to change at line 54
# include <sys/types.h> # include <sys/types.h>
# include <sys/uio.h> # include <sys/uio.h>
# include <sys/socket.h> # include <sys/socket.h>
# define SOCKET int # define SOCKET int
# define SOCKET_ERROR -1 # define SOCKET_ERROR -1
#else #else
# include <Wininet.h> # include <Wininet.h>
# pragma comment(lib, "Wininet") # pragma comment(lib, "Wininet")
#endif #endif
using namespace std;
#ifdef __linux__ #ifdef __linux__
# define MSG_MAXIOVLEN 16 # define MSG_MAXIOVLEN 16
#endif // __linux__ #endif // __linux__
// socket exception classes // socket exception classes
class sockerr { class sockerr {
int err; int err;
string text; std::string text;
public: public:
sockerr (int e, const char *operation = NULL): err (e) { sockerr (int e, const char *operation = NULL): err (e) {
if (operation != NULL) { if (operation != NULL) {
text = operation; text = operation;
} }
} }
sockerr (int e, const char *operation, const char *specification) : err ( e) { sockerr (int e, const char *operation, const char *specification) : err ( e) {
if (operation != NULL) if (operation != NULL)
text = operation; text = operation;
if (specification != NULL) { if (specification != NULL) {
text += "("; text += "(";
text += specification; text += specification;
text += ")"; text += ")";
} }
} }
sockerr (int e, const string &operation): err (e) { sockerr (int e, const std::string &operation): err (e) {
text = operation; text = operation;
} }
sockerr (const sockerr &O) { sockerr (const sockerr &O) {
err = O.err; err = O.err;
text = O.text; text = O.text;
} }
const char* what () const { return "sockerr"; } const char* what () const { return "sockerr"; }
const char* operation () const { return text.c_str(); } const char* operation () const { return text.c_str(); }
skipping to change at line 126 skipping to change at line 124
virtual operator void* () const =0; virtual operator void* () const =0;
operator sockaddr* () const { return addr (); } operator sockaddr* () const { return addr (); }
virtual int size () const =0; virtual int size () const =0;
virtual int family () const =0; virtual int family () const =0;
virtual sockaddr* addr () const =0; virtual sockaddr* addr () const =0;
}; };
struct msghdr; struct msghdr;
// socket buffer class // socket buffer class
class sockbuf: public streambuf { class sockbuf: public std::streambuf {
public: public:
enum type { enum type {
sock_stream = SOCK_STREAM, sock_stream = SOCK_STREAM,
sock_dgram = SOCK_DGRAM, sock_dgram = SOCK_DGRAM,
sock_raw = SOCK_RAW, sock_raw = SOCK_RAW,
sock_rdm = SOCK_RDM, sock_rdm = SOCK_RDM,
sock_seqpacket = SOCK_SEQPACKET sock_seqpacket = SOCK_SEQPACKET
}; };
enum option { enum option {
so_debug = SO_DEBUG, so_debug = SO_DEBUG,
skipping to change at line 174 skipping to change at line 172
}; };
enum { somaxconn = SOMAXCONN }; enum { somaxconn = SOMAXCONN };
struct socklinger { struct socklinger {
int l_onoff; // option on/off int l_onoff; // option on/off
int l_linger; // linger time int l_linger; // linger time
socklinger (int a, int b): l_onoff (a), l_linger (b) {} socklinger (int a, int b): l_onoff (a), l_linger (b) {}
}; };
typedef char char_type; typedef char char_type;
typedef streampos pos_type; typedef std::streampos pos_type;
typedef streamoff off_type; typedef std::streamoff off_type;
typedef int int_type; typedef int int_type;
typedef int seekdir; typedef int seekdir;
// const int_type eof = EOF; // const int_type eof = EOF;
enum { eof = EOF }; // LN enum { eof = EOF }; // LN
struct sockdesc { struct sockdesc {
int sock; int sock;
sockdesc (int d): sock (d) {} sockdesc (int d): sock (d) {}
}; };
skipping to change at line 202 skipping to change at line 200
bool oob; // check for out-of-band byte while reading bool oob; // check for out-of-band byte while reading
void* gend; // end of input buffer void* gend; // end of input buffer
void* pend; // end of output buffer void* pend; // end of output buffer
sockcnt(SOCKET s) sockcnt(SOCKET s)
: sock(s), cnt(1), stmo (-1), rtmo (-1), oob (false), : sock(s), cnt(1), stmo (-1), rtmo (-1), oob (false),
gend (0), pend (0) {} gend (0), pend (0) {}
}; };
sockcnt* rep; // counts the # refs to sock sockcnt* rep; // counts the # refs to sock
string sockname; // name of sockbuf - Herbert Straub std::string sockname; // name of sockbuf - Herbert Straub
#if 0 #if 0
virtual sockbuf* setbuf (char_type* s, int_type* n); virtual sockbuf* setbuf (char_type* s, int_type* n);
virtual pos_type seekoff (off_type off, virtual pos_type seekoff (off_type off,
seekdir way, seekdir way,
ios::openmode which = ios::in|ios::out); std::ios::openmode which = ios::in|ios::out );
virtual pos_type seekpos (pos_type sp, virtual pos_type seekpos (pos_type sp,
ios::openmode which = ios::in|ios::out); std::ios::openmode which = ios::in|ios::out );
#endif #endif
virtual int sync (); virtual int sync ();
virtual int showmanyc () const; virtual int showmanyc () const;
virtual streamsize xsgetn (char_type* s, streamsize n); virtual std::streamsize xsgetn (char_type* s, std::streamsize n);
virtual int_type underflow (); virtual int_type underflow ();
virtual int_type uflow (); virtual int_type uflow ();
virtual int_type pbackfail (int_type c = eof); virtual int_type pbackfail (int_type c = eof);
virtual streamsize xsputn (const char_type* s, streamsize n); virtual std::streamsize xsputn (const char_type* s, std::streamsize n) ;
virtual int_type overflow (int_type c = eof); virtual int_type overflow (int_type c = eof);
public: public:
sockbuf (const sockdesc& sd); sockbuf (const sockdesc& sd);
sockbuf (int domain, type, int proto); sockbuf (int domain, type, int proto);
sockbuf (const sockbuf&); sockbuf (const sockbuf&);
// sockbuf& operator = (const sockbuf&); // sockbuf& operator = (const sockbuf&);
virtual ~sockbuf (); virtual ~sockbuf ();
int sd () const { return rep->sock; } int sd () const { return rep->sock; }
skipping to change at line 301 skipping to change at line 299
socklinger linger () const; socklinger linger () const;
socklinger linger (socklinger opt) const; socklinger linger (socklinger opt) const;
socklinger linger (int onoff, int tm) const socklinger linger (int onoff, int tm) const
{ return linger (socklinger (onoff, tm)); } { return linger (socklinger (onoff, tm)); }
bool atmark () const; bool atmark () const;
long nread () const; long nread () const;
long howmanyc () const; long howmanyc () const;
void nbio (bool set=true) const; void nbio (bool set=true) const;
inline void setname (const char *name); inline void setname (const char *name);
inline void setname (const string &name); inline void setname (const std::string &name);
inline const string& getname (); inline const std::string& getname ();
#ifndef WIN32 #ifndef WIN32
void async (bool set=true) const; void async (bool set=true) const;
int pgrp () const; int pgrp () const;
int pgrp (int new_pgrp) const; int pgrp (int new_pgrp) const;
void closeonexec (bool set=true) const; void closeonexec (bool set=true) const;
#endif #endif
}; };
class isockstream: public istream { class isockstream: public std::istream {
protected: protected:
// isockstream (): istream(rdbuf()), ios (0) {} // isockstream (): std::istream(rdbuf()), ios (0) {}
public: public:
isockstream(sockbuf* sb): istream(sb), ios (sb) {} isockstream(sockbuf* sb): std::ios (sb), std::istre am(sb) {}
virtual ~isockstream () {} virtual ~isockstream () {}
sockbuf* rdbuf () { return (sockbuf*)ios::rdbuf(); } sockbuf* rdbuf () { return (sockbuf*)std::ios::rdbuf(); }
sockbuf* operator -> () { return rdbuf(); } sockbuf* operator -> () { return rdbuf(); }
}; };
class osockstream: public ostream { class osockstream: public std::ostream {
protected: protected:
// osockstream (): ostream(static_cast<>rdbuf()), io s (0) {} // osockstream (): ostream(static_cast<>rdbuf()), st d::ios (0) {}
public: public:
osockstream(sockbuf* sb): ostream(sb), ios (sb) {} osockstream(sockbuf* sb): std::ios (sb), std::ostrea m(sb) {}
virtual ~osockstream () {} virtual ~osockstream () {}
sockbuf* rdbuf () { return (sockbuf*)ios::rdbuf(); } sockbuf* rdbuf () { return (sockbuf*)std::ios::rdbuf(); }
sockbuf* operator -> () { return rdbuf(); } sockbuf* operator -> () { return rdbuf(); }
}; };
class iosockstream: public iostream { class iosockstream: public std::iostream {
protected: protected:
iosockstream (); iosockstream ();
public: public:
iosockstream(sockbuf* sb): iostream(sb), ios (sb) { } iosockstream(sockbuf* sb): std::ios (sb), std::iost ream(sb) {}
virtual ~iosockstream () {} virtual ~iosockstream () {}
sockbuf* rdbuf () { return (sockbuf*)ios::rdbuf(); } sockbuf* rdbuf () { return (sockbuf*)std::ios::rdbuf(); }
sockbuf* operator -> () { return rdbuf(); } sockbuf* operator -> () { return rdbuf(); }
}; };
// manipulators // manipulators
extern osockstream& crlf (osockstream&); extern osockstream& crlf (osockstream&);
extern osockstream& lfcr (osockstream&); extern osockstream& lfcr (osockstream&);
// inline // inline
void sockbuf::setname (const char *name) void sockbuf::setname (const char *name)
{ {
sockname = name; sockname = name;
} }
void sockbuf::setname (const string &name) void sockbuf::setname (const std::string &name)
{ {
sockname = name; sockname = name;
} }
const string& sockbuf::getname () const std::string& sockbuf::getname ()
{ {
return sockname; return sockname;
} }
#endif // _SOCKSTREAM_H #endif // _SOCKSTREAM_H
 End of changes. 24 change blocks. 
27 lines changed or deleted 25 lines changed or added

This html diff was produced by rfcdiff 1.41. The latest version is available from http://tools.ietf.org/tools/rfcdiff/