diff --git a/Properties/config.properties b/Properties/config.properties new file mode 100644 index 0000000..e581083 --- /dev/null +++ b/Properties/config.properties @@ -0,0 +1,6 @@ +WebUsername=admin +WebPassword=admin +WebListenPort = 8080 +SipServer=100.64.0.3 +SipUsername=100 +SipPassword=12345678 \ No newline at end of file diff --git a/SIPIntercom.iml b/SIPIntercom.iml index dc9b352..7208ba6 100644 --- a/SIPIntercom.iml +++ b/SIPIntercom.iml @@ -5,6 +5,8 @@ + + diff --git a/src/Main.java b/src/Main.java index fb8d8f5..0e913d7 100644 --- a/src/Main.java +++ b/src/Main.java @@ -1,21 +1,18 @@ +import Webpage.WebServer; +import code.common; import org.pmw.tinylog.Logger; import java.io.File; import java.text.MessageFormat; +import static code.common.currentDir; public class Main { - private static String serverAddress="100.64.0.3"; - private static String Username="user1"; - private static String Password="12345678"; private static jSIPClient client; - private static String currentDir; + private static WebServer webserver; public static void main(String[] args) { - currentDir = System.getProperty("user.dir"); - GetArguments(args); - Logger.info("Server Address: "+serverAddress); - Logger.info("Username: "+Username); - Logger.info("Password: "+Password); + common.ExtractProperties(currentDir,"config.properties", false); + // SIP Section client = new jSIPClient(); client.SetJavaSipEvent(new javaSipEvents() { @Override @@ -56,11 +53,22 @@ public class Main { } }); ReconnectSIP(); + + + // Web Server Section + webserver = new WebServer(); + webserver.Start(); + + Runtime.getRuntime().addShutdownHook(new Thread(() -> { + Logger.info("Shutting down SIPIntercom"); + if (client!=null) client.Disconnect(); + if (webserver!=null) webserver.Stop(); + })); } @SuppressWarnings("unused") private static void CallTest(String extension){ - String callnumber = MessageFormat.format("sip:{0}@{1}", extension, serverAddress); + String callnumber = MessageFormat.format("sip:{0}@{1}", extension, client.getServerAddress()); if (client.Call(callnumber)){ Logger.info("Call to {} is successful",callnumber); try{ @@ -78,7 +86,7 @@ public class Main { private static void StreamTest(String extension, String filename){ File ff = new File(currentDir, filename); if (ff.isFile()){ - String callnumber = MessageFormat.format("sip:{0}@{1}", extension, serverAddress); + String callnumber = MessageFormat.format("sip:{0}@{1}", extension, client.getServerAddress()); if (client.StreamFile(callnumber, ff.getAbsolutePath())){ Logger.info("Stream to {} is successful",callnumber); try{ @@ -94,7 +102,7 @@ public class Main { } private static void ReconnectSIP(){ - if (client.Connect(serverAddress, Username, Password,"0.0.0.0")){ + if (client.Connect()){ Logger.info("Connected to SIP Server"); } else{ @@ -107,19 +115,5 @@ public class Main { } } - private static void GetArguments(String[] args) { - if (args != null){ - for(String a : args){ - if (a.startsWith("--serverip=")){ - serverAddress=a.substring(11); - } - else if (a.startsWith("--username=")){ - Username=a.substring(11); - } - else if (a.startsWith("--password=")){ - Password=a.substring(11); - } - } - } - } + } \ No newline at end of file diff --git a/src/Webpage/WebServer.java b/src/Webpage/WebServer.java new file mode 100644 index 0000000..b9606c5 --- /dev/null +++ b/src/Webpage/WebServer.java @@ -0,0 +1,77 @@ +package Webpage; + +import code.common; +import io.javalin.Javalin; +import io.javalin.http.staticfiles.Location; + +import java.util.Objects; +import java.util.Properties; + +import static code.common.*; + +public class WebServer { + private final Javalin app; + private final int listenport; + private final String webusername; + private final String webpassword; + public WebServer() { + Properties prop = common.LoadProperties(currentDir,"config.properties"); + listenport = GetProperties_IntValue(prop,"WebListenPort", 8080); + webusername = GetProperties_StringValue(prop,"WebUsername", "admin"); + webpassword = GetProperties_StringValue(prop,"WebPassword", "admin"); + + app = Javalin.create(config -> config.addStaticFiles("/public", Location.CLASSPATH)).start(listenport); + app.get("/", ctx ->{ + if (Objects.equals(ctx.sessionAttribute("username"), webusername)){ + ctx.redirect("/index.html"); + } else { + ctx.sessionAttribute("username", null); + ctx.redirect("/login.html"); + } + }); + app.get("/logout", ctx -> { + ctx.sessionAttribute("username", null); + ctx.redirect("/login.html"); + }); + app.get("/setting", ctx -> { + if (Objects.equals(ctx.sessionAttribute("username"), webusername)){ + //TODO Setting Page + ctx.result("Setting Page"); + } else { + ctx.redirect("/login.html"); + } + }); + app.post("/login", ctx -> { + String username = ctx.formParam("username"); + String password = ctx.formParam("password"); + if (Objects.equals(username, webusername) && Objects.equals(password, webpassword)){ + ctx.sessionAttribute("username", username); + ctx.redirect("/index.html"); + } else { + ctx.redirect("/login.html"); + } + }); + app.post("/setting", ctx -> { + if (Objects.equals(ctx.sessionAttribute("username"), webusername)){ + //TODO Setting Page + ctx.result("Setting Page"); + } else { + ctx.redirect("/login.html"); + } + }); + } + + /** + * Start the web server + */ + public void Start(){ + if (app!=null) app.start(listenport); + } + + /** + * Stop the web server + */ + public void Stop(){ + if (app!=null) app.stop(); + } +} diff --git a/src/code/common.java b/src/code/common.java new file mode 100644 index 0000000..44e9ec0 --- /dev/null +++ b/src/code/common.java @@ -0,0 +1,143 @@ +package code; + +import com.google.gson.Gson; +import com.sun.jna.Native; +import org.pmw.tinylog.Logger; +import peers.sip.syntaxencoding.SipHeaderFieldName; +import peers.sip.syntaxencoding.SipHeaderFieldValue; +import peers.sip.syntaxencoding.SipHeaders; + +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; +import java.util.Properties; + +public class common { + public static String currentDir = System.getProperty("user.dir"); + public static Gson gson = new Gson(); + + public static String GetProperties_StringValue(Properties prop, String key, String defaultavalue){ + if (prop!=null){ + if (ValidString(key)){ + return prop.getProperty(key,defaultavalue); + } + } + return defaultavalue; + } + + public static int GetProperties_IntValue(Properties prop, String key, int defaultavalue){ + if (prop!=null){ + if (ValidString(key)){ + return ParseInt(prop.getProperty(key),defaultavalue); + } + } + return defaultavalue; + } + + + + /** + * Parse integer from string + * @param value string to parse + * @param defaultvalue default value if parsing failed + * @return parsed integer + */ + public static int ParseInt(String value, int defaultvalue){ + try { + return Integer.parseInt(value); + } catch (Exception e) { + return defaultvalue; + } + } + + /** + * Extract properties file from resource path + * @param directory destination directory + * @param filename destination filename + * @param overwrite overwrite if file already exists + */ + public static void ExtractProperties(String directory, String filename, boolean overwrite){ + try{ + File dest = new File(directory,filename); + if (dest.isFile() && !overwrite){ + Logger.info("Properties file already exists: {}",filename); + return; + } + File source = Native.extractFromResourcePath(filename); + if (source==null){ + Logger.error("Failed to extract properties file: {}",filename); + return; + } + if (source.renameTo(dest)) + Logger.info("Extracted properties file: {}",filename); + else Logger.error("Failed to rename properties file: {}",filename); + } catch (Exception e) { + Logger.error("Failed to extract properties file: {}",filename); + } + } + + /** + * Load properties file from directory + * @param directory destination directory + * @param filename destination filename + * @return properties object + */ + @SuppressWarnings("IOStreamConstructor") + public static Properties LoadProperties(String directory, String filename){ + Properties prop = new Properties(); + try { + File file = new File(directory,filename); + if (file.isFile()){ + InputStream is = new FileInputStream(file); + prop.load(is); + is.close(); + Logger.info("Loaded properties file: {}",filename); + } else Logger.info("Properties file not found: {}",filename); + + } catch (Exception e) { + Logger.error("Failed to load properties file: {}",filename); + } + return prop; + } + + /** + * Check if String is not null and have value + * @param value string to check + * @return true if string is not null and have value + */ + public static boolean ValidString(String value){ + if (value!=null){ + return !value.isEmpty(); + } + return false; + } + + /** + * Check if port number is valid + * @param value port number to check + * @return true if port number is valid + */ + public static boolean ValidPortNumber(int value){ + return value>0 && value<65536; + } + + /** + * Get SIP header value from SIP headers + * @param head SIP headers + * @param headername header name + * @param defaultvalue default value if header not found + * @return header value + */ + public static String GetSIPHeaderValue(SipHeaders head, String headername, String defaultvalue) { + if (head!=null) { + SipHeaderFieldName _fn = new SipHeaderFieldName(headername); + if (head.contains(_fn)) { + SipHeaderFieldValue _fv = head.get(_fn); + if (_fv!=null) { + return _fv.getValue(); + } + } + } + return defaultvalue; + } +} diff --git a/src/common.java b/src/common.java deleted file mode 100644 index 6f00c9b..0000000 --- a/src/common.java +++ /dev/null @@ -1,30 +0,0 @@ -import peers.sip.syntaxencoding.SipHeaderFieldName; -import peers.sip.syntaxencoding.SipHeaderFieldValue; -import peers.sip.syntaxencoding.SipHeaders; - -public class common { - - public static boolean ValidString(String value){ - if (value!=null){ - return !value.isEmpty(); - } - return false; - } - - public static boolean ValidPortNumber(int value){ - return value>0 && value<65536; - } - - public static String GetSIPHeaderValue(SipHeaders head, String headername) { - if (head!=null) { - SipHeaderFieldName _fn = new SipHeaderFieldName(headername); - if (head.contains(_fn)) { - SipHeaderFieldValue _fv = head.get(_fn); - if (_fv!=null) { - return _fv.getValue(); - } - } - } - return null; - } -} diff --git a/src/jSIPClient.java b/src/jSIPClient.java index b108e84..39ad526 100644 --- a/src/jSIPClient.java +++ b/src/jSIPClient.java @@ -1,12 +1,11 @@ import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.net.InetAddress; import java.net.SocketException; import java.net.UnknownHostException; import java.text.MessageFormat; +import java.util.Properties; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -14,10 +13,8 @@ import Audio.BassFileReader; import Audio.BassFileReaderListener; import Audio.BassSoundManager; import Audio.BassSoundManagerListener; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; +import code.common; import com.google.gson.JsonIOException; -import com.google.gson.JsonSyntaxException; import lombok.Getter; import org.pmw.tinylog.Logger; @@ -35,13 +32,12 @@ import peers.sip.transactionuser.DialogManager; import peers.sip.transport.SipRequest; import peers.sip.transport.SipResponse; +import static code.common.*; + @SuppressWarnings({"unused", "UnusedReturnValue"}) public class jSIPClient { public jSIPClient() { - gs = new GsonBuilder() - .setPrettyPrinting() - .create(); runningfolder = new File("").getAbsolutePath(); load_config(); Runtime.getRuntime().addShutdownHook(new Thread(() -> { @@ -51,11 +47,14 @@ public class jSIPClient { Disconnect(); })); } + + @Getter private String serverAddress; + @Getter private String Username; + @Getter private String Password; public CustomConfig cc = new CustomConfig(); private EventManager em; - private final Gson gs; private final String runningfolder; @@ -67,23 +66,18 @@ public class jSIPClient { /** - * Connect to SIP Server - * @param serverip SIP Server IP - * @param username Username to register - * @param password Password to register - * @param localip use if need to specify which Network Adapter to use + * Connect to SIP Server * @return true if parameter completed */ - public boolean Connect(String serverip, String username, String password, String localip) { + public boolean Connect() { Disconnect(); if (cc==null) { System.out.println("Creating Custom Config"); cc = new CustomConfig(); } else System.out.println("Custom Config already created"); - if (common.ValidString(serverip)) cc.setDomain(serverip); - if (common.ValidString(username)) cc.setUserPart(username); - if (common.ValidString(password)) cc.setPassword(password); - if (common.ValidString(localip)) cc.SetLocalInetAddress(localip); + cc.setDomain(serverAddress); + cc.setUserPart(Username); + cc.setPassword(Password); em = new EventManager(cc); return false; @@ -537,7 +531,7 @@ public class jSIPClient { @Override public void error(SipResponse sipResponse) { - raise_log_event("sip error, response="+gs.toJson(sipResponse)); + raise_log_event("sip error, response="+common.gson.toJson(sipResponse)); } @@ -555,10 +549,10 @@ public class jSIPClient { req = source; if (req!=null) { SipHeaders head = source.getSipHeaders(); - this.To = common.GetSIPHeaderValue(head,"To"); - this.From = common.GetSIPHeaderValue(head, "From"); - this.CallID = common.GetSIPHeaderValue(head, "Call-ID"); - this.Contact = common.GetSIPHeaderValue(head, "Contact"); + this.To = common.GetSIPHeaderValue(head,"To", null); + this.From = common.GetSIPHeaderValue(head, "From", null); + this.CallID = common.GetSIPHeaderValue(head, "Call-ID", null); + this.Contact = common.GetSIPHeaderValue(head, "Contact", null); } } @@ -578,12 +572,12 @@ public class jSIPClient { this.statusCode = source.getStatusCode(); this.reasonPhrase = source.getReasonPhrase(); SipHeaders head = source.getSipHeaders(); - this.To = common.GetSIPHeaderValue(head, "To"); - this.From = common.GetSIPHeaderValue(head, "From"); - this.CallID = common.GetSIPHeaderValue(head, "Call-ID"); - this.Contact = common.GetSIPHeaderValue(head, "Contact"); - this.Server = common.GetSIPHeaderValue(head, "Server"); - this.Date = common.GetSIPHeaderValue(head, "Date"); + this.To = common.GetSIPHeaderValue(head, "To", null); + this.From = common.GetSIPHeaderValue(head, "From", null); + this.CallID = common.GetSIPHeaderValue(head, "Call-ID", null); + this.Contact = common.GetSIPHeaderValue(head, "Contact", null); + this.Server = common.GetSIPHeaderValue(head, "Server", null); + this.Date = common.GetSIPHeaderValue(head, "Date", null); } } private @Getter final SipResponse resp; @@ -974,25 +968,21 @@ public class jSIPClient { private void save_config() { if (cc!=null) { try { - gs.toJson(cc, new FileWriter(new File(runningfolder,"Config.json"))); + common.gson.toJson(cc, new FileWriter(new File(runningfolder,"Config.json"))); raise_log_event("Config.json saved"); } catch (JsonIOException | IOException e) { raise_log_event("save_config failed, exception = "+e.getMessage()); } } } - - /** - * Dipanggil saat initialization - */ - private void load_config() { - try { - CustomConfig xx = gs.fromJson(new FileReader(new File(runningfolder,"Config.json")), CustomConfig.class); - raise_log_event("Config.json loaded"); - cc = xx; - } catch (JsonSyntaxException | JsonIOException | FileNotFoundException e) { - raise_log_event("load_config failed, exception = "+e.getMessage()); - } - + + private void load_config(){ + Properties prop = LoadProperties(currentDir,"config.properties"); + serverAddress = GetProperties_StringValue(prop,"SipServer","100.64.0.3"); + Username = GetProperties_StringValue(prop,"SipUsername","user1"); + Password = GetProperties_StringValue(prop,"SipPassword","12345678"); + Logger.info("SipServer: "+serverAddress); + Logger.info("SipUsername: "+Username); + Logger.info("SipPassword: "+Password); } } diff --git a/src/peers/sip/core/useragent/handlers/RegisterHandler.java b/src/peers/sip/core/useragent/handlers/RegisterHandler.java index be67137..4c0e93f 100644 --- a/src/peers/sip/core/useragent/handlers/RegisterHandler.java +++ b/src/peers/sip/core/useragent/handlers/RegisterHandler.java @@ -72,7 +72,7 @@ public class RegisterHandler extends MethodHandler super(userAgent, transactionManager, transportManager); } - //TODO factorize common code here and in invitehandler + //TODO factorize code.common code here and in invitehandler public synchronized ClientTransaction preProcessRegister(SipRequest sipRequest) throws SipUriSyntaxException { registered = false;