strato DDNS VBS Client

看了几款网上的DDNS Client。有些是Shareware要付费的,有些功能不符合。最后还是写了个VBS的DDNS Client。大家可以把他添加到Windows Task Scheduler里面,让它定时通过DDNS更新external的IP。

以下是给德国Strato公司配置的(其它DDNS可见最后的Comment),在使用前按需要先修改host,pass等variables:


' === settings ===
host = "<HOST>"
pass = "<PASSWORD>"
url = "https://dyndns.strato.com/nic/update?hostname=" & host & "&system=dyndns&wildcard=OFF&backmx=NO&offline=NO"
pth = "D:\ddns-client.log"

' === ddns client ===
Dim oQuery: Set oQuery = CreateObject("MSXML2.XMLHTTP.3.0")
Dim oLogger: Set oLogger = CreateObject("Scripting.FileSystemObject")

Sub Debug (pth, str)
	msg = date & " " & time & ": " & str
	Set oLogFile = oLogger.OpenTextFile(pth, 8, True, 0)
	oLogFile.Write msg	
	oLogFile.Close
End Sub

Function ResolveIP(host)
    oQuery.Open "GET", "http://ip-lookup.net/domain.php?domain=" & host, False
    oQuery.Send
    If oQuery.Status = 200 Then
        Set RegEx = New RegExp
        RegEx.Global = True
        RegEx.Pattern = "http://ip-lookup.net\?(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})"
        Set matches = RegEx.Execute(oQuery.responseText)
          If matches.Count > 0 Then
            ResolveIP = matches(0).SubMatches(0)
          End If
    End If
End Function Function GetMyIP()
    oQuery.Open "GET", "https://ip.appspot.com/", False
    oQuery.Send
    If oQuery.Status = 200 Then
        GetMyIP = Replace(Replace(oQuery.responseText, vbLf, ""), vbCr, "")
    End If
End Function Function Query(url, host, pass, ip) If ip "" Then url = url & "&myip=" & ip End If oQuery.Open "GET", url, False, host, pass oQuery.Send If oQuery.Status = 200 And (InStr(oQuery.responseText, "good") Or InStr(oQuery.responseText, "nochg")) Then Query = "ok, " & oQuery.Status & ", " & oQuery.responseText Else Query = "failed, " & oQuery.Status End If End Function ' === main === externalIp = GetMyIP() currentIp = ResolveIP(host) Debug pth, host & ": current ip=" & currentIp & ", external ip=" & externalIp If externalIp <> currentIp Then rsp = Query(url, host, pass, ip) Debug pth, rsp Else Debug pth, "ok" End If ' === list of response codes === ' good - Update successfully. ' nochg - Update successfully but the IP address have not changed. ' nohost - The hostname specified does not exist in this user account. ' abuse - The hostname specified is blocked for update abuse. ' notfqdn - The hostname specified is not a fully-qualified domain name. ' badauth - Authenticate failed. ' 911 - There is a problem or scheduled maintenance on provider side ' badagent - The user agent sent bad request(like HTTP method/parameters is not permitted) ' badresolv - Failed to connect to because failed to resolve provider address. ' badconn - Failed to connect to provider because connection timeout. ' === list of ddns providers === 'DYNDNS.org 'http://members.dyndns.org/nic/update?hostname=[HOST]&myip=[IP]&system=dyndns&wildcard=NOCHG&mx=NOCHG&backmx=NOCHG 'TwoDNS.de 'http://update.twodns.de/update.php?hostname=[HOST]&myip=[IP] 'NoIP.com 'http://dynupdate.no-ip.com/nic/update?hostname=[HOST]&myip=[IP] 'able.or.kr 'http://able.or.kr/ddns/src/update.php?hostname=[HOST]&myip=[IP]&ddnsuser=[USER]&pwd=[PASS] '3322.org 'http://www.3322.org/dyndns/update?hostname=[HOST]&system=dyndns 'selfHOST.de 'http://carol.selfhost.de/nic/update?hostname=[HOST]&myip=[IP] 'Dynamic DO!.jp 'http://free.ddo.jp/dnsupdate.php?dn=[HOST]&pw=[PASS]&ip=[IP] 'ChangeIP.com 'http://nic.ChangeIP.com/nic/update?hostname=[HOST]&myip=[IP]&system=dyndns 'DNSPod.com 'http://dnsapi.cn/Record.Modify?login_email=[USER]&login_password=[PASS]&format=xml&domain_id=[DOMAIN_ID]&record_id=[RECORD_ID]&sub_domain=[SUBDOMAIN]&record_type=A&record_line=[RECORDLINE]&value=[IP]&mx=[MX]&ttl=[TTL] 'Zoneedit.com 'http://dynamic.zoneedit.com/auth/dynamic.html?host=[HOST]&dnsto=[IP] 'Freedns.org 'http://freedns.afraid.org/dynamic/update.php?user=[FREE_DNS_SHA1]&host=[HOST]& address=[IP] 'STRATO 'http://[USER]:[PASS]@dyndns.strato.com/nic/update?hostname=[HOST]&myip=[IP]&wildcard=NOCHG&mx=NOCHG&backmx=NOCHG
Advertisements

