mod_muc: The default room name is the room node
[prosody.git] / prosody
1 #!/usr/bin/env lua
2 -- Prosody IM v0.4
3 -- Copyright (C) 2008-2009 Matthew Wild
4 -- Copyright (C) 2008-2009 Waqas Hussain
5 -- 
6 -- This project is MIT/X11 licensed. Please see the
7 -- COPYING file in the source package for more information.
8 --
9
10 -- Will be modified by configure script if run --
11
12 CFG_SOURCEDIR=nil;
13 CFG_CONFIGDIR=os.getenv("PROSODY_CFGDIR");
14 CFG_PLUGINDIR=nil;
15 CFG_DATADIR=os.getenv("PROSODY_DATADIR");
16
17 -- -- -- -- -- -- -- ---- -- -- -- -- -- -- -- --
18
19 if CFG_SOURCEDIR then
20         package.path = CFG_SOURCEDIR.."/?.lua;"..package.path
21         package.cpath = CFG_SOURCEDIR.."/?.so;"..package.cpath
22 end
23
24 if CFG_DATADIR then
25         if os.getenv("HOME") then
26                 CFG_DATADIR = CFG_DATADIR:gsub("^~", os.getenv("HOME"));
27         end
28 end
29
30 -- Required to be able to find packages installed with luarocks
31 pcall(require, "luarocks.require")
32
33
34 config = require "core.configmanager"
35
36 do
37         -- TODO: Check for other formats when we add support for them
38         -- Use lfs? Make a new conf/ dir?
39         local ok, level, err = config.load((CFG_CONFIGDIR or ".").."/prosody.cfg.lua");
40         if not ok then
41                 print("\n");
42                 print("**************************");
43                 if level == "parser" then
44                         print("A problem occured while reading the config file "..(CFG_CONFIGDIR or ".").."/prosody.cfg.lua");
45                         local err_line, err_message = tostring(err):match("%[string .-%]:(%d*): (.*)");
46                         print("Error"..(err_line and (" on line "..err_line) or "")..": "..(err_message or tostring(err)));
47                         print("");
48                 elseif level == "file" then
49                         print("Prosody was unable to find the configuration file.");
50                         print("We looked for: "..(CFG_CONFIGDIR or ".").."/prosody.cfg.lua");
51                         print("A sample config file is included in the Prosody download called prosody.cfg.lua.dist");
52                         print("Copy or rename it to prosody.cfg.lua and edit as necessary.");
53                 end
54                 print("More help on configuring Prosody can be found at http://prosody.im/doc/configure");
55                 print("Good luck!");
56                 print("**************************");
57                 print("");
58                 os.exit(1);
59         end
60 end
61
62 --- Initialize logging
63 require "core.loggingmanager"
64
65 --- Check runtime dependencies
66 require "util.dependencies"
67
68 --- Load socket framework
69 local server = require "net.server"
70
71
72
73 -- Maps connections to sessions --
74 sessions = {};
75 hosts = {};
76
77 --- Load and initialise core modules
78 require "util.import"
79 require "core.xmlhandlers"
80 require "core.rostermanager"
81 require "core.eventmanager"
82 require "core.hostmanager"
83 require "core.modulemanager"
84 require "core.usermanager"
85 require "core.sessionmanager"
86 require "core.stanza_router"
87
88 require "util.array"
89 require "util.iterators"
90 require "util.timer"
91
92 -- Commented to protect us from 
93 -- the second kind of people
94 --[[ 
95 pcall(require, "remdebug.engine");
96 if remdebug then remdebug.engine.start() end
97 ]]
98
99 local cl = require "net.connlisteners";
100
101 require "util.stanza"
102 require "util.jid"
103
104 ------------------------------------------------------------------------
105
106
107 ------------- Begin code without a home ---------------------
108
109 local data_path = config.get("*", "core", "data_path") or CFG_DATADIR or "data";
110 require "util.datamanager".set_data_path(data_path);
111 require "util.datamanager".set_callback(function(username, host, datastore)
112         return config.get(host, "core", "anonymous_login");
113 end);
114
115 ----------- End of out-of-place code --------------
116
117 eventmanager.fire_event("server-starting");
118
119 local global_ssl_ctx = ssl and config.get("*", "core", "ssl");
120 if global_ssl_ctx then
121         local default_ssl_ctx = { mode = "server", protocol = "sslv23", capath = "/etc/ssl/certs", verify = "none"; };
122         setmetatable(global_ssl_ctx, { __index = default_ssl_ctx });
123 end
124
125 -- start listening on sockets
126 function net_activate_ports(option, listener, default, conntype)
127         local ports = config.get("*", "core", option.."_ports") or default;
128         if type(ports) == "number" then ports = {ports} end;
129         
130         if type(ports) ~= "table" then
131                 log("error", "core."..option.." is not a table");
132         else
133                 for _, port in ipairs(ports) do
134                         if type(port) ~= "number" then
135                                 log("error", "Non-numeric "..option.."_ports: "..tostring(port));
136                         else
137                                 cl.start(listener, { 
138                                         ssl = conntype ~= "tcp" and global_ssl_ctx,
139                                         port = port,
140                                         interface = config.get("*", "core", option.."_interface"),
141                                         type = conntype
142                                 });
143                         end
144                 end
145         end
146 end
147
148 net_activate_ports("c2s", "xmppclient", {5222}, (global_ssl_ctx and "tls") or "tcp");
149 net_activate_ports("s2s", "xmppserver", {5269}, "tcp");
150 net_activate_ports("legacy_ssl", "xmppclient", {}, "ssl");
151
152 if config.get("*", "core", "console_enabled") then
153         if cl.get("console") then
154                 cl.start("console", { interface = config.get("*", "core", "console_interface") or "127.0.0.1" })
155         else
156                 log("error", "Console is enabled, but the console module appears not to be loaded");
157         end
158 end
159
160 -- Global function to initiate prosody shutdown
161 function prosody_shutdown(reason)
162         log("info", "Shutting down: %s", reason or "unknown reason");
163         eventmanager.fire_event("server-stopping", { reason = reason });
164         server.setquitting(true);
165 end
166
167 -- Catch global accesses --
168 local locked_globals_mt = { __index = function (t, k) error("Attempt to read a non-existent global '"..k.."'", 2); end, __newindex = function (t, k, v) error("Attempt to set a global: "..tostring(k).." = "..tostring(v), 2); end }
169
170 function unlock_globals()
171         setmetatable(_G, nil);
172 end
173
174 function lock_globals()
175         setmetatable(_G, locked_globals_mt);
176 end
177
178 -- And lock now...
179 lock_globals();
180
181 eventmanager.fire_event("server-started");
182
183 -- Error handler for errors that make it this far
184 local function catch_uncaught_error(err)
185         if err:match("%d*: interrupted!$") then
186                 return "quitting";
187         end
188         
189         log("error", "Top-level error, please report:\n%s", tostring(err));
190         local traceback = debug.traceback("", 2);
191         if traceback then
192                 log("error", "%s", traceback);
193         end
194         
195         eventmanager.fire_event("very-bad-error", "*", err, traceback);
196 end
197
198 while select(2, xpcall(server.loop, catch_uncaught_error)) ~= "quitting" do
199         socket.sleep(0.2);
200 end
201
202 eventmanager.fire_event("server-cleanup");
203
204 -- Ok, we're quitting I know, but we
205 -- need to do some tidying before we go :)
206 server.setquitting(false);
207
208 for hostname, host in pairs(hosts) do
209         if host.sessions then
210                 for username, user in pairs(host.sessions) do
211                         for resource, session in pairs(user.sessions) do
212                                 log("debug", "Closing connection for %s@%s/%s", username, hostname, resource);
213                                 session:close("system-shutdown");
214                         end
215                 end
216         end
217         
218         if host.s2sout then
219                 for remotehost, session in pairs(host.s2sout) do
220                         if session.close then
221                                 session:close("system-shutdown");
222                         else
223                                 log("warn", "Unable to close outgoing s2s session to %s, no session:close()?!", remotehost);
224                         end
225                 end
226         end
227 end
228
229 server.closeall();
230
231 eventmanager.fire_event("server-stopped");