Add the names of major contributors to the copyright statement. I've
[u/mdw/putty] / terminal.c
index f0dc9b1..9fc1787 100644 (file)
@@ -201,6 +201,7 @@ static void deselect(void);
 /* log session to file stuff ... */
 static FILE *lgfp = NULL;
 static void logtraffic(unsigned char c, int logmode);
+static void xlatlognam(char *d, char *s, char *hostname, struct tm *tm);
 
 /*
  * Resize a line to make it `cols' columns wide.
@@ -934,15 +935,18 @@ void term_out(void)
 {
     int c, inbuf_reap;
 
+    /*
+     * Optionally log the session traffic to a file. Useful for
+     * debugging and possibly also useful for actual logging.
+     */
+    if (cfg.logtype == LGTYP_DEBUG)
+       for (inbuf_reap = 0; inbuf_reap < inbuf_head; inbuf_reap++) {
+           logtraffic((unsigned char) inbuf[inbuf_reap], LGTYP_DEBUG);
+       }
+
     for (inbuf_reap = 0; inbuf_reap < inbuf_head; inbuf_reap++) {
        c = inbuf[inbuf_reap];
 
-       /*
-        * Optionally log the session traffic to a file. Useful for
-        * debugging and possibly also useful for actual logging.
-        */
-       logtraffic((unsigned char) c, LGTYP_DEBUG);
-
        /* Note only VT220+ are 8-bit VT102 is seven bit, it shouldn't even
         * be able to display 8-bit characters, but I'll let that go 'cause
         * of i18n.
@@ -985,9 +989,9 @@ void term_out(void)
                  case 4:
                  case 5:
                    if ((c & 0xC0) != 0x80) {
-                       inbuf_reap--;  /* This causes the faulting character */
-                       c = UCSERR;    /* to be logged twice - not really a */
-                       utf_state = 0; /* serious problem. */
+                       inbuf_reap--;
+                       c = UCSERR;
+                       utf_state = 0;
                        break;
                    }
                    utf_char = (utf_char << 6) | (c & 0x3f);