设置Visual Studio界面语言

  1. 打开Visual Studio
  2. Tools\Options => Environment\International Settings
  3. 下载或选择英文
  4. 右键点击Visual Studio程序Icon
  5. 在target里添加”/lcid 1033″,如下
  6. “C:\Programme (x86)\Microsoft Visual Studio 11.0\Common7\IDE\devenv.exe” /lcid 1033
  7. 重新打开Visual Studio, Voilà!

取消中文Windows系统IME转换键Strg+Space

Eclipse, IntelliJ, Visual Studio等IDE里往往Strg+Space会作为Autocomplete/Autocorrection的Hotkey。而在windows系统里安装了中文IME以后这个组合键被霸占以用作为IME之间的互换。因为一个Bug这个组合键不能被修改或覆盖。

以下是把这个组合键删除的方法(适用于windows xp, vista, 7):

> regedt32

> HKEY_CURRENT_USER/Control Panel/Input Method/Hot Keys

> 选择 00000070 ("Chinese (Traditional) IME - Ime/NonIme Toggle")

> 把’Key Modifiers’的数值修改为’00 c0 00 00

> 把’Virtual Key’的数值修改为’ff 00 00 00’

> 选择 00000010("Chinese (Simplified) IME - Ime/NonIme Toggle")

> 把’Key Modifiers’的数值修改为’00 c0 00 00

> 把’Virtual Key’的数值修改为’ff 00 00 00’

 

示意图:

remove ime chinese hotkey (solution for eclipse strg+space auto-complete)
remove ime chinese hotkey (solution for eclipse strg+space auto-complete)

highcharts 1.5 ExportController.java using servlet-api-2.5

Recently we have integrated Moxie Group’s GWT Highchart in our project and ran into the conflict with ExportController’s servlet-api-3.0 multi-part issues.

Like the old GWT does, it uses and includes servlet-api-2.5 or rather jetty 7.  Fortunately our project has already got apache-fileupload in its dependency and we could use the fileitemiterator to read the multi-part items. Changes are made in processrequest(HttpServletRequest request, HttpServletResponse response) and getParameter(HttpServletRequest request, String name) Here comes the modified code:

package com.highcharts.export.controller;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.Enumeration;

import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.batik.transcoder.TranscoderException;
import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.FileItemIterator;
import org.apache.commons.fileupload.FileItemStream;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.log4j.Logger;
import org.mortbay.log.Log;

import com.highcharts.export.util.MimeType;
import com.highcharts.export.util.SVGRasterizer;
import com.highcharts.export.util.SVGRasterizerException;

public class ExportController extends HttpServlet
{
private static final long serialVersionUID = 1L;

private static final String REQUEST_METHOD_POST = "POST";

private static final String CONTENT_TYPE_MULTIPART = "multipart/";

private static final String FORBIDDEN_WORD = "<!ENTITY";

protected static Logger logger = Logger.getLogger("exportservlet");

public ExportController()
{
super();
}

public void init()
{
}

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
processrequest(request, response);
}

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
processrequest(request, response);
}

