回精華區
作者TKyo.bbs@cpu.tfcis.org (暗黑貴公子) 看板: plan
標題[功能]IP/FQDN 表管理介面
時間動力核心 (2005/01/25 Tue 18:06:54) Updated: 2006/04/17
#if 0

  功能簡介 :

         1.將原本以文字記載的 IP/FQDN 表給 xover() 介面化, 方便管理
         2.有效減少登入時搜尋冗長 IP/FQDN 文字檔所耗費的時間
         3.IP 表以 range 來做判斷, FQDN 表則以關鍵字做判斷

  設定範例 :

       交大 - 140.113.xxx.xxx

       新增 IP 表時

         IP 範圍起點:140.113.0.0
         IP 範圍終點:140.113.255.255
                說明:國立交通大學

       新增 FQDN 表時

         FQDN 關鍵字:.nctu.edu.tw
                說明:國立交通大學

  更狠的例子 :

       TANET - 140.xxx.xxx.xxx

       新增 IP 表時

         IP 範圍起點:140.0.0.0
         IP 範圍終點:140.255.255.255

       新增 FQDN 表時

         FQDN 關鍵字:.edu.tw
                說明:TANET

  Q : 這時有些人會問, 如果我設定了 TANET 及交大, 按 's' 排序後, TANET 的設定
      會在前面, 那系統判斷時, fromhost 不就永遠都是顯示 TANET 嗎?

  A : 所以, 提供了 'L' 鎖定 IP/FQDN 資料的功能, 被鎖定的資料會置頂
      且按 's' 排序時, 被鎖定的 IP/FQDN 只會跟同為鎖定的 IP/FQDN 資料置頂排序

#endif

: src/include/global.h

  /* --------------------------------------------------- */
  /* etc/ 目錄下系統檔案                                 */
  /* --------------------------------------------------- */
    .
    .
    .
+ #ifdef HAVE_WHERE

+ #define FN_ETC_IPT      "etc/ipt.dat"   /* 來源 IP 資料表 */
+ #define FN_ETC_FQDNT    "etc/fqdnt.dat" /* 來源 FQDN 資料表 */

+ #endif

: src/include/modes.h : 假設 XO_ZONE 最後為精華區, 需跟 xz[] 同步

  #define XZ_GEM          (XO_ZONE + 13)          /* 精華區 */
+ #define XZ_ADMIP        (XO_ZONE + 14)          /*  IP 管理 */
+ #define XZ_ADMFQDN      (XO_ZONE + 15)          /* FQDN 管理 */

: src/include/struct.h : 適當位置加入

+ #ifdef HAVE_WHERE

+ typedef struct
+ {
+   time_t stamp;                 /* 編號 */
+   int xmode;                    /* 模式 */
+   u_long ip_range_src;          /* IP 範圍起點 */
+   u_long ip_range_dest;         /* IP 範圍終點 */
+   char cname[34];               /* 說明 */
+ }       IPT;

+ typedef struct
+ {
+   time_t stamp;                 /* 編號 */
+   int xmode;                    /* 模式 */
+   char query[38];               /* FQDN 關鍵字 */
+   char cname[34];               /* 說明 */
+ }       FQDNT;

+ #endif                          /* HAVE_WHERE */

: src/include/theme.h : 適當位置加入


+ #define COLOR_LOCKED    "\033[1;36m"    /* 鎖住的 IP/FQDN */
+ #define COLOR_NORMAL    "\033[0;37m"    /* 一般 IP/FQDN */

