7e4c942016-04-29Chris Angelico //! IMAP.server //! //! Handles the server side of the protocol.
02751c1998-09-02Niels Möller 
a580e12000-09-27Fredrik Hübinette (Hubbe) #pike __REAL_VERSION__
a20af62000-09-26Fredrik Hübinette (Hubbe) 
53a9021998-10-14Niels Möller inherit Protocols.Line.imap_style;
9406111998-10-16Niels Möller int debug_level;
53a9021998-10-14Niels Möller void send_line(string s) {
fb1b141999-02-02Henrik Grubbström (Grubba)  if (debug_level) { werror(sprintf("IMAP.server::send_line(%O)\n", s)); }
53a9021998-10-14Niels Möller  send(s + "\r\n"); }
fb1b141999-02-02Henrik Grubbström (Grubba) void send_lines(string ... s)
53a9021998-10-14Niels Möller {
fb1b141999-02-02Henrik Grubbström (Grubba)  if (debug_level) { werror(sprintf("IMAP.server::send_lines(%O)\n", s)); }
53a9021998-10-14Niels Möller  send_line(s * "\r\n"); }
6ea8381998-10-16Niels Möller void close_imap() { disconnect(); }
53a9021998-10-14Niels Möller void do_timeout() { if (con) { send_line("* BYE Timeout"); disconnect(); } }
9406111998-10-16Niels Möller mapping(string:function) commands; function(object:void) request_callback;
53a9021998-10-14Niels Möller  void recv_command(string s) {
ead9722003-01-20Martin Nilsson  if (!sizeof(s))
6ea8381998-10-16Niels Möller  // Ignore empty lines. return;
3524712015-05-26Martin Nilsson 
53a9021998-10-14Niels Möller  object line = .parse_line(s);
9406111998-10-16Niels Möller  // trace(4711);
53a9021998-10-14Niels Möller  string tag = line->get_atom();
9406111998-10-16Niels Möller  if (debug_level) werror("Read tag: %O\n", tag);
3524712015-05-26Martin Nilsson 
53a9021998-10-14Niels Möller  if (!tag) {
9406111998-10-16Niels Möller  // werror("Foo!\n");
53a9021998-10-14Niels Möller  send_bad_response(tag, "No tag");
9406111998-10-16Niels Möller  return;
53a9021998-10-14Niels Möller  }
3524712015-05-26Martin Nilsson 
8ef5231999-02-13Henrik Grubbström (Grubba)  int state; int|function req;
8435ab1999-02-13Henrik Grubbström (Grubba)  do { string command = line->get_atom();
53a9021998-10-14Niels Möller 
8435ab1999-02-13Henrik Grubbström (Grubba)  if (!command) { send_bad_response(tag, "No command"); return; }
53a9021998-10-14Niels Möller 
8435ab1999-02-13Henrik Grubbström (Grubba)  if (debug_level) werror("Read command: %O\n", command);
3524712015-05-26Martin Nilsson 
8ef5231999-02-13Henrik Grubbström (Grubba)  req = commands[lower_case(command)];
8435ab1999-02-13Henrik Grubbström (Grubba)  if (intp(req)) { if (!req || state) {
3524712015-05-26Martin Nilsson  send_bad_response(tag, upper_case(command)+" Unknown command");
8435ab1999-02-13Henrik Grubbström (Grubba)  return; } state = req; } else { // Found a function. break; } } while (1);
53a9021998-10-14Niels Möller 
8435ab1999-02-13Henrik Grubbström (Grubba)  request_callback(req(tag, line, state));
53a9021998-10-14Niels Möller } class recv_line {
6ea8381998-10-16Niels Möller  function handler;
53a9021998-10-14Niels Möller 
6ea8381998-10-16Niels Möller  void create(function h)
53a9021998-10-14Niels Möller  { handler = h; } void `()(string s) { handler(.parse_line(s)); } } class recv_literal {
6ea8381998-10-16Niels Möller  function handler;
3524712015-05-26Martin Nilsson 
6ea8381998-10-16Niels Möller  void create(function h)
53a9021998-10-14Niels Möller  { handler = h; } void `()(string s) { handler(s); } } /* Functions that can usefully be called by the request handler */ /* NOTE: This function sends an \r\n-pair even if the last argument is * sent as a literal. I don't understand whether or not this behaviour * is correct according to rfc-2060.*/ void send_imap(string|object ...args) { send_line(.types.imap_format_array(args)); } void send_bad_response(string tag, string msg) { tag = tag || "*"; send_imap(tag, "BAD", msg); } void send_ok_response(string tag, string msg) { send_imap(tag, "OK", msg); }
6ea8381998-10-16Niels Möller void send_continuation_response(string msg) { send_imap("+", msg); }
53a9021998-10-14Niels Möller void use_commands(mapping(string:function) c) { commands = c; } void get_request() {
9406111998-10-16Niels Möller  handle_line = recv_command;
53a9021998-10-14Niels Möller }
6ea8381998-10-16Niels Möller void get_line(function handler)
53a9021998-10-14Niels Möller {
9406111998-10-16Niels Möller  handle_line = recv_line(handler);
53a9021998-10-14Niels Möller }
6ea8381998-10-16Niels Möller void get_literal(int length, function handler)
53a9021998-10-14Niels Möller { literal_length = length; handle_literal = recv_literal(handler); }
9406111998-10-16Niels Möller void create(object f, int timeout, function(object:void) callback, int|void debug) { ::create(f, timeout); debug_level = debug; request_callback = callback;
3524712015-05-26Martin Nilsson 
9406111998-10-16Niels Möller  get_request(); }