public void processrequest(HttpServletRequest request, HttpServletResponse response) throws IOException,
ServletException
{
String svg = getParameter(request, "svg");
String filename = getFilename(getParameter(request, "filename"));
Float width = getWidth(getParameter(request, "width"));
MimeType mime = getMime(getParameter(request, "type"));

try
{
boolean multi = isMultipartRequest(request);

if (multi)
{
try
{
final FileItemFactory factory = new DiskFileItemFactory();
final ServletFileUpload upload = new ServletFileUpload(factory);
final FileItemIterator filesIterator = upload.getItemIterator(request);
while (filesIterator.hasNext())
{
final FileItemStream item = filesIterator.next();
final String name = item.getFieldName();
if ("svg".equals(name))
{
svg = new String(toByteArray(item), "UTF-8");
} else if ("filename".equals(name))
{
filename = getFilename(new String(toByteArray(item), "UTF-8"));
} else if ("width".equals(name))
{
width = getWidth(new String(toByteArray(item), "UTF-8"));
} else if ("type".equals(name))
{
mime = getMime(new String(toByteArray(item), "UTF-8"));
}
}
} catch (Exception e)
{
Log.warn("Failed to parse multi-part parameter: " + e);
}
} else
{

}
if (svg == null || svg.isEmpty())
{
throw new ServletException("The required - svg - post parameter is missing");
}
if (svg.indexOf(FORBIDDEN_WORD) > -1 || svg.indexOf(FORBIDDEN_WORD.toLowerCase()) > -1)
{
throw new ServletException("The - svg - post parameter could contain a malicious attack");
}

ExportController.writeFileContentToHttpResponse(svg, filename, width, mime, response);

} catch (IOException ioe)
{
logger.error("Oops something happened here redirect to error-page, " + ioe.getMessage());
sendError(request, response, ioe);
} catch (ServletException sce)
{
logger.error("Oops something happened here redirect to error-page, " + sce.getMessage());
sendError(request, response, sce);
}
}

public static byte[] toByteArray(final FileItemStream item) throws IOException
{
final InputStream in = item.openStream();
final ByteArrayOutputStream out = new ByteArrayOutputStream();
copy(in, out);
final byte[] byteArray = out.toByteArray();
in.close();
return byteArray;
}

public static void copy(final InputStream in, final OutputStream out) throws IOException
{
final byte[] buf = new byte[1024 * 8];
while (true)
{
final int length = in.read(buf);
if (length == -1)
{
break;
}
out.write(buf, 0, length);
}
out.flush();
}

/*
* Util methods
*/

public static void writeFileContentToHttpResponse(String svg, String filename, Float width, MimeType mime,
HttpServletResponse response) throws IOException, ServletException
{

ByteArrayOutputStream stream = new ByteArrayOutputStream();

if (!MimeType.SVG.equals(mime))
{
try
{
stream = SVGRasterizer.getInstance().transcode(stream, svg, mime, width);
} catch (SVGRasterizerException sre)
{
logger.error("Error while transcoding svg file to an image", sre);
stream.close();
throw new ServletException("Error while transcoding svg file to an image");
} catch (TranscoderException te)
{
logger.error("Error while transcoding svg file to an image", te);
stream.close();
throw new ServletException("Error while transcoding svg file to an image");
}
} else
{
stream.write(svg.getBytes());
}

// prepare response
response.reset();
response.setContentLength(stream.size());
response.setCharacterEncoding("utf-8");
response.setHeader("Content-disposition", "attachment; filename=" + filename + "." + mime.name().toLowerCase());
response.setHeader("Content-type", mime.getType());
// set encoding before writing to out, check this
ServletOutputStream out = response.getOutputStream();
// Send content to Browser
out.write(stream.toByteArray());
out.flush();
}

public static final boolean isMultipartRequest(HttpServletRequest request)
{
// inspired by org.apache.commons.fileupload
logger.debug("content-type " + request.getContentType());
return REQUEST_METHOD_POST.equalsIgnoreCase(request.getMethod()) && request.getContentType() != null
&& request.getContentType().toLowerCase().startsWith(CONTENT_TYPE_MULTIPART);
}

private String getParameter(HttpServletRequest request, String name) throws IOException, ServletException
{

return request.getParameter(name);

}

private String getFilename(String name)
{
return (name != null) ? name : "chart";
}

private static Float getWidth(String width)
{
if (width != null && !width.isEmpty())
{
Float parsedWidth = Float.valueOf(width);
if (parsedWidth.compareTo(0.0F) > 0)
{
return parsedWidth;
}
}
return null;
}

private static MimeType getMime(String mime)
{
MimeType type = MimeType.get(mime);
if (type != null)
{
return type;
}
return MimeType.PNG;
}