+ #define NECKER_ADMIP    "[←]離開 [T]修改 IP 資料說明 [t]標籤" \
+ " [d/D]刪除 [^D]標籤刪除\n" \
+ "COLOR3 "  編號    IP 範圍起點      IP 範圍終點      " \
+ "說              明%*s                \033[m"

+ #define NECKER_ADMFQDN  "[←]離開 [T]修改 FQDN 資料說明 [t]標籤" \
+ " [d/D]刪除 [^D]標籤刪除\n" \
+ COLOR3 "  編號    FQDN 關鍵字                           " \
+ "說              明%*s            \033[m"

+ #define FEETER_ADMIP    \
+ COLOR1 " IP管理 " COLOR2 " (a)新增 (E)修改 (s)排序 (↑/↓)上下" \
+ " (PgUp/PgDn)上下頁 (←)離開     "

+ #define FEETER_ADMFQDN  \
+ COLOR1 " FQDN管理 " COLOR2 " (a)新增 (E)修改 (s)排序 (↑/↓)上下" \
+ " (PgUp/PgDn)上下頁 (←)離開     "

: src/maple/xover.c : xz[]

- {NULL, NULL, M_GEM, FEETER_GEM}               /* XZ_GEM */
+ {NULL, NULL, M_GEM, FEETER_GEM},              /* XZ_GEM */
+ {NULL, NULL, M_SYSTEM, FEETER_ADMIP},         /* XZ_ADMIP */
+ {NULL, NULL, M_SYSTEM, FEETER_ADMFQDN}        /* XZ_ADMFQDN */

: src/maple/menu.c : 適當選單加入

+ "bin/admip.so:admip_main", PERM_ALLADMIN, - M_SYSTEM,
+ "IP-Manage     IP 管理",

+ "bin/admfqdn.so:admfqdn_main", PERM_ALLADMIN, - M_SYSTEM,
+ "FQDN-Manage   FQDN 管理",


: src/maple/bbsd.c

/* utmp_setup() 上方加入 4 個 function */

static u_long
trans_inaddr(ipdata)
  u_long ipdata;
{
  uschar *addr = (uschar *) &ipdata;

  return ((addr[0] << 24) + (addr[1] << 16) + (addr[2] << 8) + addr[3]);
}

static int
chkfqdnt(fqdnt, key, from)
  FQDNT *fqdnt;
  char *key;
  char *from;
{
  if (str_sub(key, fqdnt->query))
  {
    strcpy(from, fqdnt->cname);
    return 1;
  }

  return 0;
}

static int
chkipt(ipt, key, from)
  IPT *ipt;
  u_long *key;
  char *from;
{
  u_long i, j;

  i = trans_inaddr(ipt->ip_range_src);
  j = trans_inaddr(ipt->ip_range_dest);

  if ((*key != -1) && (*key >= i && *key <= j))
  {
    strcpy(from, ipt->cname);
    return 1;
  }

  return 0;
}

static int
belong_table(fpath, data, size, key, from, fchk)
  char *fpath;
  void *data;
  int size;
  void *key;
  char *from;
  int (*fchk) ();
{
  int pos, i;

  pos = 0;
  i = 0;
  while (!rec_get(fpath, data, size, pos))
  {
    if ((i = fchk(data, key, from)))
      break;
    pos++;
  }

  return i;
}

: src/maple/bbsd.c : utmp_setup()
  .
  .
  .
    char name[40];
+   FQDNT fqdnt;

    /* 先比對 FQDN */
    str_lower(name, fromhost);
-   if (!belong_list(FN_ETC_FQDN, name, utmp.from))
+   if (!(belong_table(FN_ETC_FQDNT, &fqdnt, sizeof(FQDNT),
      name, utmp.from, chkfqdnt)))
    {
+     IPT ipt;
      /* 再比對 ip */
-     sprintf(name, "%d.%d.%d.%d", addr[0], addr[1], addr[2], addr[3]);
-     if (!belong_list(FN_ETC_HOST, name, utmp.from))
+   if (!(belong_table(FN_ETC_IPT, &ipt, sizeof(IPT),
      &utmp.in_addr, utmp.from, chkipt)))
    str_ncpy(utmp.from, fromhost, sizeof(utmp.from));
    }

: src/so/admip.c 新增這隻程式

/*-------------------------------------------------------*/
/* admip.c          ( NTHU CS MapleBBS Ver 3.10 )        */
/*-------------------------------------------------------*/
/* target : IP      管理程式                             */
/* author : kyo.bbs@cszone.org                           */
/* create : 05/01/11                                     */
/* update :   /  /                                       */
/*-------------------------------------------------------*/


#include "bbs.h"


#ifdef HAVE_WHERE

extern XZ xz[];
extern char xo_pool[];

#define IPT_LOCKED      0x01            /* Don't move */

static char *
trans_addr(ipdata)
  u_long ipdata;
{
  static char buf[16];
  uschar *addr = (uschar *) &ipdata;

  sprintf(buf, "%d.%d.%d.%d", addr[0], addr[1], addr[2], addr[3]);
  return buf;
}

static u_long
trans_inaddr(ipdata)
  u_long ipdata;
{
  uschar *addr = (uschar *) &ipdata;

  return ((addr[0] << 24) + (addr[1] << 16) + (addr[2] << 8) + addr[3]);
}

static int
admip_edit(ipt, echo)
  IPT *ipt;
  int echo;
{
  char buf[16];
  u_long i;

  if (echo == GCARRY)
    strcpy(buf, trans_addr(ipt->ip_range_src));

  for (;;)
  {
    if (!(vget(b_lines, 0, "IP 範圍起點:", buf, 16, echo)))
      return 0;
    i = inet_addr(buf);
    if (i == -1)
      vmsg("IP 輸入格式錯誤!");
    else
    {
      ipt->ip_range_src = i;
      break;
    }
  }

  if (echo == GCARRY)
    strcpy(buf, trans_addr(ipt->ip_range_dest));

  for (;;)
  {
    if (!(vget(b_lines, 0, "IP 範圍終點:", buf, 16, echo)))
      return 0;
    i = inet_addr(buf);
    if (i == -1)
      vmsg("IP 輸入格式錯誤");
    else
    {
      ipt->ip_range_dest = i;
      break;
    }
  }

  if (trans_inaddr(ipt->ip_range_src) > trans_inaddr(ipt->ip_range_dest))
  {
    vmsg("IP 範圍檢查錯誤!!\nIP 範圍終點必須大於或等於 IP 範圍起點");
    return 0;
  }

  if (!(vget(b_lines, 0, "說明:", ipt->cname, 34, echo)))
    return 0;

  return 1;
}


static int
admip_add(xo)
  XO *xo;
{
  IPT ipt;

  memset(&ipt, 0, sizeof(IPT));

  if (admip_edit(&ipt, DOECHO))
  {
    time(&ipt.stamp);
    rec_add(FN_ETC_IPT, &ipt, sizeof(IPT));
  }

  return XO_INIT;
}

static int
admip_change(xo)
  XO *xo;
{
  IPT *ipt, old_ipt;
  int pos, cur;

  pos = xo->pos;
  cur = pos - xo->top;
  ipt = (IPT *) xo_pool + cur;

  old_ipt = *ipt;

  if (admip_edit(&old_ipt, GCARRY))
  {
    if (memcmp(ipt, &old_ipt, sizeof(IPT)))
    {
      if (vans("確定要修改嗎?[N] ") == 'y')
      {
        rec_put(FN_ETC_IPT, &old_ipt, sizeof(IPT), pos);
        return XO_LOAD;
      }
    }
  }

  return XO_FOOT;
}

static int
admip_title(xo)
  XO *xo;
{
  IPT *ipt, old_ipt;
  int pos, cur;

  pos = xo->pos;
  cur = pos - xo->top;
  ipt = (IPT *) xo_pool + cur;

  old_ipt = *ipt;

  if (vget(b_lines, 0, "說明:", old_ipt.cname, 34, GCARRY))
  {
    if (memcmp(ipt, &old_ipt, sizeof(IPT)))
    {
      rec_put(FN_ETC_IPT, &old_ipt, sizeof(IPT), pos);
      return XO_LOAD;
    }
  }

  return XO_FOOT;
}

static int
admip_query(xo)
  XO *xo;
{
  char *menu[] = {"QQ",
      "A  新增 IP 資料",
      "T  修改 IP 資料說明",
      "E  修改 IP 資料",
      "Q  取消", NULL};

  switch (pans(-1, -1, "功\能選單", menu))
  {
    case 'a':
      return admip_add(xo);
    case 't':
      return admip_title(xo);
    case 'e':
      return admip_change(xo);
    default:
      return XO_NONE;
  }
}

static int
admip_delete(xo)
  XO *xo;
{
  if (vans(msg_del_ny) == 'y')
  {
    if (!rec_del(xo->dir, sizeof(IPT), xo->pos, NULL, NULL))
    {
      IPT *ipt;
      ipt = (IPT *) xo_pool + (xo->pos - xo->top);
      return XO_LOAD;
    }
  }
  return XO_FOOT;
}

static int
admip_rangedel(xo)
  XO *xo;
{
  return xo_rangedel(xo, sizeof(IPT), NULL, NULL);
}


static int
vfyadmip(ipt, pos)
  IPT *ipt;
  int pos;
{
  return Tagger(ipt->stamp, pos, TAG_NIN);
}


static int
admip_prune(xo)
  XO *xo;
{
  return xo_prune(xo, sizeof(IPT), vfyadmip, NULL);
}

static int
admip_attr(mode)
  int mode;
{
  return (mode & IPT_LOCKED) ? 'L' : ' ';
}

static void
admip_item(num, ipt)
  int num;
  IPT *ipt;
{
  prints("%6d %s%c\033[m %c%-15s  ",
    num, (ipt->xmode & IPT_LOCKED) ? COLOR_LOCKED : COLOR_NORMAL,
    admip_attr(ipt->xmode),
    tag_char(ipt->stamp), trans_addr(ipt->ip_range_src));

  prints("%-15s  %s\n", trans_addr(ipt->ip_range_dest),
    ipt->cname);
}

static int
admip_body(xo)
  XO *xo;
{
  IPT *ipt;
  int max, num, tail;

  max = xo->max;
  if (max <= 0)
  {
    if (vans("新增 IP 資料?[N] ") == 'y')
      return admip_add(xo);

    return XO_QUIT;
  }

  ipt = (IPT *) xo_pool;
  num = xo->top;
  tail = num + XO_TALL;
  if (max > tail)
    max = tail;

  move(3, 0);
  do
  {
    admip_item(++num, ipt++);
  } while (num < max);
  clrtobot();

  return XO_FOOT;       /* itoc.010403: 把 b_lines 填上 feeter */
}


static int
admip_head(xo)
  XO *xo;
{
  vs_head("IP管理", str_site);
  prints(NECKER_ADMIP, d_cols, "");

  return admip_body(xo);
}


static int
admip_load(xo)
  XO *xo;
{
  xo_load(xo, sizeof(IPT));
  return admip_body(xo);
}

static int
admip_init(xo)
  XO *xo;
{
  xo_load(xo, sizeof(IPT));
  return admip_head(xo);
}

static int
admip_tag(xo)
  XO *xo;
{
  IPT *ipt;
  int tag, pos, cur;

  pos = xo->pos;
  cur = pos - xo->top;
  ipt = (IPT *) xo_pool + cur;

  if (tag = Tagger(ipt->stamp, pos, TAG_TOGGLE))
  {
    move(3 + cur, 0);
    admip_item(++pos, ipt);
  }

  return xo->pos + 1 + XO_MOVE; /* lkchu.981201: 跳至下一項 */
}

static int
ipt_cmp(a, b)
  IPT *a, *b;
{
  int iSeq, jSeq;
  u_long i, j, k;

  iSeq = (a->xmode & IPT_LOCKED) ? 1 : 0;
  jSeq = (b->xmode & IPT_LOCKED) ? 1 : 0;

  i = trans_inaddr(a->ip_range_src);
  j = trans_inaddr(b->ip_range_src);

  i = (i > j) ? 1 :
      (i < j) ? -1 :
      0;

  j = trans_inaddr(a->ip_range_dest);
  k = trans_inaddr(b->ip_range_dest);

  j = (j > k) ? 1 :
      (j < k) ? -1 :
      0;

  if (!iSeq && !jSeq)
    return (i == 0) ? ((j == 0) ? str_cmp(a->cname, b->cname) : j) : i;
  else if (!jSeq)
    return -1;
  else if (!iSeq)
    return 1;
  else
    return (i == 0) ? ((j == 0) ? str_cmp(a->cname, b->cname) : j) : i;
}

static int
admip_sort(xo)
  XO *xo;
{
  rec_sync(xo->dir, sizeof(IPT), ipt_cmp, NULL);
  return admip_load(xo);
}

static int
admip_move(xo)
  XO *xo;
{
  IPT *ipt;
  int pos, cur, i;
  char buf[40], ans[5];

  pos = xo->pos;
  cur = pos - xo->top;
  ipt = (IPT *) xo_pool + cur;



  sprintf(buf, "請輸入第 %d 選項的新位置:", pos + 1);
  if (vget(b_lines, 0, buf, ans, 5, DOECHO))
  {
    i = atoi(ans) - 1;
    if (i < 0)
      i = 0;
    else if (i >= xo->max)
      i = xo->max - 1;

    if (i != pos)
    {
      if (!rec_del(xo->dir, sizeof(IPT), pos, NULL, NULL))
      {
        rec_ins(xo->dir, ipt, sizeof(IPT), i, 1);
        xo->pos = i;
        return admip_load(xo);
      }
    }
  }
  return XO_FOOT;
}

static
admip_lock(xo)
  XO *xo;
{
  int pos, cur;
  IPT *ipt;

  pos = xo->pos;
  cur = pos - xo->top;
  ipt = (IPT *) xo_pool + cur;

  ipt->xmode ^= IPT_LOCKED;

  rec_put(xo->dir, ipt, sizeof(IPT), pos);

  move(3 + cur, 0);
  admip_item(++pos, ipt);

  return XO_NONE;
}

static int
admip_help(xo)
  XO *xo;
{
  return XO_NONE;
}

static KeyFunc admip_cb[] =
{
  XO_INIT, admip_init,
  XO_LOAD, admip_load,
  XO_HEAD, admip_head,
  XO_BODY, admip_body,

  'r', admip_query,
  'a', admip_add,
  'E', admip_change,
  'T', admip_title,
  Ctrl('D'), admip_prune,
  'd', admip_delete,
  'D', admip_rangedel,
  't', admip_tag,
  's', admip_sort,
  'm', admip_move,
  'l', admip_lock,
  'h', admip_help
};

int
admip_main()
{
  XO *xo;

  xz[XZ_ADMIP - XO_ZONE].xo = xo = xo_new(FN_ETC_IPT);
  xz[XZ_ADMIP - XO_ZONE].cb = admip_cb;
  xo->pos = 0;

  xover(XZ_ADMIP);
  free(xo);

  return 0;
}

#endif                          /* HAVE_WHERE */

: src/so/admfqdn.c 新增這隻程式

/*-------------------------------------------------------*/
/* admfqdn.c        ( NTHU CS MapleBBS Ver 3.10 )        */
/*-------------------------------------------------------*/
/* target : FQDN 管理程式                                */
/* author : kyo.bbs@cszone.org                           */
/* create : 05/01/11                                     */
/* update :   /  /                                       */
/*-------------------------------------------------------*/


#include "bbs.h"


#ifdef HAVE_WHERE

extern XZ xz[];
extern char xo_pool[];

#define FQDNT_LOCKED      0x01            /* Don't move */

static int
admfqdn_edit(fqdnt, echo)
  FQDNT *fqdnt;
  int echo;
{

  if (!(vget(b_lines, 0, "FQDN 關鍵字:", fqdnt->query, 38, echo)))
    return 0;

  str_lower(fqdnt->query, fqdnt->query);

  if (!(vget(b_lines, 0, "說明:", fqdnt->cname, 34, echo)))
    return 0;

  return 1;
}


static int
admfqdn_add(xo)
  XO *xo;
{
  FQDNT fqdnt;

  memset(&fqdnt, 0, sizeof(FQDNT));

  if (admfqdn_edit(&fqdnt, DOECHO))
  {
    time(&fqdnt.stamp);
    rec_add(FN_ETC_FQDNT, &fqdnt, sizeof(FQDNT));
  }

  return XO_INIT;
}

static int
admfqdn_change(xo)
  XO *xo;
{
  FQDNT *fqdnt, old_fqdnt;
  int pos, cur;

  pos = xo->pos;
  cur = pos - xo->top;
  fqdnt = (FQDNT *) xo_pool + cur;

  old_fqdnt = *fqdnt;

  if (admfqdn_edit(&old_fqdnt, GCARRY))
  {
    if (memcmp(fqdnt, &old_fqdnt, sizeof(FQDNT)))
    {
      if (vans("確定要修改嗎?[N] ") == 'y')
      {
        rec_put(FN_ETC_FQDNT, &old_fqdnt, sizeof(FQDNT), pos);
        return XO_LOAD;
      }
    }
  }

  return XO_FOOT;
}

static int
admfqdn_title(xo)
  XO *xo;
{
  FQDNT *fqdnt, old_fqdnt;
  int pos, cur;

  pos = xo->pos;
  cur = pos - xo->top;
  fqdnt = (FQDNT *) xo_pool + cur;

  old_fqdnt = *fqdnt;

  if (vget(b_lines, 0, "說明:", old_fqdnt.cname, 34, GCARRY))
  {
    if (memcmp(fqdnt, &old_fqdnt, sizeof(FQDNT)))
    {
      rec_put(FN_ETC_FQDNT, &old_fqdnt, sizeof(FQDNT), pos);
      return XO_LOAD;
    }
  }

  return XO_FOOT;
}

static int
admfqdn_query(xo)
  XO *xo;
{
  char *menu[] = {"QQ",
      "A  新增 FQDN 資料",
      "T  修改 FQDN 資料說明",
      "E  修改 FQDN 資料",
      "Q  取消", NULL};

  switch (pans(-1, -1, "功\能選單", menu))
  {
    case 'a':
      return admfqdn_add(xo);
    case 't':
      return admfqdn_title(xo);
    case 'e':
      return admfqdn_change(xo);
    default:
      return XO_NONE;
  }
}

static int
admfqdn_delete(xo)
  XO *xo;
{
  if (vans(msg_del_ny) == 'y')
  {
    if (!rec_del(xo->dir, sizeof(FQDNT), xo->pos, NULL, NULL))
    {
      FQDNT *fqdnt;
      fqdnt = (FQDNT *) xo_pool + (xo->pos - xo->top);
      return XO_LOAD;
    }
  }
  return XO_FOOT;
}

static int
admfqdn_rangedel(xo)
  XO *xo;
{
  return xo_rangedel(xo, sizeof(FQDNT), NULL, NULL);
}


static int
vfyadmfqdn(fqdnt, pos)
  FQDNT *fqdnt;
  int pos;
{
  return Tagger(fqdnt->stamp, pos, TAG_NIN);
}


static int
admfqdn_prune(xo)
  XO *xo;
{
  return xo_prune(xo, sizeof(FQDNT), vfyadmfqdn, NULL);
}

static int
admfqdn_attr(mode)
  int mode;
{
  return (mode & FQDNT_LOCKED) ? 'L' : ' ';
}

static void
admfqdn_item(num, fqdnt)
  int num;
  FQDNT *fqdnt;
{
  prints("%6d %s%c\033[m %c%-37s %s\n",
    num, (fqdnt->xmode & FQDNT_LOCKED) ? COLOR_LOCKED : COLOR_NORMAL,
    admfqdn_attr(fqdnt->xmode),
    tag_char(fqdnt->stamp), fqdnt->query, fqdnt->cname);
}

static int
admfqdn_body(xo)
  XO *xo;
{
  FQDNT *fqdnt;
  int max, num, tail;

  max = xo->max;
  if (max <= 0)
  {
    if (vans("新增 FQDN 資料?[N] ") == 'y')
      return admfqdn_add(xo);

    return XO_QUIT;
  }

  fqdnt = (FQDNT *) xo_pool;
  num = xo->top;
  tail = num + XO_TALL;
  if (max > tail)
    max = tail;

  move(3, 0);
  do
  {
    admfqdn_item(++num, fqdnt++);
  } while (num < max);
  clrtobot();

  return XO_FOOT;       /* itoc.010403: 把 b_lines 填上 feeter */
}


static int
admfqdn_head(xo)
  XO *xo;
{
  vs_head("FQDN管理", str_site);
  prints(NECKER_ADMFQDN, d_cols, "");

  return admfqdn_body(xo);
}


static int
admfqdn_load(xo)
  XO *xo;
{
  xo_load(xo, sizeof(FQDNT));
  return admfqdn_body(xo);
}


static int
admfqdn_init(xo)
  XO *xo;
{
  xo_load(xo, sizeof(FQDNT));
  return admfqdn_head(xo);
}

static int
admfqdn_tag(xo)
  XO *xo;
{
  FQDNT *fqdnt;
  int tag, pos, cur;

  pos = xo->pos;
  cur = pos - xo->top;
  fqdnt = (FQDNT *) xo_pool + cur;

  if (tag = Tagger(fqdnt->stamp, pos, TAG_TOGGLE))
  {
    move(3 + cur, 0);
    admfqdn_item(++pos, fqdnt);
  }

  return xo->pos + 1 + XO_MOVE; /* lkchu.981201: 跳至下一項 */
}

static int
fqdnt_cmp(a, b)
  FQDNT *a, *b;
{
  int iSeq, jSeq;
  int i, j;

  iSeq = (a->xmode & FQDNT_LOCKED) ? 1 : 0;
  jSeq = (b->xmode & FQDNT_LOCKED) ? 1 : 0;

  i = str_cmp(a->query, b->query);
  j = str_cmp(a->cname, b->cname);

  if (!iSeq && !jSeq)
    return (i == 0) ? j : i;
  else if (!jSeq)
    return -1;
  else if (!iSeq)
    return 1;
  else
    return (i == 0) ? j : i;
}

static int
admfqdn_sort(xo)
  XO *xo;
{
  rec_sync(xo->dir, sizeof(FQDNT), fqdnt_cmp, NULL);
  return admfqdn_load(xo);
}

static int
admfqdn_move(xo)
  XO *xo;
{
  FQDNT *fqdnt;
  int pos, cur, i;
  char buf[40], ans[5];

  pos = xo->pos;
  cur = pos - xo->top;
  fqdnt = (FQDNT *) xo_pool + cur;

  sprintf(buf, "請輸入第 %d 選項的新位置:", pos + 1);
  if (vget(b_lines, 0, buf, ans, 5, DOECHO))
  {
    i = atoi(ans) - 1;
    if (i < 0)
      i = 0;
    else if (i >= xo->max)
      i = xo->max - 1;

    if (i != pos)
    {
      if (!rec_del(xo->dir, sizeof(FQDNT), pos, NULL, NULL))
      {
        rec_ins(xo->dir, fqdnt, sizeof(FQDNT), i, 1);
        xo->pos = i;
        return admfqdn_load(xo);
      }
    }
  }
  return XO_FOOT;
}

static
admfqdn_lock(xo)
  XO *xo;
{
  int pos, cur;
  FQDNT *fqdnt;

  pos = xo->pos;
  cur = pos - xo->top;
  fqdnt = (FQDNT *) xo_pool + cur;

  fqdnt->xmode ^= FQDNT_LOCKED;

  rec_put(xo->dir, fqdnt, sizeof(FQDNT), pos);

  move(3 + cur, 0);
  admfqdn_item(++pos, fqdnt);

  return XO_NONE;
}

static int
admfqdn_help(xo)
  XO *xo;
{
  return XO_NONE;
}

static KeyFunc admfqdn_cb[] =
{
  XO_INIT, admfqdn_init,
  XO_LOAD, admfqdn_load,
  XO_HEAD, admfqdn_head,
  XO_BODY, admfqdn_body,

  'r', admfqdn_query,
  'a', admfqdn_add,
  'E', admfqdn_change,
  'T', admfqdn_title,
  Ctrl('D'), admfqdn_prune,
  'd', admfqdn_delete,
  'D', admfqdn_rangedel,
  't', admfqdn_tag,
  's', admfqdn_sort,
  'm', admfqdn_move,
  'l', admfqdn_lock,
  'h', admfqdn_help
};

int
admfqdn_main()
{
  XO *xo;

  xz[XZ_ADMFQDN - XO_ZONE].xo = xo = xo_new(FN_ETC_FQDNT);
  xz[XZ_ADMFQDN - XO_ZONE].cb = admfqdn_cb;
  xo->pos = 0;

  xover(XZ_ADMFQDN);
  free(xo);

  return 0;
}

#endif                          /* HAVE_WHERE */


--
  Origin:  Maple-itoc˙動力核心  cpu.tfcis.org 
  Author: TKyo cszone.twbbs.org 發表
精華選讀←離開[主題上]主題下(k)上篇(j)下篇S/a搜尋 G串列 TAB精華 ↑↓捲 Pg/Space翻