util.c revision 92921
1327952Sdim/* 2284677Sdim * Copyright (c) 1980, 1993 3353358Sdim * The Regents of the University of California. All rights reserved. 4353358Sdim * 5353358Sdim * Redistribution and use in source and binary forms, with or without 6284677Sdim * modification, are permitted provided that the following conditions 7284677Sdim * are met: 8284677Sdim * 1. Redistributions of source code must retain the above copyright 9284677Sdim * notice, this list of conditions and the following disclaimer. 10327952Sdim * 2. Redistributions in binary form must reproduce the above copyright 11284677Sdim * notice, this list of conditions and the following disclaimer in the 12327952Sdim * documentation and/or other materials provided with the distribution. 13341825Sdim * 3. All advertising materials mentioning features or use of this software 14327952Sdim * must display the following acknowledgement: 15327952Sdim * This product includes software developed by the University of 16327952Sdim * California, Berkeley and its contributors. 17309124Sdim * 4. Neither the name of the University nor the names of its contributors 18327952Sdim * may be used to endorse or promote products derived from this software 19284677Sdim * without specific prior written permission. 20327952Sdim * 21284677Sdim * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22327952Sdim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23327952Sdim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24284677Sdim * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25284677Sdim * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26284677Sdim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27284677Sdim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28284677Sdim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29284677Sdim * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30284677Sdim * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31296417Sdim * SUCH DAMAGE. 32296417Sdim */ 33296417Sdim 34314564Sdim#ifndef lint 35296417Sdim#if 0 36296417Sdimstatic char sccsid[] = "@(#)aux.c 8.1 (Berkeley) 6/6/93"; 37309124Sdim#endif 38296417Sdimstatic const char rcsid[] = 39296417Sdim "$FreeBSD: head/usr.bin/mail/aux.c 92921 2002-03-22 01:33:25Z imp $"; 40296417Sdim#endif /* not lint */ 41296417Sdim 42309124Sdim#include <sys/time.h> 43296417Sdim 44314564Sdim#include "rcv.h" 45327952Sdim#include "extern.h" 46327952Sdim 47341825Sdim/* 48353358Sdim * Mail -- a mail program 49353358Sdim * 50341825Sdim * Auxiliary functions. 51327952Sdim */ 52327952Sdim 53327952Sdimstatic char *save2str(char *, char *); 54284677Sdim 55360784Sdim/* 56341825Sdim * Return a pointer to a dynamic copy of the argument. 57341825Sdim */ 58341825Sdimchar * 59341825Sdimsavestr(str) 60341825Sdim char *str; 61341825Sdim{ 62341825Sdim char *new; 63341825Sdim int size = strlen(str) + 1; 64341825Sdim 65341825Sdim if ((new = salloc(size)) != NULL) 66341825Sdim bcopy(str, new, size); 67321369Sdim return (new); 68321369Sdim} 69321369Sdim 70321369Sdim/* 71353358Sdim * Make a copy of new argument incorporating old one. 72353358Sdim */ 73353358Sdimchar * 74353358Sdimsave2str(str, old) 75321369Sdim char *str, *old; 76296417Sdim{ 77327952Sdim char *new; 78327952Sdim int newsize = strlen(str) + 1; 79327952Sdim int oldsize = old ? strlen(old) + 1 : 0; 80327952Sdim 81327952Sdim if ((new = salloc(newsize + oldsize)) != NULL) { 82327952Sdim if (oldsize) { 83327952Sdim bcopy(old, new, oldsize); 84327952Sdim new[oldsize - 1] = ' '; 85341825Sdim } 86327952Sdim bcopy(str, new + oldsize, newsize); 87341825Sdim } 88341825Sdim return (new); 89341825Sdim} 90321369Sdim 91296417Sdim/* 92353358Sdim * Touch the named message by setting its MTOUCH flag. 93321369Sdim * Touched messages have the effect of not being sent 94353358Sdim * back to the system mailbox on exit. 95353358Sdim */ 96296417Sdimvoid 97353358Sdimtouch(mp) 98353358Sdim struct message *mp; 99296417Sdim{ 100353358Sdim 101353358Sdim mp->m_flag |= MTOUCH; 102321369Sdim if ((mp->m_flag & MREAD) == 0) 103353358Sdim mp->m_flag |= MREAD|MSTATUS; 104353358Sdim} 105296417Sdim 106353358Sdim/* 107353358Sdim * Test to see if the passed file name is a directory. 108296417Sdim * Return true if it is. 109296417Sdim */ 110321369Sdimint 111314564Sdimisdir(name) 112296417Sdim char name[]; 113321369Sdim{ 114321369Sdim struct stat sbuf; 115321369Sdim 116321369Sdim if (stat(name, &sbuf) < 0) 117321369Sdim return (0); 118296417Sdim return (S_ISDIR(sbuf.st_mode)); 119344779Sdim} 120321369Sdim 121327952Sdim/* 122327952Sdim * Count the number of arguments in the given string raw list. 123327952Sdim */ 124344779Sdimint 125344779Sdimargcount(argv) 126321369Sdim char **argv; 127321369Sdim{ 128344779Sdim char **ap; 129344779Sdim 130344779Sdim for (ap = argv; *ap++ != NULL;) 131296417Sdim ; 132327952Sdim return (ap - argv - 1); 133296417Sdim} 134309124Sdim 135327952Sdim/* 136309124Sdim * Return the desired header line from the passed message 137314564Sdim * pointer (or NULL if the desired header field is not available). 138327952Sdim */ 139314564Sdimchar * 140341825Sdimhfield(field, mp) 141344779Sdim const char *field; 142296417Sdim struct message *mp; 143296417Sdim{ 144327952Sdim FILE *ibuf; 145321369Sdim char linebuf[LINESIZE]; 146309124Sdim int lc; 147344779Sdim char *hfield; 148353358Sdim char *colon, *oldhfield = NULL; 149353358Sdim 150353358Sdim ibuf = setinput(mp); 151353358Sdim if ((lc = mp->m_lines - 1) < 0) 152353358Sdim return (NULL); 153353358Sdim if (readline(ibuf, linebuf, LINESIZE) < 0) 154353358Sdim return (NULL); 155353358Sdim while (lc > 0) { 156353358Sdim if ((lc = gethfield(ibuf, linebuf, lc, &colon)) < 0) 157353358Sdim return (oldhfield); 158353358Sdim if ((hfield = ishfield(linebuf, colon, field)) != NULL) 159321369Sdim oldhfield = save2str(hfield, oldhfield); 160321369Sdim } 161353358Sdim return (oldhfield); 162321369Sdim} 163321369Sdim 164327952Sdim/* 165327952Sdim * Return the next header field found in the given message. 166327952Sdim * Return >= 0 if something found, < 0 elsewise. 167327952Sdim * "colon" is set to point to the colon in the header. 168327952Sdim * Must deal with \ continuations & other such fraud. 169341825Sdim */ 170341825Sdimint 171341825Sdimgethfield(f, linebuf, rem, colon) 172341825Sdim FILE *f; 173341825Sdim char linebuf[]; 174353358Sdim int rem; 175353358Sdim char **colon; 176353358Sdim{ 177353358Sdim char line2[LINESIZE]; 178296417Sdim char *cp, *cp2; 179296417Sdim int c; 180341825Sdim 181341825Sdim for (;;) { 182341825Sdim if (--rem < 0) 183341825Sdim return (-1); 184341825Sdim if ((c = readline(f, linebuf, LINESIZE)) <= 0) 185341825Sdim return (-1); 186341825Sdim for (cp = linebuf; isprint((unsigned char)*cp) && *cp != ' ' && *cp != ':'; 187296417Sdim cp++) 188296417Sdim ; 189327952Sdim if (*cp != ':' || cp == linebuf) 190327952Sdim continue; 191360784Sdim /* 192296417Sdim * I guess we got a headline. 193327952Sdim * Handle wraparounding 194296417Sdim */ 195296417Sdim *colon = cp; 196296417Sdim cp = linebuf + c; 197327952Sdim for (;;) { 198327952Sdim while (--cp >= linebuf && (*cp == ' ' || *cp == '\t')) 199296417Sdim ; 200327952Sdim cp++; 201296417Sdim if (rem <= 0) 202296417Sdim break; 203296417Sdim ungetc(c = getc(f), f); 204327952Sdim if (c != ' ' && c != '\t') 205327952Sdim break; 206296417Sdim if ((c = readline(f, line2, LINESIZE)) < 0) 207327952Sdim break; 208296417Sdim rem--; 209296417Sdim for (cp2 = line2; *cp2 == ' ' || *cp2 == '\t'; cp2++) 210296417Sdim ; 211327952Sdim c -= cp2 - line2; 212327952Sdim if (cp + c >= linebuf + LINESIZE - 2) 213327952Sdim break; 214296417Sdim *cp++ = ' '; 215327952Sdim bcopy(cp2, cp, c); 216296417Sdim cp += c; 217296417Sdim } 218314564Sdim *cp = 0; 219327952Sdim return (rem); 220327952Sdim } 221314564Sdim /* NOTREACHED */ 222327952Sdim} 223314564Sdim 224314564Sdim/* 225309124Sdim * Check whether the passed line is a header line of 226327952Sdim * the desired breed. Return the field body, or 0. 227327952Sdim */ 228309124Sdim 229327952Sdimchar* 230309124Sdimishfield(linebuf, colon, field) 231309124Sdim char linebuf[]; 232321369Sdim char *colon; 233327952Sdim const char *field; 234327952Sdim{ 235314564Sdim char *cp = colon; 236327952Sdim 237314564Sdim *cp = 0; 238314564Sdim if (strcasecmp(linebuf, field) != 0) { 239327952Sdim *cp = ':'; 240327952Sdim return (0); 241327952Sdim } 242327952Sdim *cp = ':'; 243327952Sdim for (cp++; *cp == ' ' || *cp == '\t'; cp++) 244327952Sdim ; 245327952Sdim return (cp); 246327952Sdim} 247327952Sdim 248353358Sdim/* 249353358Sdim * Copy a string and lowercase the result. 250353358Sdim * dsize: space left in buffer (including space for NULL) 251353358Sdim */ 252353358Sdimvoid 253353358Sdimistrncpy(dest, src, dsize) 254353358Sdim char *dest; 255353358Sdim const char *src; 256353358Sdim size_t dsize; 257353358Sdim{ 258353358Sdim 259321369Sdim strlcpy(dest, src, dsize); 260321369Sdim while (*dest) 261321369Sdim *dest++ = tolower((unsigned char)*dest); 262321369Sdim} 263309124Sdim 264321369Sdim/* 265321369Sdim * The following code deals with input stacking to do source 266321369Sdim * commands. All but the current file pointer are saved on 267321369Sdim * the stack. 268341825Sdim */ 269309124Sdim 270321369Sdimstatic int ssp; /* Top of file stack */ 271321369Sdimstruct sstack { 272321369Sdim FILE *s_file; /* File we were in. */ 273309124Sdim int s_cond; /* Saved state of conditionals */ 274321369Sdim int s_loading; /* Loading .mailrc, etc. */ 275321369Sdim}; 276321369Sdim#define SSTACK_SIZE 64 /* XXX was NOFILE. */ 277284677Sdimstatic struct sstack sstack[SSTACK_SIZE]; 278321369Sdim 279284677Sdim/* 280353358Sdim * Pushdown current input file and switch to a new one. 281327952Sdim * Set the global flag "sourcing" so that others will realize 282321369Sdim * that they are no longer reading from a tty (in all probability). 283321369Sdim */ 284321369Sdimint 285321369Sdimsource(arglist) 286321369Sdim char **arglist; 287284677Sdim{ 288321369Sdim FILE *fi; 289321369Sdim char *cp; 290321369Sdim 291327952Sdim if ((cp = expand(*arglist)) == NULL) 292321369Sdim return (1); 293321369Sdim if ((fi = Fopen(cp, "r")) == NULL) { 294321369Sdim warn("%s", cp); 295321369Sdim return (1); 296321369Sdim } 297296417Sdim if (ssp >= SSTACK_SIZE - 1) { 298327952Sdim printf("Too much \"sourcing\" going on.\n"); 299341825Sdim (void)Fclose(fi); 300341825Sdim return (1); 301341825Sdim } 302327952Sdim sstack[ssp].s_file = input; 303296417Sdim sstack[ssp].s_cond = cond; 304327952Sdim sstack[ssp].s_loading = loading; 305327952Sdim ssp++; 306321369Sdim loading = 0; 307321369Sdim cond = CANY; 308321369Sdim input = fi; 309321369Sdim sourcing++; 310321369Sdim return (0); 311327952Sdim} 312321369Sdim 313284677Sdim/* 314321369Sdim * Pop the current input back to the previous level. 315284677Sdim * Update the "sourcing" flag as appropriate. 316284677Sdim */ 317321369Sdimint 318284677Sdimunstack() 319321369Sdim{ 320353358Sdim if (ssp <= 0) { 321353358Sdim printf("\"Source\" stack over-pop.\n"); 322353358Sdim sourcing = 0; 323353358Sdim return (1); 324353358Sdim } 325353358Sdim (void)Fclose(input); 326353358Sdim if (cond != CANY) 327353358Sdim printf("Unmatched \"if\"\n"); 328353358Sdim ssp--; 329353358Sdim cond = sstack[ssp].s_cond; 330353358Sdim loading = sstack[ssp].s_loading; 331353358Sdim input = sstack[ssp].s_file; 332353358Sdim if (ssp == 0) 333353358Sdim sourcing = loading; 334353358Sdim return (0); 335353358Sdim} 336353358Sdim 337353358Sdim/* 338353358Sdim * Touch the indicated file. 339353358Sdim * This is nifty for the shell. 340353358Sdim */ 341353358Sdimvoid 342353358Sdimalter(name) 343353358Sdim char *name; 344353358Sdim{ 345353358Sdim struct stat sb; 346353358Sdim struct timeval tv[2]; 347353358Sdim 348353358Sdim if (stat(name, &sb)) 349353358Sdim return; 350353358Sdim (void)gettimeofday(&tv[0], (struct timezone *)NULL); 351353358Sdim tv[0].tv_sec++; 352353358Sdim TIMESPEC_TO_TIMEVAL(&tv[1], &sb.st_mtimespec); 353353358Sdim (void)utimes(name, tv); 354353358Sdim} 355353358Sdim 356353358Sdim/* 357353358Sdim * Get sender's name from this message. If the message has 358353358Sdim * a bunch of arpanet stuff in it, we may have to skin the name 359353358Sdim * before returning it. 360353358Sdim */ 361353358Sdimchar * 362353358Sdimnameof(mp, reptype) 363353358Sdim struct message *mp; 364353358Sdim int reptype; 365353358Sdim{ 366353358Sdim char *cp, *cp2; 367353358Sdim 368353358Sdim cp = skin(name1(mp, reptype)); 369353358Sdim if (reptype != 0 || charcount(cp, '!') < 2) 370353358Sdim return (cp); 371353358Sdim cp2 = strrchr(cp, '!'); 372353358Sdim cp2--; 373353358Sdim while (cp2 > cp && *cp2 != '!') 374353358Sdim cp2--; 375353358Sdim if (*cp2 == '!') 376353358Sdim return (cp2 + 1); 377353358Sdim return (cp); 378353358Sdim} 379353358Sdim 380353358Sdim/* 381353358Sdim * Start of a "comment". 382353358Sdim * Ignore it. 383353358Sdim */ 384353358Sdimchar * 385353358Sdimskip_comment(cp) 386321369Sdim char *cp; 387341825Sdim{ 388353358Sdim int nesting = 1; 389353358Sdim 390353358Sdim for (; nesting > 0 && *cp; cp++) { 391353358Sdim switch (*cp) { 392353358Sdim case '\\': 393353358Sdim if (cp[1]) 394341825Sdim cp++; 395353358Sdim break; 396353358Sdim case '(': 397353358Sdim nesting++; 398353358Sdim break; 399353358Sdim case ')': 400353358Sdim nesting--; 401353358Sdim break; 402353358Sdim } 403353358Sdim } 404353358Sdim return (cp); 405341825Sdim} 406341825Sdim 407341825Sdim/* 408341825Sdim * Skin an arpa net address according to the RFC 822 interpretation 409341825Sdim * of "host-phrase." 410341825Sdim */ 411341825Sdimchar * 412341825Sdimskin(name) 413341825Sdim char *name; 414341825Sdim{ 415341825Sdim char *nbuf, *bufend, *cp, *cp2; 416353358Sdim int c, gotlt, lastsp; 417353358Sdim 418353358Sdim if (name == NULL) 419353358Sdim return (NULL); 420353358Sdim if (strchr(name, '(') == NULL && strchr(name, '<') == NULL 421353358Sdim && strchr(name, ' ') == NULL) 422353358Sdim return (name); 423353358Sdim 424353358Sdim /* We assume that length(input) <= length(output) */ 425353358Sdim if ((nbuf = malloc(strlen(name) + 1)) == NULL) 426353358Sdim err(1, "Out of memory"); 427353358Sdim gotlt = 0; 428353358Sdim lastsp = 0; 429353358Sdim bufend = nbuf; 430353358Sdim for (cp = name, cp2 = bufend; (c = *cp++) != '\0'; ) { 431353358Sdim switch (c) { 432353358Sdim case '(': 433353358Sdim cp = skip_comment(cp); 434353358Sdim lastsp = 0; 435353358Sdim break; 436353358Sdim 437353358Sdim case '"': 438353358Sdim /* 439353358Sdim * Start of a "quoted-string". 440353358Sdim * Copy it in its entirety. 441353358Sdim */ 442353358Sdim while ((c = *cp) != '\0') { 443353358Sdim cp++; 444353358Sdim if (c == '"') 445353358Sdim break; 446353358Sdim if (c != '\\') 447353358Sdim *cp2++ = c; 448353358Sdim else if ((c = *cp) != '\0') { 449353358Sdim *cp2++ = c; 450353358Sdim cp++; 451353358Sdim } 452353358Sdim } 453353358Sdim lastsp = 0; 454353358Sdim break; 455353358Sdim 456353358Sdim case ' ': 457353358Sdim if (cp[0] == 'a' && cp[1] == 't' && cp[2] == ' ') 458353358Sdim cp += 3, *cp2++ = '@'; 459353358Sdim else 460353358Sdim if (cp[0] == '@' && cp[1] == ' ') 461353358Sdim cp += 2, *cp2++ = '@'; 462353358Sdim else 463353358Sdim lastsp = 1; 464353358Sdim break; 465353358Sdim 466353358Sdim case '<': 467353358Sdim cp2 = bufend; 468353358Sdim gotlt++; 469353358Sdim lastsp = 0; 470353358Sdim break; 471353358Sdim 472353358Sdim case '>': 473353358Sdim if (gotlt) { 474353358Sdim gotlt = 0; 475353358Sdim while ((c = *cp) != '\0' && c != ',') { 476353358Sdim cp++; 477353358Sdim if (c == '(') 478353358Sdim cp = skip_comment(cp); 479353358Sdim else if (c == '"') 480353358Sdim while ((c = *cp) != '\0') { 481353358Sdim cp++; 482353358Sdim if (c == '"') 483353358Sdim break; 484353358Sdim if (c == '\\' && *cp != '\0') 485353358Sdim cp++; 486353358Sdim } 487353358Sdim } 488360784Sdim lastsp = 0; 489353358Sdim break; 490353358Sdim } 491353358Sdim /* Fall into . . . */ 492353358Sdim 493353358Sdim default: 494353358Sdim if (lastsp) { 495353358Sdim lastsp = 0; 496353358Sdim *cp2++ = ' '; 497353358Sdim } 498353358Sdim *cp2++ = c; 499353358Sdim if (c == ',' && *cp == ' ' && !gotlt) { 500353358Sdim *cp2++ = ' '; 501353358Sdim while (*++cp == ' ') 502353358Sdim ; 503360784Sdim lastsp = 0; 504353358Sdim bufend = cp2; 505360784Sdim } 506353358Sdim } 507353358Sdim } 508353358Sdim *cp2 = '\0'; 509353358Sdim 510353358Sdim if ((cp = realloc(nbuf, strlen(nbuf) + 1)) != NULL) 511353358Sdim nbuf = cp; 512 return (nbuf); 513} 514 515/* 516 * Fetch the sender's name from the passed message. 517 * Reptype can be 518 * 0 -- get sender's name for display purposes 519 * 1 -- get sender's name for reply 520 * 2 -- get sender's name for Reply 521 */ 522char * 523name1(mp, reptype) 524 struct message *mp; 525 int reptype; 526{ 527 char namebuf[LINESIZE]; 528 char linebuf[LINESIZE]; 529 char *cp, *cp2; 530 FILE *ibuf; 531 int first = 1; 532 533 if ((cp = hfield("from", mp)) != NULL) 534 return (cp); 535 if (reptype == 0 && (cp = hfield("sender", mp)) != NULL) 536 return (cp); 537 ibuf = setinput(mp); 538 namebuf[0] = '\0'; 539 if (readline(ibuf, linebuf, LINESIZE) < 0) 540 return (savestr(namebuf)); 541newname: 542 for (cp = linebuf; *cp != '\0' && *cp != ' '; cp++) 543 ; 544 for (; *cp == ' ' || *cp == '\t'; cp++) 545 ; 546 for (cp2 = &namebuf[strlen(namebuf)]; 547 *cp != '\0' && *cp != ' ' && *cp != '\t' && 548 cp2 < namebuf + LINESIZE - 1;) 549 *cp2++ = *cp++; 550 *cp2 = '\0'; 551 if (readline(ibuf, linebuf, LINESIZE) < 0) 552 return (savestr(namebuf)); 553 if ((cp = strchr(linebuf, 'F')) == NULL) 554 return (savestr(namebuf)); 555 if (strncmp(cp, "From", 4) != 0) 556 return (savestr(namebuf)); 557 while ((cp = strchr(cp, 'r')) != NULL) { 558 if (strncmp(cp, "remote", 6) == 0) { 559 if ((cp = strchr(cp, 'f')) == NULL) 560 break; 561 if (strncmp(cp, "from", 4) != 0) 562 break; 563 if ((cp = strchr(cp, ' ')) == NULL) 564 break; 565 cp++; 566 if (first) { 567 cp2 = namebuf; 568 first = 0; 569 } else 570 cp2 = strrchr(namebuf, '!') + 1; 571 strlcpy(cp2, cp, sizeof(namebuf) - (cp2 - namebuf) - 1); 572 strcat(namebuf, "!"); 573 goto newname; 574 } 575 cp++; 576 } 577 return (savestr(namebuf)); 578} 579 580/* 581 * Count the occurances of c in str 582 */ 583int 584charcount(str, c) 585 char *str; 586 int c; 587{ 588 char *cp; 589 int i; 590 591 for (i = 0, cp = str; *cp != '\0'; cp++) 592 if (*cp == c) 593 i++; 594 return (i); 595} 596 597/* 598 * See if the given header field is supposed to be ignored. 599 */ 600int 601isign(field, ignore) 602 const char *field; 603 struct ignoretab ignore[2]; 604{ 605 char realfld[LINESIZE]; 606 607 if (ignore == ignoreall) 608 return (1); 609 /* 610 * Lower-case the string, so that "Status" and "status" 611 * will hash to the same place. 612 */ 613 istrncpy(realfld, field, sizeof(realfld)); 614 if (ignore[1].i_count > 0) 615 return (!member(realfld, ignore + 1)); 616 else 617 return (member(realfld, ignore)); 618} 619 620int 621member(realfield, table) 622 char *realfield; 623 struct ignoretab *table; 624{ 625 struct ignore *igp; 626 627 for (igp = table->i_head[hash(realfield)]; igp != NULL; igp = igp->i_link) 628 if (*igp->i_field == *realfield && 629 equal(igp->i_field, realfield)) 630 return (1); 631 return (0); 632} 633