protected void sendError(HttpServletRequest request, HttpServletResponse response, Throwable ex) throws IOException,
ServletException
{
String headers = null;
String htmlHeader =
"<HTML><HEAD><TITLE>Highcharts Export error</TITLE><style type=\"text/css\">"
+ "body {font-family: \"Trebuchet MS\", Arial, Helvetica, sans-serif;} table {border-collapse: collapse;}th {background-color:green;color:white;} td, th {border: 1px solid #98BF21;} </style></HEAD><BODY>";
String htmlFooter = "</BODY></HTML>";

response.setContentType("text/html");

PrintWriter out = response.getWriter();
Enumeration<String> e = request.getHeaderNames();
String svg = this.getParameter(request, "svg");

out.println(htmlHeader);
out.println("<h3>Error while converting SVG</h3>");
out.println("<h4>Error message</h4>");
out.println("<p>" + ex.getMessage() + "</p>");
out.println("<h4>Debug steps</h4><ol>"
+ "<li>Copy the SVG:<br/><textarea cols=100 rows=5>"
+ svg
+ "</textarea></li>"
+ "<li>Go to <a href='http://validator.w3.org/#validate_by_input' target='_blank'>validator.w3.org/#validate_by_input</a></li>"
+ "<li>Paste the SVG</li>" + "<li>Click More Options and select SVG 1.1 for Use Doctype</li>"
+ "<li>Click the Check button</li></ol>");

out.println("<h4>Request Headers</h4>");
out.println("<TABLE>");
out.println("<tr><th> Header </th><th> Value </th>");

while (e.hasMoreElements())
{
headers = (String) e.nextElement();
if (headers != null)
{
out.println("<tr><td align=center><b>" + headers + "</td>");
out.println("<td align=center>" + request.getHeader(headers) + "</td></tr>");
}
}
out.println("</TABLE><BR>");
out.println(htmlFooter);

}
}
<pre>

LDAP Java Client

package de.zf.pada.server.util;

import java.util.Hashtable;

import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;

public class LdapClient
{
  private static final String LDAP_AD_SERVER = "ldap://<server>";

  private static final String LDAP_SEARCH_BASE = "DC=,DC=";

  public static void main(String[] args)
  {
    final String user = "<user>";
    final DirContext ctx = connect("\\" + user, "<pass>");
    SearchResult r = lookup(ctx, user);
    String grp = getGroup(ctx, r);
    System.out.println("user: " + user + ", group: " + grp);
    disconnect(ctx);
  }

  public static SearchResult lookup(DirContext ctx, String acc)
  {
    String f = "(&(objectClass=user)(sAMAccountName=" + acc + "))";

    SearchControls sc = new SearchControls();
    sc.setSearchScope(SearchControls.SUBTREE_SCOPE);

    try
    {
      NamingEnumeration results = ctx.search(LDAP_SEARCH_BASE, f, sc);
      SearchResult searchResult = null;
      if (results.hasMoreElements())
      {
        searchResult = (SearchResult) results.nextElement();

        if (results.hasMoreElements())
        {
          System.err.println("Matched multiple users for the account: " + acc);
          return null;
        }
      }
      return searchResult;
    } catch (Exception e)
    {
      System.err.println("LDAP search failed: " + e);
      e.printStackTrace();
      return null;
    }

  }

  public static String getGroup(DirContext ctx, SearchResult srLdapUser)
  {
    if (srLdapUser != null)
    {
      try
      {
        final byte[] objSIDBytes = (byte[]) srLdapUser.getAttributes().get("objectSid").get();
        final String grpID = (String) srLdapUser.getAttributes().get("primaryGroupID").get();
        final String objSID = decodeSID(objSIDBytes);
        final String grpSID = objSID.substring(0, objSID.lastIndexOf('-') + 1) + grpID;

        final String f = "(&(objectClass=group)(objectSid=" + grpSID + "))";
        final SearchControls sc = new SearchControls();
        sc.setSearchScope(SearchControls.SUBTREE_SCOPE);
        final NamingEnumeration results = ctx.search(LDAP_SEARCH_BASE, f, sc);

        if (results.hasMoreElements())
        {
          SearchResult searchResult = (SearchResult) results.nextElement();

          if (results.hasMoreElements())
          {
            System.err.println("Matched multiple groups for the group with SID: " + grpSID);
          } else
          {
            return (String) searchResult.getAttributes().get("sAMAccountName").get();
          }
        }
      } catch (Exception e)
      {
        System.err.println("Failed to get group: " + e);
        e.printStackTrace();
      }
    }
    return null;
  }

