                        (setq emdocs-mode nil)
                        (emdocs-disconnect))
               (with-current-buffer buffer
-                (make-local-variable 'emdocs-is-network-insert)
                 (setq emdocs-is-network-insert nil)
-                (add-hook 'after-change-functions
-                          #'emdocs-after-change-function)))))
+                (setq-local after-change-functions
+                            (cons
+                             (lambda (beg end prev-length)
+                               (emdocs-after-change-function
+                                buffer beg end prev-length))
+                             after-change-functions))))))
       (message "Not connected to internet: exiting.")
       (setq emdocs-mode nil)
       (emdocs-disconnect))))
 
 (defun emdocs-connect ()
   "docstring"
-  (make-local-variable 'emdocs-ip-addr)
   (setq emdocs-ip-addr (read-from-minibuffer "ip: "))
   ;; check for private ips
   (if (or (string-match "^192\\.168\\.[0-9]+\\.[0-9]+$" emdocs-ip-addr)

  (with-current-buffer (emdocs-get-client-process-buffer buffer)
    (goto-char (point-min))
    (insert "sentinel:" msg)
    (unless (bolp) (newline)))
  (cond ((string-match "^give me buffer and ip\n$" msg)
         (process-send-string
          sock
          (json-encode
           `(:buffer ,(buffer-name buffer)
             :ip ,(emdocs-get-internal-ip-address)))))))

(defun emdocs-client-filter (buffer sock msg)
  "docstring"
  ;; assumes will only receive json from emdocs-after-change-function
  (with-current-buffer (emdocs-get-client-process-buffer buffer)
    (goto-char (point-min))
    (insert "filter:" msg)
    (unless (bolp) (newline)))
  (let* ((json-object-type 'plist)
         (json-msg (json-read-from-string msg)))
    (with-current-buffer (plist-get json-msg :buffer)
      (save-excursion
        (setq emdocs-is-network-insert t)
        (unwind-protect
            (cond
             ((string-equal "insert" (plist-get json-msg :edit_type))
              (goto-char (plist-get json-msg :point))
              (insert (plist-get json-msg :content)))
             ((string-equal "delete" (plist-get json-msg :edit_type))
              (goto-char (plist-get json-msg :point))
              (delete-char (plist-get json-msg :content))))
          (setq emdocs-is-network-insert nil))))))

(defun emdocs-connect-client (buffer ip)
  "docstring"
  (make-network-process
   :name (emdocs-get-client-process-name buffer ip)
   ;; TODO: remove the log buffer
   :buffer (emdocs-get-client-process-buffer buffer)
   :family 'ipv4

   :noquery t))

(defun emdocs-broadcast-message (msg)
  (message msg)
  (loop for client in *emdocs-clients*
        do (process-send-string client msg)))

(defun emdocs-emit-keypress-json (buffer type point content)
  (emdocs-broadcast-message
   (json-encode
    `(:buffer ,(if (bufferp buffer)
                   (buffer-name buffer)
                 buffer)
      :edit_type ,type
      :point ,point
      :content ,content))))

(defun emdocs-after-change-function (buffer beg end prev-length)
  (with-current-buffer (buffer-name buffer)
    (if (boundp 'emdocs-is-network-insert)
        (unless emdocs-is-network-insert
          (cond ((= prev-length 0)
                 (emdocs-emit-keypress-json
                  buffer "insert" beg (buffer-substring beg end)))
                ((= beg end)
                 (emdocs-emit-keypress-json
                  buffer "delete" beg prev-length))))
      (message "WHAT"))))

(defvar-local emdocs-client-list nil
  "docstring")

(defvar-local emdocs-ip-addr nil
  "docstring")

(defvar-local emdocs-is-network-insert nil
  "docstring")

(defun emdocs-attach-sockets-to-buffer (buffer ip)
  "docstring"