@@ -3079,11 +3083,18 @@ void term_mouse(Mouse_Button b, Mouse_Action a, int x, int y,
 {
     pos selpoint;
     unsigned long *ldata;
+    int raw_mouse = xterm_mouse && !(cfg.mouse_override && shift);
 
-    if (y < 0)
+    if (y < 0) {
        y = 0;
-    if (y >= rows)
+       if (a == MA_DRAG && !raw_mouse)
+           term_scroll(0, -1);
+    }
+    if (y >= rows) {
        y = rows - 1;
+       if (a == MA_DRAG && !raw_mouse)
+           term_scroll(0, +1);
+    }
     if (x < 0) {
        if (y > 0) {
            x = cols - 1;
@@ -3100,7 +3111,7 @@ void term_mouse(Mouse_Button b, Mouse_Action a, int x, int y,
     if ((ldata[cols] & LATTR_MODE) != LATTR_NORM)
        selpoint.x /= 2;
 
-    if (xterm_mouse) {
+    if (raw_mouse) {
        int encstate = 0, r, c;
        char abuf[16];
        static int is_down = 0;
@@ -3281,13 +3292,33 @@ int term_ldisc(int option)
 /*
  * from_backend(), to get data from the backend for the terminal.
  */
-void from_backend(int is_stderr, char *data, int len)
+int from_backend(int is_stderr, char *data, int len)
 {
     while (len--) {
        if (inbuf_head >= INBUF_SIZE)
            term_out();
        inbuf[inbuf_head++] = *data++;
     }
+
+    /*
+     * We process all stdout/stderr data immediately we receive it,
+     * and don't return until it's all gone. Therefore, there's no
+     * reason at all to return anything other than zero from this
+     * function.
+     * 
+     * This is a slightly suboptimal way to deal with SSH2 - in
+     * principle, the window mechanism would allow us to continue
+     * to accept data on forwarded ports and X connections even
+     * while the terminal processing was going slowly - but we
+     * can't do the 100% right thing without moving the terminal
+     * processing into a separate thread, and that might hurt
+     * portability. So we manage stdout buffering the old SSH1 way:
+     * if the terminal processing goes slowly, the whole SSH
+     * connection stops accepting data until it's ready.
+     * 
+     * In practice, I can't imagine this causing serious trouble.
+     */
+    return 0;
 }
 
 /*
@@ -3306,22 +3337,35 @@ void logtraffic(unsigned char c, int logmode)
     }
 }
 
+void settimstr(char *ta, int no_sec);
+char *subslfcode(char *dest, char *src, char *dstrt);
+char *stpncpy(char *dst, const char *src, size_t maxlen);
+char timdatbuf[20];
+char currlogfilename[FILENAME_MAX];
+
 /* open log file append/overwrite mode */
 void logfopen(void)
 {
     char buf[256];
     time_t t;
-    struct tm *tm;
+    struct tm tm;
     char writemod[4];
 
     if (!cfg.logtype)
        return;
     sprintf(writemod, "wb");          /* default to rewrite */
-    lgfp = fopen(cfg.logfilename, "r");        /* file already present? */
+
+    time(&t);
+    tm = *localtime(&t);
+
+    /* substitute special codes in file name */
+    xlatlognam(currlogfilename,cfg.logfilename,cfg.host, &tm);
+
+    lgfp = fopen(currlogfilename, "r");        /* file already present? */
     if (lgfp) {
        int i;
        fclose(lgfp);
-       i = askappend(cfg.logfilename);
+       i = askappend(currlogfilename);
        if (i == 1)
            writemod[0] = 'a';         /* set append mode */
        else if (i == 0) {             /* cancelled */
@@ -3331,22 +3375,20 @@ void logfopen(void)
        }
     }
 
-    lgfp = fopen(cfg.logfilename, writemod);
+    lgfp = fopen(currlogfilename, writemod);
     if (lgfp) {                               /* enter into event log */
        sprintf(buf, "%s session log (%s mode) to file : ",
                (writemod[0] == 'a') ? "Appending" : "Writing new",
                (cfg.logtype == LGTYP_ASCII ? "ASCII" :
                 cfg.logtype == LGTYP_DEBUG ? "raw" : "<ukwn>"));
        /* Make sure we do not exceed the output buffer size */
-       strncat(buf, cfg.logfilename, 128);
+       strncat(buf, currlogfilename, 128);
        buf[strlen(buf)] = '\0';
        logevent(buf);
 
-       /* --- write header line iinto log file */
+       /* --- write header line into log file */
        fputs("=~=~=~=~=~=~=~=~=~=~=~= PuTTY log ", lgfp);
-       time(&t);
-       tm = localtime(&t);
-       strftime(buf, 24, "%Y.%m.%d %H:%M:%S", tm);
+       strftime(buf, 24, "%Y.%m.%d %H:%M:%S", &tm);
        fputs(buf, lgfp);
        fputs(" =~=~=~=~=~=~=~=~=~=~=~=\r\n", lgfp);
     }
@@ -3359,3 +3401,57 @@ void logfclose(void)
        lgfp = NULL;
     }
 }
+
+/*
+ * translate format codes into time/date strings
+ * and insert them into log file name
+ *
+ * "&Y":YYYY   "&m":MM   "&d":DD   "&T":hhmm   "&h":<hostname>   "&&":&
+ */
+static void xlatlognam(char *d, char *s, char *hostname, struct tm *tm) {
+    char buf[10], *bufp;
+    int size;
+    char *ds = d; /* save start pos. */
+    int len = FILENAME_MAX-1;
+
+    while (*s) {
+       /* Let (bufp, len) be the string to append. */
+       bufp = buf;                    /* don't usually override this */
+       if (*s == '&') {
+           char c;
+           s++;
+           if (*s) switch (c = *s++, tolower(c)) {
+             case 'y':
+               size = strftime(buf, sizeof(buf), "%Y", tm);
+               break;
+             case 'm':
+               size = strftime(buf, sizeof(buf), "%m", tm);
+               break;
+             case 'd':
+               size = strftime(buf, sizeof(buf), "%d", tm);
+               break;
+             case 't':
+               size = strftime(buf, sizeof(buf), "%H%M%S", tm);
+               break;
+             case 'h':
+               bufp = hostname;
+               size = strlen(bufp);
+               break;
+             default:
+               buf[0] = '&';
+               size = 1;
+               if (c != '&')
+                   buf[size++] = c;
+           }
+       } else {
+           buf[0] = *s++;
+           size = 1;
+       }
+       if (size > len)
+           size = len;
+       memcpy(d, bufp, size);
+       d += size;
+       len -= size;
+    }
+    *d = '\0';
+}