  private static String decodeSID(byte[] sid)
  {

    final StringBuilder strSid = new StringBuilder("S-");
    final int revision = sid[0];
    strSid.append(Integer.toString(revision));

    final int countSubAuths = sid[1] & 0xFF;

    long authority = 0;
    for (int i = 2; i <= 7; i++)
    {
      authority |= ((long) sid[i]) << (8 * (5 - (i - 2)));
    }
    strSid.append("-");
    strSid.append(Long.toHexString(authority));

    int offset = 8;
    int size = 4;
    for (int j = 0; j < countSubAuths; j++)
    {
      long subAuthority = 0;
      for (int k = 0; k < size; k++)
      {
        subAuthority |= (long) (sid[offset + k] & 0xFF) << (8 * k);
      }

      strSid.append("-");
      strSid.append(subAuthority);

      offset += size;
    }

    return strSid.toString();
  }

  public static boolean disconnect(final DirContext ctx)
  {
    if (ctx != null)
    {
      try
      {
        ctx.close();
        return true;
      } catch (NamingException e)
      {
      }
    }
    return false;
  }

  public static DirContext connect(final String ldapUser, final String ldapPass)
  {
    try
    {
      final Hashtable<String, String> env = new Hashtable<String, String>();
      env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
      env.put(Context.PROVIDER_URL, LDAP_AD_SERVER);
      env.put(Context.SECURITY_AUTHENTICATION, "simple");
      env.put("java.naming.ldap.attributes.binary", "objectSID");
      env.put(Context.SECURITY_PRINCIPAL, ldapUser);
      env.put(Context.SECURITY_CREDENTIALS, ldapPass);
      return new InitialDirContext(env);
    } catch (Exception e)
    {
      e.printStackTrace();
      return null;
    }
  }
}

java:无边框窗口测试

以下代码演示一个focused时有边框,离开后没边框的Java窗口。

test_borderless_undecorated_java_window

import java.awt.AWTEvent;
import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.event.AWTEventListener;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.Timer;
import java.util.TimerTask;

import javax.swing.JFrame;
import javax.swing.JLabel;

public class Test
{
  private static final Timer timer = new Timer();


  public static void main(String[] args)
  {
    final JFrame frmMain = new JFrame("无边窗口测试");
    frmMain.setAlwaysOnTop(true);
    frmMain.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    final JLabel lbl = new JLabel("窗户内", JLabel.CENTER);
    lbl.setPreferredSize(new Dimension(200, 200));
    frmMain.getContentPane().add(lbl);
    frmMain.addWindowFocusListener(new WindowAdapter()
    {
      @Override
      public void windowLostFocus(WindowEvent e)
      {
        if (!frmMain.isUndecorated())
        {
          timer.schedule(new TimerTask()
          {
            @Override
            public void run()
            {
              if (!frmMain.isFocused() && !frmMain.isUndecorated())
              {
                frmMain.dispose();
                lbl.setText("窗户外");
                frmMain.setUndecorated(true);
                frmMain.setVisible(true);
              }
            }
          }, 100);
        }
      }
    });
    final long eventMask = AWTEvent.MOUSE_EVENT_MASK;
    Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener()
    {
      public void eventDispatched(AWTEvent e)
      {
        if (e.getID() == MouseEvent.MOUSE_PRESSED)
        {
          if (frmMain.isUndecorated())
          {
            timer.schedule(new TimerTask()
            {
              @Override
              public void run()
              {
                if (frmMain.isFocused() && frmMain.isUndecorated())
                {
                  frmMain.dispose();
                  lbl.setText("窗户内");
                  frmMain.setUndecorated(false);
                  frmMain.setVisible(true);
                }
              }
            }, 100);
          }
        }
      }
    }, eventMask);
    frmMain.pack();
    frmMain.setVisible(true);
  }
}

Eclipse/GWT研发模式下的服务器设置

GWT研发端口: -codeServerPort 9997

服务器端口: -port 9999

网卡绑定: -bindAddress 0.0.0.0

如:

-port 9999 -remoteUI “${gwt_remote_ui_server_port}:${unique_id}” -startupUrl AppManager.html -logLevel DEBUG -codeServerPort 9997 -war D:\dev\pada\workspace\pada\war de.zf.pada.AppManager -bindAddress 0.0.0.0 de.zf.pada.AppManager