Add NetworkTime as an application, based on Axel's original. This is mostly
based on Hamish Morrison's work on a GCI task. The changes I made from his patch were to move this from preferences to apps (I think it is more of an app than a preflet) and to change the name back to NetworkTime (he had made it NTP, but most people probably won't know what that stands for.) This also fixes #2412. I noticed some changes this could use but wanted to add it before making any changes so there is an SVN history of those changes. I'll probably also make an icon in the next few days. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@40088 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
9530027447
commit
aa252ae103
@ -36,6 +36,7 @@ HaikuSubInclude mediaconverter ;
|
||||
HaikuSubInclude mediaplayer ;
|
||||
HaikuSubInclude midiplayer ;
|
||||
HaikuSubInclude networkstatus ;
|
||||
HaikuSubInclude networktime ;
|
||||
HaikuSubInclude overlayimage ;
|
||||
HaikuSubInclude packageinstaller ;
|
||||
HaikuSubInclude packagemanager ;
|
||||
|
248
src/apps/networktime/EditServerListWindow.cpp
Normal file
248
src/apps/networktime/EditServerListWindow.cpp
Normal file
@ -0,0 +1,248 @@
|
||||
/*
|
||||
* Copyright 2004, pinc Software. All Rights Reserved.
|
||||
* Distributed under the terms of the MIT license.
|
||||
*/
|
||||
|
||||
|
||||
#include "EditServerListWindow.h"
|
||||
#include "NetworkTime.h"
|
||||
|
||||
#include <Application.h>
|
||||
#include <TextView.h>
|
||||
#include <ScrollView.h>
|
||||
#include <Button.h>
|
||||
#include <Screen.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
static const uint32 kMsgServersEdited = 'sedt';
|
||||
|
||||
static const char *kServerDelimiters = ", \n\t";
|
||||
|
||||
|
||||
struct tokens {
|
||||
char *buffer;
|
||||
char *next;
|
||||
const char *delimiters;
|
||||
};
|
||||
|
||||
|
||||
static void
|
||||
put_tokens(tokens &tokens)
|
||||
{
|
||||
free(tokens.buffer);
|
||||
tokens.buffer = NULL;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
prepare_tokens(tokens &tokens, const char *text, const char *delimiters)
|
||||
{
|
||||
tokens.buffer = strdup(text);
|
||||
if (tokens.buffer == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
tokens.delimiters = delimiters;
|
||||
tokens.next = tokens.buffer;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static const char *
|
||||
next_token(tokens &tokens)
|
||||
{
|
||||
char *token = strtok(tokens.next, tokens.delimiters);
|
||||
if (tokens.next != NULL)
|
||||
tokens.next = NULL;
|
||||
if (token == NULL)
|
||||
put_tokens(tokens);
|
||||
|
||||
return token;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
EditServerListWindow::EditServerListWindow(BRect position, const BMessage &settings)
|
||||
: BWindow(position, "Edit Server List", B_TITLED_WINDOW,
|
||||
B_ASYNCHRONOUS_CONTROLS),
|
||||
fSettings(settings)
|
||||
{
|
||||
BRect rect = Bounds();
|
||||
BView *view = new BView(rect, NULL, B_FOLLOW_ALL, B_WILL_DRAW);
|
||||
view->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
|
||||
AddChild(view);
|
||||
|
||||
rect = view->Bounds().InsetByCopy(5, 5);
|
||||
|
||||
BButton *button = new BButton(rect, "defaults", "Reset To Defaults",
|
||||
new BMessage(kMsgResetServerList), B_FOLLOW_LEFT_RIGHT | B_FOLLOW_BOTTOM);
|
||||
float width, height;
|
||||
button->GetPreferredSize(&width, &height);
|
||||
button->ResizeTo(rect.Width(), height);
|
||||
button->MoveBy(0, rect.Height() - height);
|
||||
button->SetTarget(be_app);
|
||||
view->AddChild(button);
|
||||
|
||||
rect.bottom -= 5 + height;
|
||||
rect.InsetBy(2, 2);
|
||||
rect.right -= B_V_SCROLL_BAR_WIDTH;
|
||||
|
||||
fServerView = new BTextView(rect, "list",
|
||||
rect.OffsetToCopy(B_ORIGIN).InsetByCopy(3, 3), B_FOLLOW_ALL);
|
||||
fServerView->SetStylable(true);
|
||||
|
||||
BScrollView *scrollView = new BScrollView("scroller", fServerView, B_FOLLOW_ALL, B_WILL_DRAW, false, true);
|
||||
view->AddChild(scrollView);
|
||||
|
||||
UpdateServerView(settings);
|
||||
|
||||
SetSizeLimits(200, 16384, 200, 16384);
|
||||
|
||||
if (Frame().LeftTop() == B_ORIGIN) {
|
||||
// center on screen
|
||||
BScreen screen;
|
||||
MoveTo((screen.Frame().Width() - Bounds().Width()) / 2,
|
||||
(screen.Frame().Height() - Bounds().Height()) / 2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
EditServerListWindow::~EditServerListWindow()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
EditServerListWindow::UpdateDefaultServerView(const BMessage &message)
|
||||
{
|
||||
int32 defaultServer;
|
||||
if (message.FindInt32("default server", &defaultServer) != B_OK)
|
||||
return;
|
||||
|
||||
BFont font(be_plain_font);
|
||||
fServerView->SetFontAndColor(0, fServerView->TextLength(),
|
||||
&font, B_FONT_FAMILY_AND_STYLE);
|
||||
|
||||
struct tokens tokens;
|
||||
const char *server;
|
||||
if (fSettings.FindString("server", defaultServer, &server) == B_OK
|
||||
&& prepare_tokens(tokens, fServerView->Text(), kServerDelimiters) == B_OK) {
|
||||
const char *token;
|
||||
while ((token = next_token(tokens)) != NULL) {
|
||||
if (strcasecmp(token, server))
|
||||
continue;
|
||||
|
||||
int32 start = int32(token - tokens.buffer);
|
||||
|
||||
BFont font;
|
||||
font.SetFace(B_BOLD_FACE);
|
||||
fServerView->SetFontAndColor(start, start + strlen(server),
|
||||
&font, B_FONT_FAMILY_AND_STYLE);
|
||||
|
||||
break;
|
||||
}
|
||||
put_tokens(tokens);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
EditServerListWindow::UpdateServerView(const BMessage &message)
|
||||
{
|
||||
if (message.HasString("server") || message.HasBool("reset servers"))
|
||||
fServerView->SetText("");
|
||||
|
||||
int32 defaultServer;
|
||||
if (message.FindInt32("default server", &defaultServer) != B_OK)
|
||||
defaultServer = 0;
|
||||
|
||||
const char *server;
|
||||
int32 index = 0;
|
||||
for (; message.FindString("server", index, &server) == B_OK; index++) {
|
||||
int32 start, end;
|
||||
fServerView->GetSelection(&start, &end);
|
||||
|
||||
fServerView->Insert(server);
|
||||
fServerView->Insert("\n");
|
||||
}
|
||||
|
||||
UpdateDefaultServerView(message);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
EditServerListWindow::UpdateServerList()
|
||||
{
|
||||
// get old default server
|
||||
|
||||
int32 defaultServer;
|
||||
if (fSettings.FindInt32("default server", &defaultServer) != B_OK)
|
||||
defaultServer = 0;
|
||||
const char *server;
|
||||
if (fSettings.FindString("server", defaultServer, &server) != B_OK)
|
||||
server = NULL;
|
||||
|
||||
// take over server list
|
||||
|
||||
struct tokens tokens;
|
||||
if (prepare_tokens(tokens, fServerView->Text(), kServerDelimiters) == B_OK) {
|
||||
BMessage servers(kMsgUpdateSettings);
|
||||
|
||||
int32 count = 0, newDefaultServer = -1;
|
||||
|
||||
const char *token;
|
||||
while ((token = next_token(tokens)) != NULL) {
|
||||
servers.AddString("server", token);
|
||||
if (!strcasecmp(token, server))
|
||||
newDefaultServer = count;
|
||||
|
||||
count++;
|
||||
}
|
||||
|
||||
if (count != 0) {
|
||||
if (newDefaultServer == -1)
|
||||
newDefaultServer = 0;
|
||||
|
||||
servers.AddInt32("default server", newDefaultServer);
|
||||
be_app->PostMessage(&servers);
|
||||
} else
|
||||
be_app->PostMessage(kMsgResetServerList);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
EditServerListWindow::QuitRequested()
|
||||
{
|
||||
be_app->PostMessage(kMsgEditServerListWindowClosed);
|
||||
|
||||
BMessage update(kMsgUpdateSettings);
|
||||
update.AddRect("edit servers frame", Frame());
|
||||
be_app->PostMessage(&update);
|
||||
|
||||
UpdateServerList();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
EditServerListWindow::MessageReceived(BMessage *message)
|
||||
{
|
||||
switch (message->what) {
|
||||
case kMsgServersEdited:
|
||||
UpdateServerList();
|
||||
break;
|
||||
|
||||
case kMsgSettingsUpdated:
|
||||
if (message->HasString("server"))
|
||||
UpdateServerView(*message);
|
||||
else
|
||||
UpdateDefaultServerView(*message);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
32
src/apps/networktime/EditServerListWindow.h
Normal file
32
src/apps/networktime/EditServerListWindow.h
Normal file
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright 2004, pinc Software. All Rights Reserved.
|
||||
* Distributed under the terms of the MIT license.
|
||||
*/
|
||||
#ifndef EDIT_SERVER_LIST_WINDOW_H
|
||||
#define EDIT_SERVER_LIST_WINDOW_H
|
||||
|
||||
|
||||
#include <Window.h>
|
||||
|
||||
class BTextView;
|
||||
|
||||
|
||||
class EditServerListWindow : public BWindow {
|
||||
public:
|
||||
EditServerListWindow(BRect position, const BMessage &settings);
|
||||
virtual ~EditServerListWindow();
|
||||
|
||||
virtual bool QuitRequested();
|
||||
virtual void MessageReceived(BMessage *message);
|
||||
|
||||
private:
|
||||
void UpdateDefaultServerView(const BMessage &message);
|
||||
void UpdateServerView(const BMessage &message);
|
||||
|
||||
void UpdateServerList();
|
||||
|
||||
const BMessage &fSettings;
|
||||
BTextView *fServerView;
|
||||
};
|
||||
|
||||
#endif /* EDIT_SERVER_LIST_WINDOW_H */
|
21
src/apps/networktime/Jamfile
Normal file
21
src/apps/networktime/Jamfile
Normal file
@ -0,0 +1,21 @@
|
||||
SubDir HAIKU_TOP src apps networktime ;
|
||||
|
||||
Application NetworkTime :
|
||||
EditServerListWindow.cpp
|
||||
NetworkTime.cpp
|
||||
ntp.cpp
|
||||
UpdateWindow.cpp
|
||||
$(DRIVER_SETTINGS)
|
||||
|
||||
: be $(TARGET_LIBSTDC++) $(HAIKU_LOCALE_LIBS) $(HAIKU_NETWORK_LIBS)
|
||||
: NetworkTime.rdef
|
||||
;
|
||||
|
||||
DoCatalogs NetworkTime :
|
||||
x-vnd.Haiku-NetworkTime
|
||||
:
|
||||
EditServerListWindow.cpp
|
||||
NetworkTime.cpp
|
||||
ntp.cpp
|
||||
UpdateWindow.cpp
|
||||
;
|
54
src/apps/networktime/Monitor.h
Normal file
54
src/apps/networktime/Monitor.h
Normal file
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright 2004, pinc Software. All Rights Reserved.
|
||||
* Distributed under the terms of the MIT license.
|
||||
*/
|
||||
#ifndef MONITOR_H
|
||||
#define MONITOR_H
|
||||
|
||||
|
||||
#include <SupportDefs.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
|
||||
class Monitor {
|
||||
public:
|
||||
virtual ~Monitor() {}
|
||||
|
||||
virtual void Update(const char *text, ...);
|
||||
virtual void Update(float progress, const char *text = NULL, ...);
|
||||
|
||||
virtual void Done(status_t status);
|
||||
|
||||
private:
|
||||
virtual void update(float progress, const char *text, va_list args) = 0;
|
||||
};
|
||||
|
||||
|
||||
inline void
|
||||
Monitor::Update(const char *text, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
va_start(args, text);
|
||||
update(-1.f, text, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
|
||||
inline void
|
||||
Monitor::Update(float progress, const char *text, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
va_start(args, text);
|
||||
update(progress, text, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
|
||||
inline void
|
||||
Monitor::Done(status_t /*status*/)
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* MONITOR_H */
|
670
src/apps/networktime/NetworkTime.cpp
Normal file
670
src/apps/networktime/NetworkTime.cpp
Normal file
@ -0,0 +1,670 @@
|
||||
/*
|
||||
* Copyright 2004, pinc Software. All Rights Reserved.
|
||||
* Distributed under the terms of the MIT license.
|
||||
*/
|
||||
|
||||
|
||||
#include "NetworkTime.h"
|
||||
#include "UpdateWindow.h"
|
||||
#include "EditServerListWindow.h"
|
||||
#include "ntp.h"
|
||||
|
||||
#include <Application.h>
|
||||
#include <Path.h>
|
||||
#include <File.h>
|
||||
#include <FindDirectory.h>
|
||||
#include <Alert.h>
|
||||
#include <TextView.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <getopt.h>
|
||||
#include <ctype.h>
|
||||
|
||||
|
||||
status_t update_time(const BMessage &settings, Monitor *monitor);
|
||||
status_t update_time(const BMessage &server, Monitor *monitor, thread_id *_asyncThread);
|
||||
|
||||
|
||||
static const uint32 kMsgNetworkTimeSettings = 'NtpS';
|
||||
|
||||
extern const char *__progname;
|
||||
static const char *sProgramName = __progname;
|
||||
|
||||
|
||||
class Settings {
|
||||
public:
|
||||
Settings();
|
||||
~Settings();
|
||||
|
||||
void CopyMessage(BMessage &message) const;
|
||||
const BMessage &Message() const;
|
||||
void UpdateFrom(BMessage &message);
|
||||
|
||||
void ResetServersToDefaults();
|
||||
void ResetToDefaults();
|
||||
status_t Load();
|
||||
status_t Save();
|
||||
|
||||
private:
|
||||
status_t GetPath(BPath &path);
|
||||
|
||||
BMessage fMessage;
|
||||
bool fWasUpdated;
|
||||
};
|
||||
|
||||
|
||||
class PrintMonitor : public Monitor {
|
||||
private:
|
||||
virtual void
|
||||
update(float progress, const char *text, va_list args)
|
||||
{
|
||||
if (progress != -1.f)
|
||||
printf("%3g%% ", progress);
|
||||
else
|
||||
printf(" ");
|
||||
|
||||
if (text != NULL)
|
||||
vprintf(text, args);
|
||||
|
||||
putchar('\n');
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class MessengerMonitor : public Monitor {
|
||||
public:
|
||||
MessengerMonitor(BMessenger messenger)
|
||||
:
|
||||
fMessenger(messenger)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void
|
||||
Done(status_t status)
|
||||
{
|
||||
BMessage message(kMsgStatusUpdate);
|
||||
message.AddInt32("status", status);
|
||||
|
||||
fMessenger.SendMessage(&message);
|
||||
fMessenger.SendMessage(kMsgStopTimeUpdate);
|
||||
|
||||
// This deadlocks Dano
|
||||
//be_app_messenger.SendMessage(kMsgStopTimeUpdate);
|
||||
}
|
||||
|
||||
private:
|
||||
virtual void
|
||||
update(float progress, const char *text, va_list args)
|
||||
{
|
||||
BMessage message(kMsgStatusUpdate);
|
||||
if (progress != -1.f)
|
||||
message.AddFloat("progress", progress);
|
||||
|
||||
if (text != NULL) {
|
||||
char buffer[2048];
|
||||
vsprintf(buffer, text, args);
|
||||
message.AddString("message", buffer);
|
||||
}
|
||||
|
||||
fMessenger.SendMessage(&message);
|
||||
}
|
||||
|
||||
BMessenger fMessenger;
|
||||
};
|
||||
|
||||
|
||||
class NetworkTimeApplication : public BApplication {
|
||||
public:
|
||||
NetworkTimeApplication(Settings &settings);
|
||||
virtual ~NetworkTimeApplication();
|
||||
|
||||
virtual void ReadyToRun();
|
||||
virtual void MessageReceived(BMessage *message);
|
||||
virtual void AboutRequested();
|
||||
|
||||
void BroadcastSettingsChanges(BMessage &message);
|
||||
|
||||
private:
|
||||
Settings &fSettings;
|
||||
thread_id fUpdateThread;
|
||||
BWindow *fServerListWindow;
|
||||
};
|
||||
|
||||
|
||||
status_t
|
||||
adopt_int32(const BMessage &from, BMessage &to, const char *name, bool &updated)
|
||||
{
|
||||
int32 value;
|
||||
if (from.FindInt32(name, &value) != B_OK)
|
||||
return B_ENTRY_NOT_FOUND;
|
||||
|
||||
int32 original;
|
||||
if (to.FindInt32(name, &original) == B_OK) {
|
||||
if (value == original)
|
||||
return B_OK;
|
||||
|
||||
updated = true;
|
||||
return to.ReplaceInt32(name, value);
|
||||
}
|
||||
|
||||
updated = true;
|
||||
return to.AddInt32(name, value);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
adopt_bool(const BMessage &from, BMessage &to, const char *name, bool &updated)
|
||||
{
|
||||
bool value;
|
||||
if (from.FindBool(name, &value) != B_OK)
|
||||
return B_ENTRY_NOT_FOUND;
|
||||
|
||||
bool original;
|
||||
if (to.FindBool(name, &original) == B_OK) {
|
||||
if (value == original)
|
||||
return B_OK;
|
||||
|
||||
updated = true;
|
||||
return to.ReplaceBool(name, value);
|
||||
}
|
||||
|
||||
updated = true;
|
||||
return to.AddBool(name, value);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
adopt_rect(const BMessage &from, BMessage &to, const char *name, bool &updated)
|
||||
{
|
||||
BRect rect;
|
||||
if (from.FindRect(name, &rect) != B_OK)
|
||||
return B_ENTRY_NOT_FOUND;
|
||||
|
||||
BRect original;
|
||||
if (to.FindRect(name, &original) == B_OK) {
|
||||
if (rect == original)
|
||||
return B_OK;
|
||||
|
||||
updated = true;
|
||||
return to.ReplaceRect(name, rect);
|
||||
}
|
||||
|
||||
updated = true;
|
||||
return to.AddRect(name, rect);
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
class UpdateLooper : public BLooper {
|
||||
public:
|
||||
UpdateLooper(const BMessage &settings, Monitor *monitor);
|
||||
|
||||
void MessageReceived(BMessage *message);
|
||||
|
||||
private:
|
||||
const BMessage &fSettings;
|
||||
Monitor *fMonitor;
|
||||
};
|
||||
|
||||
|
||||
UpdateLooper::UpdateLooper(const BMessage &settings, Monitor *monitor)
|
||||
: BLooper("update looper"),
|
||||
fSettings(settings),
|
||||
fMonitor(monitor)
|
||||
{
|
||||
PostMessage(kMsgUpdateTime);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
UpdateLooper::MessageReceived(BMessage *message)
|
||||
{
|
||||
if (message->what != kMsgUpdateTime)
|
||||
return;
|
||||
|
||||
update_time(fSettings, fMonitor);
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
NetworkTimeApplication::NetworkTimeApplication(Settings &settings)
|
||||
: BApplication("application/x-vnd.Haiku-NetworkTime"),
|
||||
fSettings(settings),
|
||||
fUpdateThread(-1),
|
||||
fServerListWindow(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
NetworkTimeApplication::~NetworkTimeApplication()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
NetworkTimeApplication::ReadyToRun()
|
||||
{
|
||||
BRect rect;
|
||||
if (fSettings.Message().FindRect("status frame", &rect) != B_OK)
|
||||
rect.Set(0, 0, 300, 150);
|
||||
|
||||
UpdateWindow *window = new UpdateWindow(rect, fSettings.Message());
|
||||
window->Show();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
NetworkTimeApplication::BroadcastSettingsChanges(BMessage &message)
|
||||
{
|
||||
BWindow *window;
|
||||
int32 index = 0;
|
||||
while ((window = WindowAt(index++)) != NULL)
|
||||
window->PostMessage(&message);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
NetworkTimeApplication::MessageReceived(BMessage *message)
|
||||
{
|
||||
switch (message->what) {
|
||||
case kMsgUpdateSettings:
|
||||
{
|
||||
fSettings.UpdateFrom(*message);
|
||||
|
||||
message->what = kMsgSettingsUpdated;
|
||||
BroadcastSettingsChanges(*message);
|
||||
break;
|
||||
}
|
||||
|
||||
case kMsgResetServerList:
|
||||
{
|
||||
fSettings.ResetServersToDefaults();
|
||||
|
||||
BMessage updated = fSettings.Message();
|
||||
updated.what = kMsgSettingsUpdated;
|
||||
|
||||
BroadcastSettingsChanges(updated);
|
||||
break;
|
||||
}
|
||||
|
||||
case kMsgStopTimeUpdate:
|
||||
if (fUpdateThread >= B_OK)
|
||||
kill_thread(fUpdateThread);
|
||||
|
||||
fUpdateThread = -1;
|
||||
break;
|
||||
|
||||
case kMsgUpdateTime:
|
||||
{
|
||||
if (fUpdateThread >= B_OK)
|
||||
break;
|
||||
|
||||
MessengerMonitor *monitor = NULL;
|
||||
BMessenger messenger;
|
||||
if (message->FindMessenger("monitor", &messenger) == B_OK)
|
||||
monitor = new MessengerMonitor(messenger);
|
||||
|
||||
update_time(fSettings.Message(), monitor, &fUpdateThread);
|
||||
break;
|
||||
}
|
||||
|
||||
case kMsgEditServerList:
|
||||
if (fServerListWindow == NULL) {
|
||||
BRect rect;
|
||||
if (fSettings.Message().FindRect("edit servers frame", &rect) != B_OK)
|
||||
rect.Set(0, 0, 250, 250);
|
||||
fServerListWindow = new EditServerListWindow(rect, fSettings.Message());
|
||||
}
|
||||
|
||||
fServerListWindow->Show();
|
||||
break;
|
||||
|
||||
case kMsgEditServerListWindowClosed:
|
||||
fServerListWindow = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
NetworkTimeApplication::AboutRequested()
|
||||
{
|
||||
BAlert *alert = new BAlert("about", "Network Time\n"
|
||||
"\twritten by Axel Dörfler\n\n"
|
||||
"\tCopyright " B_UTF8_COPYRIGHT "2004, pinc Software.\n"
|
||||
"\tAll Rights Reserved.\n", "Ok");
|
||||
BTextView *view = alert->TextView();
|
||||
BFont font;
|
||||
|
||||
view->SetStylable(true);
|
||||
|
||||
view->GetFont(&font);
|
||||
font.SetSize(18);
|
||||
font.SetFace(B_BOLD_FACE);
|
||||
view->SetFontAndColor(0, 12, &font);
|
||||
|
||||
alert->Go();
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
Settings::Settings()
|
||||
:
|
||||
fMessage(kMsgNetworkTimeSettings),
|
||||
fWasUpdated(false)
|
||||
{
|
||||
ResetToDefaults();
|
||||
Load();
|
||||
}
|
||||
|
||||
|
||||
Settings::~Settings()
|
||||
{
|
||||
if (fWasUpdated)
|
||||
Save();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Settings::CopyMessage(BMessage &message) const
|
||||
{
|
||||
message = fMessage;
|
||||
}
|
||||
|
||||
|
||||
const BMessage &
|
||||
Settings::Message() const
|
||||
{
|
||||
return fMessage;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Settings::UpdateFrom(BMessage &message)
|
||||
{
|
||||
if (message.HasBool("reset servers")) {
|
||||
fMessage.RemoveName("server");
|
||||
fWasUpdated = true;
|
||||
}
|
||||
|
||||
if (message.HasString("server")) {
|
||||
// remove old servers
|
||||
fMessage.RemoveName("server");
|
||||
|
||||
const char *server;
|
||||
int32 index = 0;
|
||||
while (message.FindString("server", index++, &server) == B_OK) {
|
||||
fMessage.AddString("server", server);
|
||||
}
|
||||
|
||||
fWasUpdated = true;
|
||||
}
|
||||
|
||||
adopt_int32(message, fMessage, "default server", fWasUpdated);
|
||||
|
||||
adopt_bool(message, fMessage, "auto mode", fWasUpdated);
|
||||
adopt_bool(message, fMessage, "knows auto mode", fWasUpdated);
|
||||
adopt_bool(message, fMessage, "try all servers", fWasUpdated);
|
||||
adopt_bool(message, fMessage, "choose default server", fWasUpdated);
|
||||
|
||||
adopt_rect(message, fMessage, "status frame", fWasUpdated);
|
||||
adopt_rect(message, fMessage, "edit servers frame", fWasUpdated);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Settings::ResetServersToDefaults()
|
||||
{
|
||||
fMessage.RemoveName("server");
|
||||
|
||||
fMessage.AddString("server", "pool.ntp.org");
|
||||
fMessage.AddString("server", "de.pool.ntp.org");
|
||||
fMessage.AddString("server", "time.nist.gov");
|
||||
|
||||
if (fMessage.ReplaceInt32("default server", 0) != B_OK)
|
||||
fMessage.AddInt32("default server", 0);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Settings::ResetToDefaults()
|
||||
{
|
||||
fMessage.MakeEmpty();
|
||||
ResetServersToDefaults();
|
||||
|
||||
fMessage.AddBool("knows auto mode", false);
|
||||
fMessage.AddBool("auto mode", false);
|
||||
fMessage.AddBool("try all servers", true);
|
||||
fMessage.AddBool("choose default server", true);
|
||||
|
||||
fMessage.AddRect("status frame", BRect(0, 0, 300, 150));
|
||||
fMessage.AddRect("edit servers frame", BRect(0, 0, 250, 250));
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Settings::Load()
|
||||
{
|
||||
status_t status;
|
||||
|
||||
BPath path;
|
||||
if ((status = GetPath(path)) != B_OK)
|
||||
return status;
|
||||
|
||||
BFile file(path.Path(), B_READ_ONLY);
|
||||
if ((status = file.InitCheck()) != B_OK)
|
||||
return status;
|
||||
|
||||
BMessage load;
|
||||
if ((status = load.Unflatten(&file)) != B_OK)
|
||||
return status;
|
||||
|
||||
if (load.what != kMsgNetworkTimeSettings)
|
||||
return B_BAD_TYPE;
|
||||
|
||||
fMessage = load;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Settings::Save()
|
||||
{
|
||||
status_t status;
|
||||
|
||||
BPath path;
|
||||
if ((status = GetPath(path)) != B_OK)
|
||||
return status;
|
||||
|
||||
BFile file(path.Path(), B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE);
|
||||
if ((status = file.InitCheck()) != B_OK)
|
||||
return status;
|
||||
|
||||
file.SetSize(0);
|
||||
|
||||
return fMessage.Flatten(&file);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Settings::GetPath(BPath &path)
|
||||
{
|
||||
status_t status;
|
||||
if ((status = find_directory(B_USER_SETTINGS_DIRECTORY, &path)) != B_OK)
|
||||
return status;
|
||||
|
||||
path.Append("pinc.networktime settings");
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
status_t
|
||||
update_time(const BMessage &settings, Monitor *monitor)
|
||||
{
|
||||
int32 defaultServer;
|
||||
if (settings.FindInt32("default server", &defaultServer) != B_OK)
|
||||
defaultServer = 0;
|
||||
|
||||
status_t status = B_ENTRY_NOT_FOUND;
|
||||
const char *server;
|
||||
if (settings.FindString("server", defaultServer, &server) == B_OK)
|
||||
status = ntp_update_time(server, monitor);
|
||||
|
||||
// try other servers if we should
|
||||
if (status != B_OK && settings.FindBool("try all servers")) {
|
||||
for (int32 index = 0; ; index++) {
|
||||
if (index == defaultServer)
|
||||
index++;
|
||||
if (settings.FindString("server", index, &server) != B_OK)
|
||||
break;
|
||||
|
||||
status = ntp_update_time(server, monitor);
|
||||
if (status == B_OK) {
|
||||
if (be_app != NULL && settings.FindBool("choose default server")) {
|
||||
BMessage update(kMsgUpdateSettings);
|
||||
update.AddInt32("default server", index);
|
||||
be_app->PostMessage(&update);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (monitor != NULL)
|
||||
monitor->Done(status);
|
||||
|
||||
delete monitor;
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
update_time(const BMessage &settings, Monitor *monitor, thread_id *_asyncThread)
|
||||
{
|
||||
if (_asyncThread != NULL) {
|
||||
BLooper *looper = new UpdateLooper(settings, monitor);
|
||||
*_asyncThread = looper->Run();
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
return update_time(settings, monitor);
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
parse_time(char *arg, int32 *_seconds)
|
||||
{
|
||||
char *unit;
|
||||
|
||||
if (isdigit(arg[0]))
|
||||
*_seconds = strtoul(arg, &unit, 10);
|
||||
else
|
||||
return false;
|
||||
|
||||
if (unit[0] == '\0' || !strcmp(unit, "m")) {
|
||||
*_seconds *= 60;
|
||||
return true;
|
||||
}
|
||||
if (!strcmp(unit, "h")) {
|
||||
*_seconds *= 60 * 60;
|
||||
return true;
|
||||
}
|
||||
if (!strcmp(unit, "s"))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
usage(void)
|
||||
{
|
||||
fprintf(stderr, "usage: %s [-s|--server <host>] [-p|--periodic <interval>] [-n|--silent] [-g|--nogui]\n"
|
||||
" -s, --server\t\tContact \"host\" instead of saved list\n"
|
||||
" -p, --periodic\tPeriodically query for the time, interval specified in minutes\n"
|
||||
" -n, --silent\t\tDo not print progress\n"
|
||||
" -g, --nogui\t\tDo not show graphical user interface (implied by other options)\n",
|
||||
sProgramName);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
Settings settings;
|
||||
|
||||
if (argc > 1) {
|
||||
// when there are any command line options, we will switch to command line mode
|
||||
|
||||
BMessage message;
|
||||
settings.CopyMessage(message);
|
||||
// we may want to override the global settings with command line options
|
||||
|
||||
static struct option const longopts[] = {
|
||||
{"server", required_argument, NULL, 's'},
|
||||
{"periodic", required_argument, NULL, 'p'},
|
||||
{"silent", no_argument, NULL, 'n'},
|
||||
{"nogui", no_argument, NULL, 'g'},
|
||||
{"help", no_argument, NULL, 'h'},
|
||||
{NULL, 0, NULL, 0}
|
||||
};
|
||||
|
||||
int32 interval = 0;
|
||||
bool silent = false;
|
||||
|
||||
char option;
|
||||
while ((option = getopt_long(argc, argv, "s:p:h", longopts, NULL)) != -1) {
|
||||
switch (option) {
|
||||
case 's':
|
||||
message.RemoveName("server");
|
||||
message.AddString("server", optarg);
|
||||
message.ReplaceInt32("default server", 0);
|
||||
break;
|
||||
case 'n':
|
||||
silent = true;
|
||||
break;
|
||||
case 'g':
|
||||
// default in command line mode
|
||||
break;
|
||||
case 'p':
|
||||
if (parse_time(optarg, &interval))
|
||||
break;
|
||||
// supposed to fall through
|
||||
case 'h':
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
}
|
||||
|
||||
while (true) {
|
||||
Monitor *monitor = NULL;
|
||||
if (!silent)
|
||||
monitor = new PrintMonitor();
|
||||
|
||||
update_time(message, monitor, NULL);
|
||||
|
||||
if (interval == 0)
|
||||
break;
|
||||
|
||||
snooze(interval * 1000000LL);
|
||||
}
|
||||
} else {
|
||||
NetworkTimeApplication app(settings);
|
||||
app.Run();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
22
src/apps/networktime/NetworkTime.h
Normal file
22
src/apps/networktime/NetworkTime.h
Normal file
@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright 2004, pinc Software. All Rights Reserved.
|
||||
* Distributed under the terms of the MIT license.
|
||||
*/
|
||||
#ifndef NETWORK_TIME_H
|
||||
#define NETWORK_TIME_H
|
||||
|
||||
|
||||
#include <SupportDefs.h>
|
||||
|
||||
|
||||
static const uint32 kMsgUpdateTime = 'uptm';
|
||||
static const uint32 kMsgStopTimeUpdate = 'stpt';
|
||||
static const uint32 kMsgStatusUpdate = 'stup';
|
||||
static const uint32 kMsgUpdateSettings = 'upse';
|
||||
static const uint32 kMsgSettingsUpdated = 'seUp';
|
||||
static const uint32 kMsgResetServerList = 'rtsl';
|
||||
|
||||
static const uint32 kMsgEditServerList = 'edsl';
|
||||
static const uint32 kMsgEditServerListWindowClosed = 'eswc';
|
||||
|
||||
#endif /* NETWORK_TIME_H */
|
19
src/apps/networktime/NetworkTime.rdef
Normal file
19
src/apps/networktime/NetworkTime.rdef
Normal file
@ -0,0 +1,19 @@
|
||||
|
||||
resource app_signature "application/x-vnd.Haiku-NetworkTime";
|
||||
|
||||
resource app_version {
|
||||
major = 1,
|
||||
middle = 0,
|
||||
minor = 0,
|
||||
|
||||
/* 0 = development 1 = alpha 2 = beta
|
||||
3 = gamma 4 = golden master 5 = final */
|
||||
variety = 2,
|
||||
|
||||
internal = 0,
|
||||
|
||||
short_info = "NetworkTime",
|
||||
long_info = "NetworkTime ©2004 pinc Software"
|
||||
};
|
||||
|
||||
resource app_flags B_SINGLE_LAUNCH;
|
303
src/apps/networktime/UpdateWindow.cpp
Normal file
303
src/apps/networktime/UpdateWindow.cpp
Normal file
@ -0,0 +1,303 @@
|
||||
/*
|
||||
* Copyright 2004, pinc Software. All Rights Reserved.
|
||||
* Distributed under the terms of the MIT license.
|
||||
*/
|
||||
|
||||
|
||||
#include "UpdateWindow.h"
|
||||
#include "NetworkTime.h"
|
||||
|
||||
#include <Application.h>
|
||||
#include <MenuBar.h>
|
||||
#include <MenuItem.h>
|
||||
#include <StatusBar.h>
|
||||
#include <Button.h>
|
||||
#include <Alert.h>
|
||||
#include <Screen.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
static const uint32 kMsgAutoMode = 'aumd';
|
||||
static const uint32 kMsgTryAllServers = 'tasr';
|
||||
static const uint32 kMsgChooseDefaultServer = 'cdsr';
|
||||
static const uint32 kMsgDefaultServer = 'dsrv';
|
||||
|
||||
|
||||
UpdateWindow::UpdateWindow(BRect position, const BMessage &settings)
|
||||
: BWindow(position, "Network Time", B_TITLED_WINDOW,
|
||||
B_NOT_ZOOMABLE | B_NOT_RESIZABLE | B_ASYNCHRONOUS_CONTROLS),
|
||||
fSettings(settings)
|
||||
{
|
||||
bool autoMode;
|
||||
if (settings.FindBool("auto mode", &autoMode) != B_OK)
|
||||
autoMode = false;
|
||||
|
||||
// pressing the control key will avoid auto quit
|
||||
fAutoQuit = modifiers() & B_CONTROL_KEY ? false : autoMode;
|
||||
bool showMenu = !fAutoQuit;
|
||||
|
||||
BMenuBar *bar = new BMenuBar(Bounds(), "");
|
||||
BMenu *menu;
|
||||
BMenuItem *item;
|
||||
|
||||
menu = new BMenu("Project");
|
||||
|
||||
menu->AddItem(item = new BMenuItem("About" B_UTF8_ELLIPSIS, new BMessage(B_ABOUT_REQUESTED), '?'));
|
||||
item->SetTarget(be_app);
|
||||
menu->AddItem(new BMenuItem("Quit", new BMessage(B_QUIT_REQUESTED), 'Q'));
|
||||
bar->AddItem(menu);
|
||||
|
||||
fServerMenu = new BMenu("Servers");
|
||||
fServerMenu->SetRadioMode(true);
|
||||
BuildServerMenu();
|
||||
|
||||
menu = new BMenu("Options");
|
||||
menu->AddItem(fTryAllServersItem = new BMenuItem("Try All Servers",
|
||||
new BMessage(kMsgTryAllServers)));
|
||||
menu->AddItem(fChooseDefaultServerItem = new BMenuItem("Choose Default Server Automatically",
|
||||
new BMessage(kMsgChooseDefaultServer)));
|
||||
menu->AddItem(fAutoModeItem = new BMenuItem("Auto Mode", new BMessage(kMsgAutoMode)));
|
||||
menu->AddSeparatorItem();
|
||||
menu->AddItem(fServerMenu);
|
||||
menu->AddItem(new BMenuItem("Edit Server List" B_UTF8_ELLIPSIS, new BMessage(kMsgEditServerList)));
|
||||
bar->AddItem(menu);
|
||||
|
||||
if (showMenu)
|
||||
AddChild(bar);
|
||||
|
||||
BRect rect = Bounds();
|
||||
if (showMenu)
|
||||
rect.top = bar->Bounds().Height();
|
||||
|
||||
BView *view = new BView(rect, NULL, B_FOLLOW_ALL, B_WILL_DRAW);
|
||||
view->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
|
||||
AddChild(view);
|
||||
|
||||
rect = view->Bounds().InsetByCopy(5, 5);
|
||||
fStatusBar = new BStatusBar(rect, "status", NULL, NULL);
|
||||
float width, height;
|
||||
fStatusBar->GetPreferredSize(&width, &height);
|
||||
fStatusBar->ResizeTo(rect.Width(), height);
|
||||
fStatusBar->SetResizingMode(B_FOLLOW_TOP | B_FOLLOW_LEFT_RIGHT);
|
||||
view->AddChild(fStatusBar);
|
||||
|
||||
BMessage *buttonMessage = new BMessage(fAutoQuit ? kMsgStopTimeUpdate : kMsgUpdateTime);
|
||||
buttonMessage->AddMessenger("monitor", this);
|
||||
|
||||
if (showMenu) {
|
||||
rect.top += height + 4;
|
||||
fButton = new BButton(rect, NULL, "Update", buttonMessage,
|
||||
B_FOLLOW_TOP | B_FOLLOW_LEFT_RIGHT);
|
||||
fButton->ResizeToPreferred();
|
||||
if (autoMode)
|
||||
fButton->SetLabel("Stop");
|
||||
fButton->MoveBy((rect.Width() - fButton->Bounds().Width()) / 2, 0);
|
||||
view->AddChild(fButton);
|
||||
|
||||
ResizeTo(Bounds().Width(),
|
||||
bar->Bounds().Height() + fButton->Frame().bottom + 5);
|
||||
} else {
|
||||
fButton = NULL;
|
||||
ResizeTo(Bounds().Width(), height + 9);
|
||||
}
|
||||
|
||||
SetSizeLimits(200, 16384, Bounds().Height(), Bounds().Height());
|
||||
|
||||
if (Frame().LeftTop() == B_ORIGIN) {
|
||||
// center on screen
|
||||
BScreen screen;
|
||||
MoveTo((screen.Frame().Width() - Bounds().Width()) / 2,
|
||||
(screen.Frame().Height() - Bounds().Height()) / 2);
|
||||
}
|
||||
|
||||
// Update views
|
||||
BMessage update = fSettings;
|
||||
update.what = kMsgSettingsUpdated;
|
||||
PostMessage(&update);
|
||||
|
||||
// Automatically start update in "auto mode"
|
||||
if (fAutoQuit) {
|
||||
BMessage update(kMsgUpdateTime);
|
||||
update.AddMessenger("monitor", this);
|
||||
|
||||
be_app->PostMessage(&update);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
UpdateWindow::~UpdateWindow()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
UpdateWindow::QuitRequested()
|
||||
{
|
||||
BMessage update(kMsgUpdateSettings);
|
||||
update.AddRect("status frame", Frame());
|
||||
be_app_messenger.SendMessage(&update);
|
||||
|
||||
be_app->PostMessage(B_QUIT_REQUESTED);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
UpdateWindow::BuildServerMenu()
|
||||
{
|
||||
// remove old entries
|
||||
BMenuItem *item;
|
||||
while ((item = fServerMenu->RemoveItem(0L)) != NULL)
|
||||
delete item;
|
||||
|
||||
int32 defaultServer;
|
||||
if (fSettings.FindInt32("default server", &defaultServer) != B_OK)
|
||||
defaultServer = 0;
|
||||
|
||||
const char *server;
|
||||
for (int32 i = 0; fSettings.FindString("server", i, &server) == B_OK; i++) {
|
||||
fServerMenu->AddItem(item = new BMenuItem(server, new BMessage(kMsgDefaultServer)));
|
||||
if (i == defaultServer)
|
||||
item->SetMarked(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
UpdateWindow::MessageReceived(BMessage *message)
|
||||
{
|
||||
switch (message->what) {
|
||||
case kMsgSettingsUpdated:
|
||||
{
|
||||
if (message->HasString("server"))
|
||||
BuildServerMenu();
|
||||
else {
|
||||
int32 index;
|
||||
if (message->FindInt32("default server", &index) == B_OK) {
|
||||
BMenuItem *item = fServerMenu->ItemAt(index);
|
||||
if (item != NULL)
|
||||
item->SetMarked(true);
|
||||
}
|
||||
}
|
||||
|
||||
bool boolean;
|
||||
if (message->FindBool("auto mode", &boolean) == B_OK)
|
||||
fAutoModeItem->SetMarked(boolean);
|
||||
if (message->FindBool("try all servers", &boolean) == B_OK)
|
||||
fTryAllServersItem->SetMarked(boolean);
|
||||
if (message->FindBool("choose default server", &boolean) == B_OK)
|
||||
fChooseDefaultServerItem->SetMarked(boolean);
|
||||
break;
|
||||
}
|
||||
|
||||
case kMsgAutoMode:
|
||||
{
|
||||
fAutoModeItem->SetMarked(!fAutoModeItem->IsMarked());
|
||||
|
||||
if (!fSettings.FindBool("knows auto mode")) {
|
||||
// we should alert the user about the changed behaviour
|
||||
(new BAlert("notice",
|
||||
"Attention!\n\n"
|
||||
"Activating this mode let's the user interface only show the "
|
||||
"bare minimum, and you will not be able to reach the menu "
|
||||
"anymore.\n"
|
||||
"Also, the application will quit immediately after the time has "
|
||||
"been updated successfully; it will only stay if updating fails, "
|
||||
"so that you can catch the reason for the error.\n\n"
|
||||
"If you want to get the full interface again, you have to "
|
||||
"press the control key while starting this application.\n\n"
|
||||
"This warning will appear only the first time you select this mode.",
|
||||
"Ok"))->Go();
|
||||
}
|
||||
|
||||
BMessage update(kMsgUpdateSettings);
|
||||
update.AddBool("auto mode", fAutoModeItem->IsMarked());
|
||||
update.AddBool("knows auto mode", true);
|
||||
be_app->PostMessage(&update);
|
||||
break;
|
||||
}
|
||||
|
||||
case kMsgTryAllServers:
|
||||
{
|
||||
fTryAllServersItem->SetMarked(!fTryAllServersItem->IsMarked());
|
||||
|
||||
BMessage update(kMsgUpdateSettings);
|
||||
update.AddBool("try all servers", fTryAllServersItem->IsMarked());
|
||||
be_app->PostMessage(&update);
|
||||
break;
|
||||
}
|
||||
|
||||
case kMsgChooseDefaultServer:
|
||||
{
|
||||
fChooseDefaultServerItem->SetMarked(!fChooseDefaultServerItem->IsMarked());
|
||||
|
||||
BMessage update(kMsgUpdateSettings);
|
||||
update.AddBool("choose default server", fChooseDefaultServerItem->IsMarked());
|
||||
be_app->PostMessage(&update);
|
||||
break;
|
||||
}
|
||||
|
||||
case kMsgDefaultServer:
|
||||
{
|
||||
int32 index;
|
||||
if (message->FindInt32("index", &index) != B_OK)
|
||||
break;
|
||||
|
||||
BMessage update(kMsgUpdateSettings);
|
||||
update.AddInt32("default server", index);
|
||||
be_app->PostMessage(&update);
|
||||
break;
|
||||
}
|
||||
|
||||
case kMsgEditServerList:
|
||||
be_app->PostMessage(kMsgEditServerList);
|
||||
break;
|
||||
|
||||
case kMsgStopTimeUpdate:
|
||||
if (fButton != NULL) {
|
||||
fButton->SetLabel("Update");
|
||||
fButton->Message()->what = kMsgUpdateTime;
|
||||
}
|
||||
|
||||
BButton *source;
|
||||
if (message->FindPointer("source", (void **)&source) == B_OK
|
||||
&& fButton == source)
|
||||
fStatusBar->SetText("Stopped.");
|
||||
|
||||
be_app->PostMessage(message);
|
||||
break;
|
||||
|
||||
case kMsgUpdateTime:
|
||||
if (fButton != NULL) {
|
||||
fButton->SetLabel("Stop");
|
||||
fButton->Message()->what = kMsgStopTimeUpdate;
|
||||
}
|
||||
|
||||
be_app->PostMessage(message);
|
||||
break;
|
||||
|
||||
case kMsgStatusUpdate:
|
||||
float progress;
|
||||
if (message->FindFloat("progress", &progress) == B_OK)
|
||||
fStatusBar->Update(progress - fStatusBar->CurrentValue());
|
||||
|
||||
const char *text;
|
||||
if (message->FindString("message", &text) == B_OK)
|
||||
fStatusBar->SetText(text);
|
||||
|
||||
status_t status;
|
||||
if (message->FindInt32("status", (int32 *)&status) == B_OK) {
|
||||
if (status == B_OK && fAutoQuit)
|
||||
QuitRequested();
|
||||
else if (fButton != NULL) {
|
||||
fButton->SetLabel("Update");
|
||||
fButton->Message()->what = kMsgUpdateTime;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
BWindow::MessageReceived(message);
|
||||
}
|
||||
}
|
||||
|
36
src/apps/networktime/UpdateWindow.h
Normal file
36
src/apps/networktime/UpdateWindow.h
Normal file
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright 2004, pinc Software. All Rights Reserved.
|
||||
* Distributed under the terms of the MIT license.
|
||||
*/
|
||||
#ifndef UPDATE_WINDOW_H
|
||||
#define UPDATE_WINDOW_H
|
||||
|
||||
|
||||
#include <Window.h>
|
||||
|
||||
class BStatusBar;
|
||||
class BButton;
|
||||
class BMenuItem;
|
||||
class BMenu;
|
||||
|
||||
|
||||
class UpdateWindow : public BWindow {
|
||||
public:
|
||||
UpdateWindow(BRect position, const BMessage &settings);
|
||||
virtual ~UpdateWindow();
|
||||
|
||||
virtual bool QuitRequested();
|
||||
virtual void MessageReceived(BMessage *message);
|
||||
|
||||
void BuildServerMenu();
|
||||
|
||||
private:
|
||||
const BMessage &fSettings;
|
||||
BStatusBar *fStatusBar;
|
||||
BButton *fButton;
|
||||
BMenuItem *fAutoModeItem, *fTryAllServersItem, *fChooseDefaultServerItem;
|
||||
BMenu *fServerMenu;
|
||||
bool fAutoQuit;
|
||||
};
|
||||
|
||||
#endif /* UPDATE_WINDOW_H */
|
220
src/apps/networktime/ntp.cpp
Normal file
220
src/apps/networktime/ntp.cpp
Normal file
@ -0,0 +1,220 @@
|
||||
/*
|
||||
* Copyright 2004-2009, pinc Software. All Rights Reserved.
|
||||
* Distributed under the terms of the MIT license.
|
||||
*/
|
||||
|
||||
|
||||
#include "ntp.h"
|
||||
|
||||
#include <OS.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <netdb.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
/* This structure and its data fields are described in RFC 1305
|
||||
* "Network Time Protocol (Version 3)" in appendix A.
|
||||
*/
|
||||
|
||||
struct fixed32 {
|
||||
int16 integer;
|
||||
uint16 fraction;
|
||||
|
||||
void
|
||||
SetTo(int16 integer, uint16 fraction = 0)
|
||||
{
|
||||
this->integer = htons(integer);
|
||||
this->fraction = htons(fraction);
|
||||
}
|
||||
|
||||
int16 Integer() { return htons(integer); }
|
||||
uint16 Fraction() { return htons(fraction); }
|
||||
};
|
||||
|
||||
struct ufixed64 {
|
||||
uint32 integer;
|
||||
uint32 fraction;
|
||||
|
||||
void
|
||||
SetTo(uint32 integer, uint32 fraction = 0)
|
||||
{
|
||||
this->integer = htonl(integer);
|
||||
this->fraction = htonl(fraction);
|
||||
}
|
||||
|
||||
uint32 Integer() { return htonl(integer); }
|
||||
uint32 Fraction() { return htonl(fraction); }
|
||||
};
|
||||
|
||||
struct ntp_data {
|
||||
uint8 mode : 3;
|
||||
uint8 version : 3;
|
||||
uint8 leap_indicator : 2;
|
||||
|
||||
uint8 stratum;
|
||||
int8 poll;
|
||||
int8 precision; /* in seconds of the nearest power of two */
|
||||
|
||||
fixed32 root_delay;
|
||||
fixed32 root_dispersion;
|
||||
uint32 root_identifier;
|
||||
|
||||
ufixed64 reference_timestamp;
|
||||
ufixed64 originate_timestamp;
|
||||
ufixed64 receive_timestamp;
|
||||
ufixed64 transmit_timestamp;
|
||||
|
||||
/* optional authenticator follows (96 bits) */
|
||||
};
|
||||
|
||||
#define NTP_PORT 123
|
||||
#define NTP_VERSION_3 3
|
||||
|
||||
enum ntp_leap_warnings {
|
||||
LEAP_NO_WARNING = 0,
|
||||
LEAP_LAST_MINUTE_61_SECONDS,
|
||||
LEAP_LAST_MINUTE_59_SECONDS,
|
||||
LEAP_CLOCK_NOT_IN_SYNC,
|
||||
};
|
||||
|
||||
enum ntp_modes {
|
||||
MODE_RESERVED = 0,
|
||||
MODE_SYMMETRIC_ACTIVE,
|
||||
MODE_SYMMETRIC_PASSIVE,
|
||||
MODE_CLIENT,
|
||||
MODE_SERVER,
|
||||
MODE_BROADCAST,
|
||||
MODE_NTP_CONTROL_MESSAGE,
|
||||
};
|
||||
|
||||
|
||||
const uint32 kUTCtoGMT = 12 * 60 * 60;
|
||||
|
||||
|
||||
uint32
|
||||
seconds_system_difference(void)
|
||||
{
|
||||
const uint32 kYear2000 = 3155713200UL;
|
||||
// that many seconds from year 1900 to 2000.
|
||||
|
||||
struct tm tm;
|
||||
memset(&tm, 0, sizeof(struct tm));
|
||||
tm.tm_mday = 1;
|
||||
tm.tm_year = 100;
|
||||
|
||||
return kYear2000 - mktime(&tm);
|
||||
}
|
||||
|
||||
|
||||
uint32
|
||||
seconds_since_1900(void)
|
||||
{
|
||||
return seconds_system_difference() + real_time_clock();
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
ntp_update_time(const char *hostname, Monitor *monitor)
|
||||
{
|
||||
if (monitor)
|
||||
monitor->Update(0, "Contacting server \"%s\"...", hostname);
|
||||
|
||||
hostent *server = gethostbyname(hostname);
|
||||
if (server == NULL) {
|
||||
if (monitor)
|
||||
monitor->Update("Could not contact server.");
|
||||
return B_ENTRY_NOT_FOUND;
|
||||
}
|
||||
|
||||
if (monitor)
|
||||
monitor->Update(25, "Sending request...");
|
||||
|
||||
ntp_data message;
|
||||
memset(&message, 0, sizeof(ntp_data));
|
||||
|
||||
message.leap_indicator = LEAP_CLOCK_NOT_IN_SYNC;
|
||||
message.version = NTP_VERSION_3;
|
||||
message.mode = MODE_CLIENT;
|
||||
|
||||
message.stratum = 1; // primary reference
|
||||
message.precision = -5; // 2^-5 ~ 32-64 Hz precision
|
||||
|
||||
message.root_delay.SetTo(1); // 1 sec
|
||||
message.root_dispersion.SetTo(1);
|
||||
|
||||
message.transmit_timestamp.SetTo(seconds_since_1900());
|
||||
|
||||
int connection = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (connection < 0) {
|
||||
if (monitor)
|
||||
monitor->Update("Could not create socket: %s", strerror(errno));
|
||||
return errno;
|
||||
}
|
||||
|
||||
struct sockaddr_in address;
|
||||
address.sin_family = AF_INET;
|
||||
address.sin_port = htons(NTP_PORT);
|
||||
address.sin_addr.s_addr = *(uint32 *)server->h_addr_list[0];
|
||||
|
||||
if (sendto(connection, (char *)&message, sizeof(ntp_data),
|
||||
0, (struct sockaddr *)&address, sizeof(address)) < 0) {
|
||||
if (monitor)
|
||||
monitor->Update("Sending request failed: %s", strerror(errno));
|
||||
return errno;
|
||||
}
|
||||
|
||||
// message is sent, now just wait for something to be returned...
|
||||
|
||||
if (monitor)
|
||||
monitor->Update(50, "Waiting for answer...");
|
||||
|
||||
fd_set waitForReceived;
|
||||
FD_ZERO(&waitForReceived);
|
||||
FD_SET(connection, &waitForReceived);
|
||||
|
||||
struct timeval timeout;
|
||||
timeout.tv_sec = 3;
|
||||
timeout.tv_usec = 0;
|
||||
// we'll wait 3 seconds for the answer
|
||||
|
||||
if (select(connection + 1, &waitForReceived, NULL, NULL, &timeout) <= 0) {
|
||||
if (monitor)
|
||||
monitor->Update("Waiting for answer failed: %s", strerror(errno));
|
||||
return errno;
|
||||
}
|
||||
|
||||
message.transmit_timestamp.SetTo(0);
|
||||
|
||||
socklen_t addressSize = sizeof(address);
|
||||
if (recvfrom(connection, (char *)&message, sizeof(ntp_data), 0,
|
||||
(sockaddr *)&address, &addressSize) < (ssize_t)sizeof(ntp_data)) {
|
||||
if (monitor)
|
||||
monitor->Update("Message receiving failed: %s", strerror(errno));
|
||||
close(connection);
|
||||
return errno;
|
||||
}
|
||||
|
||||
close(connection);
|
||||
|
||||
if (message.transmit_timestamp.Integer() == 0) {
|
||||
if (monitor)
|
||||
monitor->Update("Received invalid time.");
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
time_t now = message.transmit_timestamp.Integer() - seconds_system_difference() + kUTCtoGMT;
|
||||
|
||||
if (monitor) {
|
||||
char buffer[64];
|
||||
strftime(buffer, sizeof(buffer), "%a %b %T %Y", localtime(&now));
|
||||
monitor->Update(100, "Message received: %s", buffer);
|
||||
}
|
||||
|
||||
set_real_time_clock(now);
|
||||
return B_OK;
|
||||
}
|
15
src/apps/networktime/ntp.h
Normal file
15
src/apps/networktime/ntp.h
Normal file
@ -0,0 +1,15 @@
|
||||
/*
|
||||
* Copyright 2004, pinc Software. All Rights Reserved.
|
||||
* Distributed under the terms of the MIT license.
|
||||
*/
|
||||
#ifndef NTP_H
|
||||
#define NTP_H
|
||||
|
||||
|
||||
#include "Monitor.h"
|
||||
#include <SupportDefs.h>
|
||||
|
||||
|
||||
extern status_t ntp_update_time(const char *host, Monitor *monitor = NULL);
|
||||
|
||||
#endif /* NTP_H */
|
Loading…
Reference in New Issue
Block a user