#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>
#include <fcntl.h>
#include <syslog.h>
#include <netdb.h>
#include <utmp.h>
#include <pwd.h>
#include <setjmp.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/ioctl.h>
#include <pthread.h>
#include <net/if.h>
#include <CoreFoundation/CFBundle.h>
#include <CoreFoundation/CFUserNotification.h>
#define APPLE 1
#include "../Family/ppp_defs.h"
#include "../Family/if_ppp.h"
#include "../Family/ppp_domain.h"
#include "../Helpers/pppd/pppd.h"
#include "../Helpers/pppd/fsm.h"
#include "../Helpers/pppd/lcp.h"
#define ICON "NetworkConnect.icns"
static int dialog_idle(struct ppp_idle *idle);
static int dialog_start_link();
static int dialog_link_up();
static int dialog_ask(CFStringRef message, CFStringRef ok, CFStringRef cancel, int timeout);
static void dialog_reminder(void *arg);
static void dialog_phasechange(void *arg, int p);
static CFBundleRef bundle = 0;
static CFURLRef bundleURL = 0;
static pthread_t reminderthread = 0;
static int reminderresult = 0;
static bool askpasswordafter = 0;
static bool noaskpassword = 0;
static bool noidleprompt = 0;
static int reminder = 0;
option_t dialogs_options[] = {
{ "noaskpassword", o_bool, &noaskpassword,
"Don't ask for a password at all", 1 },
{ "askpasswordafter", o_bool, &askpasswordafter,
"Don't ask for a password before to connect", 1 },
{ "noidleprompt", o_bool, &noidleprompt,
"Don't ask user before to disconnect on idle", 1 },
{ "reminder", o_int, &reminder,
"Ask user to stay connected after reminder period" },
{ NULL }
};
int start(CFBundleRef ref)
{
bundle = ref;
bundleURL = CFBundleCopyBundleURL(bundle);
if (!bundleURL)
return 1;
CFRetain(bundle);
add_options(dialogs_options);
add_notifier(&phasechange, dialog_phasechange, 0);
start_link_hook = dialog_start_link;
link_up_hook = dialog_link_up;
return 0;
}
void dialog_phasechange(void *arg, int p)
{
if (reminder && p == PHASE_RUNNING)
TIMEOUT(dialog_reminder, 0, reminder);
else
UNTIMEOUT(dialog_reminder, 0);
}
void *dialog_reminder_thread(void *arg)
{
int status, timeout;
status = pthread_detach(pthread_self());
if (status == noErr) {
if (reminder < (60 * 5)) timeout = 30;
else if (reminder < (60 * 10)) timeout = 60;
else if (reminder < (60 * 20)) timeout = 120;
else if (reminder < (60 * 30)) timeout = 180;
else timeout = 240;
reminderresult = dialog_ask(CFSTR("Reminder timeout"), CFSTR("Stay connected"), CFSTR("Disconnect"), timeout);
}
return 0;
}
void dialog_reminder_watch(void *arg)
{
int tlim;
switch (reminderresult) {
case -1:
TIMEOUT(dialog_reminder_watch, 0, 2);
break;
case 0:
TIMEOUT(dialog_reminder, 0, reminder);
UNTIMEOUT(check_idle, NULL);
if (idle_time_hook != 0)
tlim = (*idle_time_hook)(NULL);
else
tlim = idle_time_limit;
if (tlim > 0)
TIMEOUT(check_idle, NULL, tlim);
break;
default :
lcp_close(0, "User request");
status = EXIT_USER_REQUEST;
}
}
void dialog_reminder(void *arg)
{
int status;
reminderresult = -1;
status = pthread_create(&reminderthread, NULL, dialog_reminder_thread, NULL);
if (status == noErr) {
TIMEOUT(dialog_reminder_watch, 0, 2);
}
}
int dialog_password(char *user, int maxuserlen, char *passwd, int maxpasswdlen)
{
CFUserNotificationRef alert;
CFOptionFlags flags;
CFMutableDictionaryRef dict;
SInt32 error;
CFMutableArrayRef array;
CFURLRef url;
CFStringRef str;
int ret = 0;
dict = CFDictionaryCreateMutable(NULL, 0, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
if (dict) {
url = CFBundleCopyResourceURL(bundle, CFSTR(ICON), NULL, NULL);
if (url) {
CFDictionaryAddValue(dict, kCFUserNotificationIconURLKey, url);
CFRelease(url);
}
array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
if (array) {
CFArrayAppendValue(array, CFSTR("Password:"));
CFDictionaryAddValue(dict, kCFUserNotificationTextFieldTitlesKey, array);
CFRelease(array);
}
array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
if (array) {
CFDictionaryAddValue(dict, kCFUserNotificationTextFieldValuesKey, array);
CFRelease(array);
}
CFDictionaryAddValue(dict, kCFUserNotificationLocalizationURLKey, bundleURL);
CFDictionaryAddValue(dict, kCFUserNotificationAlertHeaderKey, CFSTR("Internet Connect"));
CFDictionaryAddValue(dict, kCFUserNotificationAlternateButtonTitleKey, CFSTR("Cancel"));
alert = CFUserNotificationCreate(NULL, 0, CFUserNotificationSecureTextField(0), &error, dict);
if (alert) {
CFUserNotificationReceiveResponse(alert, 0, &flags);
if ((flags & 3) == 1) {
}
else {
ret = 1;
str = CFUserNotificationGetResponseValue(alert, kCFUserNotificationTextFieldValuesKey, 0);
if (str)
CFStringGetCString(str, passwd, MAXSECRETLEN, kCFStringEncodingUTF8);
}
CFRelease(alert);
}
CFRelease(dict);
}
return ret;
}
int dialog_start_link()
{
if (noaskpassword || *passwd || askpasswordafter)
return 1;
return dialog_password(user, MAXNAMELEN, passwd, MAXSECRETLEN);
}
int dialog_link_up()
{
if (noaskpassword || *passwd || !askpasswordafter)
return 1;
return dialog_password(user, MAXNAMELEN, passwd, MAXSECRETLEN);
}
int dialog_idle(struct ppp_idle *idle)
{
int itime = 0;
if (idle == 0)
return idle_time_limit;
itime = MIN(idle->xmit_idle, idle->recv_idle);
if ((idle_time_limit - itime) <= 0) {
if (noidleprompt || dialog_ask(CFSTR("Idle timeout"), CFSTR("Stay connected"), CFSTR("Disconnect"), 30)) {
return 0;
}
return idle_time_limit;
}
return idle_time_limit - itime;
}
int dialog_ask(CFStringRef message, CFStringRef ok, CFStringRef cancel, int timeout)
{
CFUserNotificationRef alert;
CFOptionFlags flags;
CFMutableDictionaryRef dict;
SInt32 error;
CFURLRef url;
flags = 3; dict = CFDictionaryCreateMutable(NULL, 0,
&kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
if (dict) {
url = CFBundleCopyResourceURL(bundle, CFSTR(ICON), NULL, NULL);
if (url) {
CFDictionaryAddValue(dict, kCFUserNotificationIconURLKey, url);
CFRelease(url);
}
CFDictionaryAddValue(dict, kCFUserNotificationLocalizationURLKey, bundleURL);
CFDictionaryAddValue(dict, kCFUserNotificationAlertHeaderKey, CFSTR("Internet Connect"));
CFDictionaryAddValue(dict, kCFUserNotificationAlertMessageKey, message);
if (ok) CFDictionaryAddValue(dict, kCFUserNotificationDefaultButtonTitleKey, ok);
if (cancel) CFDictionaryAddValue(dict, kCFUserNotificationAlternateButtonTitleKey, cancel);
alert = CFUserNotificationCreate(NULL, timeout, kCFUserNotificationCautionAlertLevel, &error, dict);
if (alert) {
CFUserNotificationReceiveResponse(alert, timeout, &flags);
CFRelease(alert);
}
CFRelease(dict);
}
return (flags & 3);
}