Annotation of 43BSD/contrib/mh/uip/spop.c, revision 1.1

1.1     ! root        1: #ifndef        SPOP
        !             2: /* sbboards.c - MH style mailer to write to a ZOTnet BBoard */
        !             3: #else  SPOP
        !             4: /* spop.c - MH style mailer to write to a POP subscriber */
        !             5: #endif SPOP
        !             6: 
        !             7: #ifndef        SPOP
        !             8: 
        !             9: /* This program acts like the MMDF ch_bboards channel: it does local
        !            10:    delivery to a ZOTnet BBoard and/or addition re-distribution to other
        !            11:    recipients of the BBoard.  This program can function both as a SendMail
        !            12:    mailer and an MH .mh_receive file, depending on whether SENDMTS or
        !            13:    MHMTS is set.  Currently, the MHMTS version of this program does not do
        !            14:    re-distribution.
        !            15: 
        !            16:    This program should be used ONLY if you have "bboards on" set in your
        !            17:    MH configuration, and if you have "mts sendmail" or "mts mh" set as well.
        !            18:  */
        !            19: 
        !            20: #else  SPOP
        !            21: 
        !            22: /* This program acts like the MMDF-II ch_pop channel: it does local
        !            23:    delivery for non-local users.  These users are known as POP subscribers
        !            24:    and use the Post Office Protocol with a POP server in order to access
        !            25:    their maildrop.
        !            26:  */
        !            27: 
        !            28: #endif SPOP
        !            29: 
        !            30: #undef DISTRIBUTE
        !            31: #ifdef SENDMTS
        !            32: #ifndef        SPOP
        !            33: #define        DISTRIBUTE
        !            34: #endif not SPOP
        !            35: #endif SENDMTS
        !            36: 
        !            37: #include "../h/mh.h"
        !            38: #ifndef        SPOP
        !            39: #include "../h/addrsbr.h"
        !            40: #endif not SPOP
        !            41: #include "../h/dropsbr.h"
        !            42: #include "../zotnet/bboards.h"
        !            43: #include "../zotnet/tws.h"
        !            44: #include <stdio.h>
        !            45: #include "../zotnet/mts.h"
        !            46: #include <pwd.h>
        !            47: #ifndef        SYS5
        !            48: #include <sysexits.h>
        !            49: #else  SYS5
        !            50: #define        EX_CANTCREAT    1
        !            51: #define        EX_IOERR        1
        !            52: #define        EX_NOINPUT      1
        !            53: #define        EX_NOUSER       1
        !            54: #define        EX_OK           0
        !            55: #define        EX_OSERR        1
        !            56: #define        EX_OSFILE       1
        !            57: #define        EX_UNAVAILABLE  1
        !            58: #define        EX_USAGE        1
        !            59: #endif SYS5
        !            60: #ifdef DISTRIBUTE
        !            61: #include "../mts/sendmail/smail.h"
        !            62: #endif DISTRIBUTE
        !            63: 
        !            64: 
        !            65: #define        NBB     100
        !            66: 
        !            67: #ifndef        SPOP
        !            68: #define        ENTITY  "bboard"
        !            69: #else  SPOP
        !            70: #define        ENTITY  "subscriber"
        !            71: #endif SPOP
        !            72: 
        !            73: /*  */
        !            74: 
        !            75: static int  bb_fderr;
        !            76: 
        !            77: static int  bb_uid;
        !            78: static int  bb_gid;
        !            79: 
        !            80: int    dst_rcpt ();
        !            81: 
        !            82: 
        !            83: #ifndef        SPOP
        !            84: static char bb_from[BUFSIZ];
        !            85: static char bb_head[BUFSIZ];
        !            86: static char bb_home[BUFSIZ];
        !            87: static char bb_time[BUFSIZ];
        !            88: #ifdef DISTRIBUTE
        !            89: static char bb_rept[BUFSIZ];
        !            90: #endif DISTRIBUTE
        !            91: #else  SPOP
        !            92: #define        bb_head NULLCP
        !            93: #endif SPOP
        !            94: 
        !            95: static struct bboard  *bb[NBB];
        !            96: 
        !            97: 
        !            98: long   lseek ();
        !            99: 
        !           100: #ifdef SYS5
        !           101: struct passwd  *getpwnam ();
        !           102: #endif SYS5
        !           103: 
        !           104: /*  */
        !           105: 
        !           106: /* ARGSUSED */
        !           107: 
        !           108: main (argc, argv, envp)
        !           109: int     argc;
        !           110: char  **argv,
        !           111:       **envp;
        !           112: {
        !           113:     int     fd;
        !           114:     char    tmpfil[BUFSIZ];
        !           115: 
        !           116: #ifdef MHMTS
        !           117:     if (argc != 5)
        !           118:        adios (EX_USAGE, NULL, "you lose really big");
        !           119: #endif MHMTS
        !           120:     arginit (argv);
        !           121: 
        !           122:     fd = copyfile (fileno (stdin), tmpfil);
        !           123:     (void) unlink (tmpfil);
        !           124: 
        !           125:     localmail (fd);
        !           126: #ifdef DISTRIBUTE
        !           127:     distribute (fd);
        !           128:     notify (fd);
        !           129: #endif DISTRIBUTE
        !           130: 
        !           131:     exit (EX_OK);
        !           132: }
        !           133: 
        !           134: /*  */
        !           135: 
        !           136: static  localmail (fd)
        !           137: int     fd;
        !           138: {
        !           139:     int     i,
        !           140:             md;
        !           141:     register struct bboard  *bp;
        !           142: 
        !           143:     for (i = 0; bp = bb[i]; i++)
        !           144:        if (bp -> bb_file && *bp -> bb_file) {
        !           145:            (void) lseek (fd, 0L, 0);
        !           146: #ifndef        SPOP
        !           147:            if ((md = mbx_open (bp -> bb_file, bb_uid, bb_gid, BBMODE))
        !           148: #else  SPOP
        !           149:            if ((md = mbx_open (bp -> bb_file, bb_uid, bb_gid, POMODE))
        !           150: #endif SPOP
        !           151:                    == NOTOK) {
        !           152:                (void) lose ("unable to open %s", bp -> bb_file);
        !           153:                continue;
        !           154:            }
        !           155: #ifndef        SPOP
        !           156:            if (mbx_init (bp) != NOTOK)
        !           157: #endif not SPOP
        !           158:                (void) mbx_copy (bp -> bb_file, md, fd, 1, bb_head, 0);
        !           159:            (void) mbx_close (bp -> bb_file, md);
        !           160:        }
        !           161: }
        !           162: 
        !           163: /*  */
        !           164: 
        !           165: #ifndef        SPOP
        !           166: static int  mbx_init (bp)
        !           167: register struct bboard  *bp;
        !           168: {
        !           169:     int            fd,
        !           170:            clear;
        !           171:     register struct bboard  *ip;
        !           172:     register FILE *fp;
        !           173: 
        !           174:     if ((fd = mbx_Xopen (bp -> bb_info, bb_uid, bb_gid, BBMODE, &clear))
        !           175:            == NOTOK)
        !           176:        return lose ("unable to lock and open %s", bp -> bb_info);
        !           177:     if ((fp = fdopen (fd, "w")) == NULL) {
        !           178:         (void) mbx_close (bp -> bb_info, fd);
        !           179:        return lose ("unable to fdopen %s", bp -> bb_info);
        !           180:     }
        !           181: 
        !           182:     if ((ip = getbbnam (bp -> bb_name)) == NULL) {
        !           183:        (void) lkfclose (fp, bp -> bb_info);
        !           184:        return lose ("unable to get information on BBoard %s", bp -> bb_name);
        !           185:     }
        !           186:     (void) strcpy (bb_time, dtimenow ());
        !           187:     (void) sprintf (bb_head, "BBoard-ID: %d\nBB-Posted: %s\n",
        !           188:            bp -> bb_maxima = ++ip -> bb_maxima, bb_time);
        !           189: 
        !           190:     fprintf (fp, "%d\n%s\n", bp -> bb_maxima, bb_time);
        !           191:     (void) lkfclose (fp, bp -> bb_info);
        !           192: 
        !           193:     return OK;
        !           194: }
        !           195: #endif not SPOP
        !           196: 
        !           197: /*  */
        !           198: 
        !           199: #ifdef DISTRIBUTE
        !           200: static  distribute (fd)
        !           201: int     fd;
        !           202: {
        !           203:     int     i;
        !           204:     register struct bboard  *bp;
        !           205: 
        !           206:     for (i = 0; bp = bb[i]; i++)
        !           207:        if (bp -> bb_dist && *bp -> bb_dist)
        !           208:            break;
        !           209:     if (bp == NULL)
        !           210:        return;
        !           211: 
        !           212:     if (dst_init () == NOTOK) {
        !           213:        dst_lose ();
        !           214:        return;
        !           215:     }
        !           216:     for (i = 0; bp = bb[i]; i++)
        !           217:        if (bp -> bb_dist && *bp -> bb_dist)
        !           218:            if (dst_adrs (bp) == NOTOK) {
        !           219:                dst_lose ();
        !           220:                return;
        !           221:            }
        !           222:     if (dst_text (fd) == NOTOK || dst_end () == NOTOK)
        !           223:        dst_lose ();
        !           224: }
        !           225: 
        !           226: /*  */
        !           227: 
        !           228: static int  dst_init ()
        !           229: {
        !           230:     int     retval;
        !           231: 
        !           232:     if (rp_isbad (retval = sm_init (NULLCP, NULLCP, 0, 0, 0))
        !           233:            || rp_isbad (retval = sm_winit (S_MAIL, bb_from)))
        !           234:        return lose ("problem initializing SendMail; %s",
        !           235:                rp_string (retval));
        !           236: 
        !           237:     return OK;
        !           238: }
        !           239: 
        !           240: /*  */
        !           241: 
        !           242: static int  dst_adrs (bp)
        !           243: register struct bboard  *bp;
        !           244: {
        !           245:     if (getbbdist (bp, dst_rcpt))
        !           246:        return lose ("getbbdist failed: %s", getbberr ());
        !           247: 
        !           248:     return OK;
        !           249: }
        !           250: 
        !           251: /*  */
        !           252: 
        !           253: static int  dst_rcpt (mbox, host)
        !           254: register char   *mbox,
        !           255:                *host;
        !           256: {
        !           257:     int     retval;
        !           258: 
        !           259:     switch (retval = sm_wadr (mbox, host, NULLCP)) {
        !           260:        case RP_OK:
        !           261:            return OK;
        !           262: 
        !           263:        case RP_NO:
        !           264:        case RP_USER:
        !           265:            (void) lose ("%s@%s: loses; %s", mbox, host, rp_string (retval));
        !           266:            return OK;          /* fail-soft */
        !           267: 
        !           268:        default:
        !           269:            return lose ("%s@%s: unexpected response; %s",
        !           270:                    mbox, host, rp_string (retval));
        !           271:     }
        !           272: }
        !           273: 
        !           274: /*  */
        !           275: 
        !           276: static int  dst_text (fd)
        !           277: int     fd;
        !           278: {
        !           279:     int     i,
        !           280:             retval;
        !           281:     char    buffer[BUFSIZ];
        !           282: 
        !           283:     if (rp_isbad (retval = sm_waend ()))
        !           284:        return lose ("problem ending addresses; %s", rp_string (retval));
        !           285: 
        !           286:     (void) lseek (fd, 0L, 0);
        !           287:     while ((i = read (fd, buffer, sizeof buffer)) > 0)
        !           288:        if (rp_isbad (retval = sm_wtxt (buffer, i)))
        !           289:            return lose ("problem writing text; %s", rp_string (retval));
        !           290: 
        !           291:     return (i != NOTOK ? OK : lose ("error reading from file"));
        !           292: }
        !           293: 
        !           294: /*  */
        !           295: 
        !           296: static int  dst_end ()
        !           297: {
        !           298:     int     retval;
        !           299: 
        !           300:     switch (retval = sm_wtend ()) {
        !           301:        case RP_OK:
        !           302:            (void) sm_end (OK);
        !           303:            return OK;
        !           304: 
        !           305:        case RP_NO:
        !           306:        case RP_NDEL:
        !           307:            return lose ("posting failed; %s", rp_string (retval));
        !           308: 
        !           309:        default:
        !           310:            return lose ("unexpected response; %s", rp_string (retval));
        !           311:     }
        !           312: }
        !           313: 
        !           314: /*  */
        !           315: 
        !           316: static  dst_lose ()
        !           317: {
        !           318:     (void) sm_end (NOTOK);
        !           319: }
        !           320: 
        !           321: /*  */
        !           322: 
        !           323: /* VARARGS1 */
        !           324: 
        !           325: static int  lose (fmt, a, b, c, d)
        !           326: char   *fmt,
        !           327:        *a,
        !           328:        *b,
        !           329:        *c,
        !           330:        *d;
        !           331: {
        !           332:     int     fd,
        !           333:             i;
        !           334:     char   *bp,
        !           335:            buffer[BUFSIZ];
        !           336: 
        !           337:     if (bb_fderr == NOTOK) {
        !           338:        if ((fd = open ("/dev/null", 0)) == NOTOK)
        !           339:            adios (EX_OSERR, "/dev/null", "unable to open");
        !           340:        bb_fderr = copyfile (fd, bb_rept);
        !           341:     }
        !           342: 
        !           343:     (void) sprintf (bp = buffer, fmt, a, b, c, d);
        !           344:     bp += strlen (bp);
        !           345:     bp += strlen (strcpy(bp, "\n"));
        !           346:     i = bp - buffer;
        !           347:     if (write (bb_fderr, buffer, i) != i)
        !           348:        adios (EX_IOERR, bb_rept, "error writing");
        !           349: 
        !           350:     return NOTOK;
        !           351: }
        !           352: 
        !           353: /*  */
        !           354: 
        !           355: static  notify (fd)
        !           356: int     fd;
        !           357: {
        !           358:     int     i;
        !           359:     char    buffer[BUFSIZ];
        !           360: 
        !           361:     if (bb_fderr == NOTOK)
        !           362:        return;
        !           363: 
        !           364:     if (rp_isbad (sm_init (NULLCP, NULLCP, 0, 0, 0))
        !           365:            || rp_isbad (sm_winit (S_MAIL, bb_from)))
        !           366:        goto sm_err;
        !           367: 
        !           368:     switch (sm_wadr (bb_from, NULLCP, NULLCP)) {
        !           369:        case RP_OK:
        !           370:            for (i = 0; bb[i]; i++) {
        !           371:                (void) sprintf (buffer, "local-%s-request", bb[i] -> bb_name);
        !           372:                (void) sm_wadr (buffer, LocalName (), NULLCP);
        !           373:            }
        !           374:            break;
        !           375: 
        !           376:        default:
        !           377:            goto sm_err;
        !           378:     }
        !           379: 
        !           380:     if (rp_isbad (sm_waend ()))
        !           381:        goto sm_err;
        !           382: 
        !           383:     (void) sprintf (buffer,
        !           384:            "Date: %s\nFrom: %s\nTo: %s\nSubject: BBoards Failure\n\n",
        !           385:            dtimenow (), bb_from, bb_from);
        !           386:     if (rp_isbad (sm_wtxt (buffer, strlen (buffer))))
        !           387:        goto sm_err;
        !           388: 
        !           389:     for (i = 0; bb[i]; i++) {
        !           390:        (void) sprintf (buffer, "BBoard %s\n", bb[i] -> bb_name);
        !           391:        if (rp_isbad (sm_wtxt (buffer, strlen (buffer))))
        !           392:            goto sm_err;
        !           393:     }
        !           394: 
        !           395:     (void) lseek (bb_fderr, 0L, 0);
        !           396:     while ((i = read (bb_fderr, buffer, sizeof buffer)) > 0)
        !           397:        if (rp_isbad (sm_wtxt (buffer, i)))
        !           398:            goto sm_err;
        !           399: 
        !           400:     (void) strcpy (buffer, "\n------- Forwarded Message\n\n");
        !           401:     if (rp_isbad (sm_wtxt (buffer, strlen (buffer))) || encap (fd) == NOTOK)
        !           402:        goto sm_err;
        !           403:     (void) strcpy (buffer, "\n------- End of Forwarded Message\n\n");
        !           404:     if (rp_isbad (sm_wtxt (buffer, strlen (buffer))))
        !           405:        goto sm_err;
        !           406: 
        !           407:     switch (sm_wtend ()) {
        !           408:        case RP_OK:
        !           409:            (void) unlink (bb_rept);
        !           410:            (void) sm_end (OK);
        !           411:            return;
        !           412: 
        !           413:        default:
        !           414:     sm_err: ;
        !           415:            adios (EX_UNAVAILABLE, NULLCP,
        !           416:                    "failed and unable to post advisory, see %s for details",
        !           417:                    bb_rept);
        !           418:     }
        !           419: }
        !           420: 
        !           421: /*  */
        !           422: 
        !           423: /* very similar to sbr/cpydgst.c */
        !           424: 
        !           425: #define        S1      0
        !           426: #define        S2      1
        !           427: 
        !           428: #define        output(c)       if (bp >= dp) flush (), *bp++ = c; else *bp++ = c
        !           429: #define        flush()         if ((j = bp - outbuf) \
        !           430:                                && rp_isbad (sm_wtxt (outbuf, j))) \
        !           431:                            return NOTOK; \
        !           432:                        else \
        !           433:                            bp = outbuf
        !           434: 
        !           435: static int  encap (fd)
        !           436: register int    fd;
        !           437: {
        !           438:     register int    i,
        !           439:                     state;
        !           440:     register char  *cp,
        !           441:                    *ep;
        !           442:     char    buffer[BUFSIZ];
        !           443:     register int    j;
        !           444:     register char  *bp,
        !           445:                    *dp;
        !           446:     char    outbuf[BUFSIZ];
        !           447: 
        !           448:     (void) lseek (fd, 0L, 0);
        !           449: 
        !           450:     dp = (bp = outbuf) + sizeof outbuf;
        !           451:     for (state = S1; (i = read (fd, buffer, sizeof buffer)) > 0;)
        !           452:        for (ep = (cp = buffer) + i; cp < ep; cp++) {
        !           453:            if (*cp == NULL)
        !           454:                continue;
        !           455:            switch (state) {
        !           456:                case S1: 
        !           457:                    if (*cp == '-') {
        !           458:                        output ('-');
        !           459:                        output (' ');
        !           460:                    }
        !           461:                    state = S2; /* fall */
        !           462: 
        !           463:                case S2: 
        !           464:                    output (*cp);
        !           465:                    if (*cp == '\n')
        !           466:                        state = S1;
        !           467:                    break;
        !           468:            }
        !           469:        }
        !           470: 
        !           471:     if (i == NOTOK)
        !           472:        return NOTOK;
        !           473:     flush ();
        !           474: 
        !           475:     return OK;
        !           476: }
        !           477: #endif DISTRIBUTE
        !           478: 
        !           479: /*  */
        !           480: 
        !           481: #ifndef        DISTRIBUTE
        !           482: /* VARARGS1 */
        !           483: 
        !           484: static int  lose (fmt, a, b, c, d)
        !           485: char   *fmt,
        !           486:        *a,
        !           487:        *b,
        !           488:        *c,
        !           489:        *d;
        !           490: {
        !           491:     adios (EX_UNAVAILABLE, NULLCP, fmt, a, b, c, d);/* NOTREACHED */
        !           492: }
        !           493: #endif not DISTRIBUTE
        !           494: 
        !           495: /*  */
        !           496: 
        !           497: static  arginit (vec)
        !           498: register char  **vec;
        !           499: {
        !           500:     register int    i;
        !           501: #ifdef MHMTS
        !           502:     register char  *ap;
        !           503: #endif MHMTS
        !           504:     char    addr[BUFSIZ];
        !           505:     register struct bboard *bp;
        !           506:     register struct passwd *pw;
        !           507: 
        !           508:     invo_name = r1bindex (*vec++, '/');
        !           509:     m_foil (NULLCP);
        !           510:     mts_init (invo_name);
        !           511: 
        !           512: #ifndef        SPOP
        !           513:     if ((pw = getpwnam (BBOARDS)) == NULL)
        !           514:        adios (EX_OSFILE, NULLCP, "no entry for ~%s", BBOARDS);
        !           515: #else  SPOP
        !           516:     if ((pw = getpwnam (POPUID)) == NULL || !setpwinfo (pw, POPDB, 1))
        !           517:        adios (EX_OSFILE, NULLCP, "%s", pw ? getbberr () : "POP user-id unknown");
        !           518: #endif SPOP
        !           519: 
        !           520:     if (pw -> pw_uid != geteuid ())
        !           521: #ifndef SPOP
        !           522:     adios (EX_OSERR, NULLCP, "not running setuid to %s", BBOARDS);
        !           523: #else  SPOP
        !           524:     adios (EX_OSERR, NULLCP, "not running setuid to %s", POPUID);
        !           525: #endif SPOP
        !           526: 
        !           527:     bb_uid = pw -> pw_uid;
        !           528:     bb_gid = pw -> pw_gid;
        !           529: #ifndef        SPOP
        !           530:     (void) strcpy (bb_from, adrsprintf (pw -> pw_name, LocalName ()));
        !           531:     (void) strcpy (bb_home, pw -> pw_dir);
        !           532: #endif not SPOP
        !           533: 
        !           534: #ifdef MHMTS
        !           535:     vec += 3;
        !           536: #endif MHMTS
        !           537:     if (*vec == NULL)
        !           538:        adios (EX_USAGE, NULLCP, "usage: %s %s [%s ...]",
        !           539:                invo_name, ENTITY, ENTITY);
        !           540: 
        !           541:     for (i = 0; *vec; vec++) {
        !           542: #ifdef MHMTS
        !           543:        if (ap = index (*vec, '.'))
        !           544:            *vec = ++ap;
        !           545: #endif MHMTS
        !           546:        make_lower (addr, *vec);
        !           547: 
        !           548:        if ((bp = getbbnam (addr)) == NULL
        !           549:                && (bp = getbbaka (addr)) == NULL)
        !           550:            adios (EX_NOUSER, NULLCP, "no such %s as %s", ENTITY, *vec);
        !           551:        if ((bb[i++] = getbbcpy (bp)) == NULL)
        !           552:            adios (EX_UNAVAILABLE, NULLCP, "insufficient memory on %s", *vec);
        !           553: 
        !           554:        if (i >= NBB - 1)
        !           555:            adios (EX_USAGE, NULLCP, "too many %ss, starting with %s",
        !           556:                    ENTITY, *vec);
        !           557:     }
        !           558:     bb[i] = NULL;
        !           559: 
        !           560:     (void) umask (0022);
        !           561: 
        !           562:     bb_fderr = NOTOK;
        !           563: }
        !           564: 
        !           565: /*  */
        !           566: 
        !           567: static int  copyfile (qd, tmpfil)
        !           568: int     qd;
        !           569: register char   *tmpfil;
        !           570: {
        !           571:     int     i,
        !           572:             fd;
        !           573:     char    buffer[BUFSIZ];
        !           574: 
        !           575:     (void) strcpy (tmpfil, m_tmpfil (invo_name));
        !           576:     if ((fd = creat (tmpfil, 0600)) == NOTOK)
        !           577:        adios (EX_CANTCREAT, tmpfil, "unable to create");
        !           578:     (void) close (fd);
        !           579:     if ((fd = open (tmpfil, 2)) == NOTOK)
        !           580:        adios (EX_NOINPUT, tmpfil, "unable to re-open");
        !           581: 
        !           582:     (void) lseek (qd, 0L, 0);
        !           583:     while ((i = read (qd, buffer, sizeof buffer)) > 0)
        !           584:        if (write (fd, buffer, i) != i)
        !           585:            adios (EX_IOERR, tmpfil, "error writing");
        !           586:     if (i == NOTOK)
        !           587:        adios (EX_IOERR, "input", "error reading");
        !           588: 
        !           589:     (void) lseek (fd, 0L, 0);
        !           590: 
        !           591:     return fd;
        !           592: }
        !           593: 
        !           594: /*  */
        !           595: 
        !           596: /* VARARGS3 */
        !           597: 
        !           598: #ifdef MHMTS
        !           599: /* ARGSUSED */
        !           600: #endif MHMTS
        !           601: 
        !           602: static  void adios (code, what, fmt, a, b, c, d, e, f)
        !           603: int     code;
        !           604: char   *what,
        !           605:        *fmt,
        !           606:        *a,
        !           607:        *b,
        !           608:        *c,
        !           609:        *d,
        !           610:        *e,
        !           611:        *f;
        !           612: {
        !           613:     advise (what, fmt, a, b, c, d, e, f);
        !           614: #ifdef SENDMTS
        !           615:     done (code);
        !           616: #endif SENDMTS
        !           617: #ifdef MHMTS
        !           618:     done (1);
        !           619: #endif MHMTS
        !           620: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.